⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ppp_oe.c

📁 STM32F107_ETH_LwIP_V1.0.0.rar
💻 C
📖 第 1 页 / 共 3 页
字号:
    PPPOE_ADD_16(p, PPPOE_TAG_ACNAME);
    PPPOE_ADD_16(p, l2);
    MEMCPY(p, sc->sc_concentrator_name, l2);
    p += l2;
  }
  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
  PPPOE_ADD_16(p, sizeof(sc));
  MEMCPY(p, &sc, sizeof sc);

  /* send pkt */
  return pppoe_output(sc, pb);
}

static void
pppoe_timeout(void *arg)
{
  int retry_wait, err;
  struct pppoe_softc *sc = (struct pppoe_softc*)arg;

  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));

  switch (sc->sc_state) {
    case PPPOE_STATE_PADI_SENT:
      /*
       * We have two basic ways of retrying:
       *  - Quick retry mode: try a few times in short sequence
       *  - Slow retry mode: we already had a connection successfully
       *    established and will try infinitely (without user
       *    intervention)
       * We only enter slow retry mode if IFF_LINK1 (aka autodial)
       * is not set.
       */

      /* initialize for quick retry mode */
      retry_wait = PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried);

      sc->sc_padi_retried++;
      if (sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) {
#if 0
        if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) {
          /* slow retry mode */
          retry_wait = PPPOE_SLOW_RETRY;
        } else
#endif
        {
          pppoe_abort_connect(sc);
          return;
        }
      }
      if ((err = pppoe_send_padi(sc)) != 0) {
        sc->sc_padi_retried--;
        PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
      }
      tcpip_timeout(retry_wait, pppoe_timeout, sc);
      break;

    case PPPOE_STATE_PADR_SENT:
      sc->sc_padr_retried++;
      if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) {
        MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
        sc->sc_state = PPPOE_STATE_PADI_SENT;
        sc->sc_padr_retried = 0;
        if ((err = pppoe_send_padi(sc)) != 0) {
          PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
        }
        tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc);
        return;
      }
      if ((err = pppoe_send_padr(sc)) != 0) {
        sc->sc_padr_retried--;
        PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
      }
      tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc);
      break;
    case PPPOE_STATE_CLOSING:
      pppoe_do_disconnect(sc);
      break;
    default:
      return;  /* all done, work in peace */
  }
}

/* Start a connection (i.e. initiate discovery phase) */
int
pppoe_connect(struct pppoe_softc *sc)
{
  int err;

  if (sc->sc_state != PPPOE_STATE_INITIAL) {
    return EBUSY;
  }

#ifdef PPPOE_SERVER
  /* wait PADI if IFF_PASSIVE */
  if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {
    return 0;
  }
#endif
  /* save state, in case we fail to send PADI */
  sc->sc_state = PPPOE_STATE_PADI_SENT;
  sc->sc_padr_retried = 0;
  err = pppoe_send_padi(sc);
  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err));
  tcpip_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc);
  return err;
}

/* disconnect */
void
pppoe_disconnect(struct pppoe_softc *sc)
{
  if (sc->sc_state < PPPOE_STATE_SESSION) {
    return;
  }
  /*
   * Do not call pppoe_disconnect here, the upper layer state
   * machine gets confused by this. We must return from this
   * function and defer disconnecting to the timeout handler.
   */
  sc->sc_state = PPPOE_STATE_CLOSING;
  tcpip_timeout(20, pppoe_timeout, sc);
}

static int
pppoe_do_disconnect(struct pppoe_softc *sc)
{
  int err;

  if (sc->sc_state < PPPOE_STATE_SESSION) {
    err = EBUSY;
  } else {
    PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
    err = pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest);
  }

  /* cleanup softc */
  sc->sc_state = PPPOE_STATE_INITIAL;
  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
  if (sc->sc_ac_cookie) {
    mem_free(sc->sc_ac_cookie);
    sc->sc_ac_cookie = NULL;
  }
  sc->sc_ac_cookie_len = 0;
#ifdef PPPOE_SERVER
  if (sc->sc_hunique) {
    mem_free(sc->sc_hunique);
    sc->sc_hunique = NULL;
  }
  sc->sc_hunique_len = 0;
#endif
  sc->sc_session = 0;

  sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */

  return err;
}

/* Connection attempt aborted */
static void
pppoe_abort_connect(struct pppoe_softc *sc)
{
  printf("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
  sc->sc_state = PPPOE_STATE_CLOSING;

  sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */

  /* clear connection state */
  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
  sc->sc_state = PPPOE_STATE_INITIAL;
}

/* Send a PADR packet */
static err_t
pppoe_send_padr(struct pppoe_softc *sc)
{
  struct pbuf *pb;
  u8_t *p;
  size_t len, l1 = 0; /* XXX: gcc */

  if (sc->sc_state != PPPOE_STATE_PADR_SENT) {
    return ERR_CONN;
  }

  len = 2 + 2 + 2 + 2 + sizeof(sc);    /* service name, host unique */
  if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */
    l1 = strlen(sc->sc_service_name);
    len += l1;
  }
  if (sc->sc_ac_cookie_len > 0) {
    len += 2 + 2 + sc->sc_ac_cookie_len;  /* AC cookie */
  }
  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);
  if (!pb) {
    return ERR_MEM;
  }
  p = (u8_t*)pb->payload + sizeof (struct eth_hdr);
  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len);
  PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
  if (sc->sc_service_name != NULL) {
    PPPOE_ADD_16(p, l1);
    MEMCPY(p, sc->sc_service_name, l1);
    p += l1;
  } else {
    PPPOE_ADD_16(p, 0);
  }
  if (sc->sc_ac_cookie_len > 0) {
    PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);
    PPPOE_ADD_16(p, sc->sc_ac_cookie_len);
    MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len);
    p += sc->sc_ac_cookie_len;
  }
  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
  PPPOE_ADD_16(p, sizeof(sc));
  MEMCPY(p, &sc, sizeof sc);

  return pppoe_output(sc, pb);
}

