📄 ppp_oe.c
字号:
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 + -