/* send a PADT packet */
static err_t
pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest)
{
  struct pbuf *pb;
  struct eth_hdr *ethhdr;
  err_t res;
  u8_t *p;

  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN, PBUF_RAM);
  if (!pb) {
    return ERR_MEM;
  }

  ethhdr = (struct eth_hdr *)pb->payload;
  ethhdr->type = htons(ETHTYPE_PPPOEDISC);
  MEMCPY(ethhdr->dest.addr, dest, sizeof(ethhdr->dest.addr));
  MEMCPY(ethhdr->src.addr, ((struct eth_addr *)outgoing_if->hwaddr)->addr, sizeof(ethhdr->src.addr));

  p = (u8_t*)(ethhdr + 1);
  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0);

  res = outgoing_if->linkoutput(outgoing_if, pb);

  pbuf_free(pb);

  return res;
}

#ifdef PPPOE_SERVER
static err_t
pppoe_send_pado(struct pppoe_softc *sc)
{
  struct pbuf *pb;
  u8_t *p;
  size_t len;

  if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
    return ERR_CONN;
  }

  /* calc length */
  len = 0;
  /* include ac_cookie */
  len += 2 + 2 + sizeof(sc);
  /* include hunique */
  len += 2 + 2 + sc->sc_hunique_len;
  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);
  if (!pb) {
    return ERR_MEM;
  }
  p = (u8_t*)pb->payload + sizeof (struct eth_hdr);
  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len);
  PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);
  PPPOE_ADD_16(p, sizeof(sc));
  MEMCPY(p, &sc, sizeof(sc));
  p += sizeof(sc);
  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
  PPPOE_ADD_16(p, sc->sc_hunique_len);
  MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len);
  return pppoe_output(sc, pb);
}

static err_t
pppoe_send_pads(struct pppoe_softc *sc)
{
  struct pbuf *pb;
  u8_t *p;
  size_t len, l1 = 0;  /* XXX: gcc */

  if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
    return ERR_CONN;
  }

  sc->sc_session = mono_time.tv_sec % 0xff + 1;
  /* calc length */
  len = 0;
  /* include hunique */
  len += 2 + 2 + 2 + 2 + sc->sc_hunique_len;  /* service name, host unique*/
  if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */
    l1 = strlen(sc->sc_service_name);
    len += l1;
  }
  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);
  if (!pb) {
    return ERR_MEM;
  }
  p = (u8_t*)pb->payload + sizeof (struct eth_hdr);
  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len);
  PPPOE_ADD_16(p, PPPOE_TAG_SNAME);
  if (sc->sc_service_name != NULL) {
    PPPOE_ADD_16(p, l1);
    MEMCPY(p, sc->sc_service_name, l1);
    p += l1;
  } else {
    PPPOE_ADD_16(p, 0);
  }
  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);
  PPPOE_ADD_16(p, sc->sc_hunique_len);
  MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len);
  return pppoe_output(sc, pb);
}
#endif

err_t
pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb)
{
  u8_t *p;
  size_t len;

  /* are we ready to process data yet? */
  if (sc->sc_state < PPPOE_STATE_SESSION) {
    /*sppp_flush(&sc->sc_sppp.pp_if);*/
    pbuf_free(pb);
    return ERR_CONN;
  }

  len = pb->tot_len;

  /* make room for Ethernet header - should not fail */
  if (pbuf_header(pb, sizeof(struct eth_hdr) + PPPOE_HEADERLEN) != 0) {
    /* bail out */
    PPPDEBUG((LOG_ERR, "pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));
    LINK_STATS_INC(link.lenerr);
    pbuf_free(pb);
    return ERR_BUF;
  } 

  p = (u8_t*)pb->payload + sizeof(struct eth_hdr);
  PPPOE_ADD_HEADER(p, 0, sc->sc_session, len);

  return pppoe_output(sc, pb);
}

#if 0 /*def PFIL_HOOKS*/
static int
pppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir)
{
  struct pppoe_softc *sc;
  int s;

  if (mp != (struct pbuf **)PFIL_IFNET_DETACH) {
    return 0;
  }

  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
    if (sc->sc_ethif != ifp) {
      continue;
    }
    if (sc->sc_sppp.pp_if.if_flags & IFF_UP) {
      sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING);
      printf("%c%c%"U16_F": ethernet interface detached, going down\n",
          sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
    }
    sc->sc_ethif = NULL;
    pppoe_clear_softc(sc, "ethernet interface detached");
  }

  return 0;
}
#endif

static void
pppoe_clear_softc(struct pppoe_softc *sc, const char *message)
{
  LWIP_UNUSED_ARG(message);

  /* stop timer */
  tcpip_untimeout(pppoe_timeout, sc);
  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message));

  /* fix our state */
  sc->sc_state = PPPOE_STATE_INITIAL;

  /* notify upper layers */
  sc->sc_linkStatusCB(sc->sc_pd, 0);

  /* clean up softc */
  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));
  if (sc->sc_ac_cookie) {
    mem_free(sc->sc_ac_cookie);
    sc->sc_ac_cookie = NULL;
  }
  sc->sc_ac_cookie_len = 0;
  sc->sc_session = 0;
}

#endif /* PPPOE_SUPPORT */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -