📄 ppp_oe.c
字号:
}
ethhdr = (struct eth_hdr *)pb->payload;
off += sizeof(*ethhdr);
ac_cookie = NULL;
ac_cookie_len = 0;
#ifdef PPPOE_SERVER
hunique = NULL;
hunique_len = 0;
#endif
session = 0;
if (pb->len - off <= PPPOE_HEADERLEN) {
printf("pppoe: packet too short: %d\n", pb->len);
goto done;
}
ph = (struct pppoehdr *) (ethhdr + 1);
if (ph->vertype != PPPOE_VERTYPE) {
printf("pppoe: unknown version/type packet: 0x%x\n", ph->vertype);
goto done;
}
session = ntohs(ph->session);
plen = ntohs(ph->plen);
off += sizeof(*ph);
if (plen + off > pb->len) {
printf("pppoe: packet content does not fit: data available = %d, packet size = %u\n",
pb->len - off, plen);
goto done;
}
if(pb->tot_len == pb->len) {
pb->tot_len = pb->len = off + plen; /* ignore trailing garbage */
}
tag = 0;
len = 0;
sc = NULL;
while (off + sizeof(pt) <= pb->len) {
MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt));
tag = ntohs(pt.tag);
len = ntohs(pt.len);
if (off + sizeof(pt) + len > pb->len) {
printf("pppoe: tag 0x%x len 0x%x is too long\n", tag, len);
goto done;
}
switch (tag) {
case PPPOE_TAG_EOL:
goto breakbreak;
case PPPOE_TAG_SNAME:
break; /* ignored */
case PPPOE_TAG_ACNAME:
break; /* ignored */
case PPPOE_TAG_HUNIQUE:
if (sc != NULL) {
break;
}
#ifdef PPPOE_SERVER
hunique = (u8_t*)pb->payload + off + sizeof(pt);
hunique_len = len;
#endif
sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif);
if (sc != NULL) {
snprintf(devname, sizeof(devname), "%c%c%"U16_F, sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
}
break;
case PPPOE_TAG_ACCOOKIE:
if (ac_cookie == NULL) {
ac_cookie = (u8_t*)pb->payload + off + sizeof(pt);
ac_cookie_len = len;
}
break;
case PPPOE_TAG_SNAME_ERR:
err_msg = "SERVICE NAME ERROR";
errortag = 1;
break;
case PPPOE_TAG_ACSYS_ERR:
err_msg = "AC SYSTEM ERROR";
errortag = 1;
break;
case PPPOE_TAG_GENERIC_ERR:
err_msg = "GENERIC ERROR";
errortag = 1;
break;
}
if (err_msg) {
error = NULL;
if (errortag && len) {
error = mem_malloc(len+1);
if (error) {
strncpy(error, (char*)pb->payload + off + sizeof(pt), len);
error[len-1] = '\0';
}
}
if (error) {
printf("%s: %s: %s\n", devname, err_msg, error);
mem_free(error);
} else {
printf("%s: %s\n", devname, err_msg);
}
if (errortag) {
goto done;
}
}
off += sizeof(pt) + len;
}
breakbreak:;
switch (ph->code) {
case PPPOE_CODE_PADI:
#ifdef PPPOE_SERVER
/*
* got service name, concentrator name, and/or host unique.
* ignore if we have no interfaces with IFF_PASSIVE|IFF_UP.
*/
if (LIST_EMPTY(&pppoe_softc_list)) {
goto done;
}
LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {
if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) {
continue;
}
if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {
continue;
}
if (sc->sc_state == PPPOE_STATE_INITIAL) {
break;
}
}
if (sc == NULL) {
/* printf("pppoe: free passive interface is not found\n"); */
goto done;
}
if (hunique) {
if (sc->sc_hunique) {
mem_free(sc->sc_hunique);
}
sc->sc_hunique = mem_malloc(hunique_len);
if (sc->sc_hunique == NULL) {
goto done;
}
sc->sc_hunique_len = hunique_len;
MEMCPY(sc->sc_hunique, hunique, hunique_len);
}
MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest);
sc->sc_state = PPPOE_STATE_PADO_SENT;
pppoe_send_pado(sc);
break;
#endif /* PPPOE_SERVER */
case PPPOE_CODE_PADR:
#ifdef PPPOE_SERVER
/*
* get sc from ac_cookie if IFF_PASSIVE
*/
if (ac_cookie == NULL) {
/* be quiet if there is not a single pppoe instance */
printf("pppoe: received PADR but not includes ac_cookie\n");
goto done;
}
sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif);
if (sc == NULL) {
/* be quiet if there is not a single pppoe instance */
if (!LIST_EMPTY(&pppoe_softc_list)) {
printf("pppoe: received PADR but could not find request for it\n");
}
goto done;
}
if (sc->sc_state != PPPOE_STATE_PADO_SENT) {
printf("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
goto done;
}
if (hunique) {
if (sc->sc_hunique) {
mem_free(sc->sc_hunique);
}
sc->sc_hunique = mem_malloc(hunique_len);
if (sc->sc_hunique == NULL) {
goto done;
}
sc->sc_hunique_len = hunique_len;
MEMCPY(sc->sc_hunique, hunique, hunique_len);
}
pppoe_send_pads(sc);
sc->sc_state = PPPOE_STATE_SESSION;
tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */
break;
#else
/* ignore, we are no access concentrator */
goto done;
#endif /* PPPOE_SERVER */
case PPPOE_CODE_PADO:
if (sc == NULL) {
/* be quiet if there is not a single pppoe instance */
if (!LIST_EMPTY(&pppoe_softc_list)) {
printf("pppoe: received PADO but could not find request for it\n");
}
goto done;
}
if (sc->sc_state != PPPOE_STATE_PADI_SENT) {
printf("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);
goto done;
}
if (ac_cookie) {
if (sc->sc_ac_cookie) {
mem_free(sc->sc_ac_cookie);
}
sc->sc_ac_cookie = mem_malloc(ac_cookie_len);
if (sc->sc_ac_cookie == NULL) {
goto done;
}
sc->sc_ac_cookie_len = ac_cookie_len;
MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len);
}
MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr));
tcpip_untimeout(pppoe_timeout, sc);
sc->sc_padr_retried = 0;
sc->sc_state = PPPOE_STATE_PADR_SENT;
if ((err = pppoe_send_padr(sc)) != 0) {
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_CODE_PADS:
if (sc == NULL) {
goto done;
}
sc->sc_session = session;
tcpip_untimeout(pppoe_timeout, sc);
PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": session 0x%x connected\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, session));
sc->sc_state = PPPOE_STATE_SESSION;
tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */
break;
case PPPOE_CODE_PADT:
if (sc == NULL) {
goto done;
}
pppoe_clear_softc(sc, "received PADT");
break;
default:
if(sc) {
printf("%c%c%"U16_F": unknown code (0x%04x) session = 0x%04x\n",
sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num,
ph->code, session);
} else {
printf("pppoe: unknown code (0x%04x) session = 0x%04x\n", ph->code, session);
}
break;
}
done:
pbuf_free(pb);
return;
}
void
pppoe_disc_input(struct netif *netif, struct pbuf *p)
{
/* avoid error messages if there is not a single pppoe instance */
if (!LIST_EMPTY(&pppoe_softc_list)) {
pppoe_dispatch_disc_pkt(netif, p);
} else {
pbuf_free(p);
}
}
void
pppoe_data_input(struct netif *netif, struct pbuf *pb)
{
u16_t session, plen;
struct pppoe_softc *sc;
struct pppoehdr *ph;
#ifdef PPPOE_TERM_UNKNOWN_SESSIONS
u8_t shost[ETHER_ADDR_LEN];
#endif
#ifdef PPPOE_TERM_UNKNOWN_SESSIONS
MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost));
#endif
if (pbuf_header(pb, -(int)sizeof(struct eth_hdr)) != 0) {
/* bail out */
PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header failed\n"));
LINK_STATS_INC(link.lenerr);
goto drop;
}
pb = pppSingleBuf (pb);
if (pb->len <= PPPOE_HEADERLEN) {
printf("pppoe (data): dropping too short packet: %d bytes\n", pb->len);
goto drop;
}
if (pb->len < sizeof(*ph)) {
printf("pppoe_data_input: could not get PPPoE header\n");
goto drop;
}
ph = (struct pppoehdr *)pb->payload;
if (ph->vertype != PPPOE_VERTYPE) {
printf("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype);
goto drop;
}
if (ph->code != 0) {
goto drop;
}
session = ntohs(ph->session);
sc = pppoe_find_softc_by_session(session, netif);
if (sc == NULL) {
#ifdef PPPOE_TERM_UNKNOWN_SESSIONS
printf("pppoe: input for unknown session 0x%x, sending PADT\n", session);
pppoe_send_padt(netif, session, shost);
#endif
goto drop;
}
plen = ntohs(ph->plen);
if (pbuf_header(pb, -(int)(PPPOE_HEADERLEN)) != 0) {
/* bail out */
PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header PPPOE_HEADERLEN failed\n"));
LINK_STATS_INC(link.lenerr);
goto drop;
}
PPPDEBUG((LOG_DEBUG, "pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n",
sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num,
pb->len, plen));
if (pb->len < plen) {
goto drop;
}
pppInProcOverEthernet(sc->sc_pd, pb);
return;
drop:
pbuf_free(pb);
}
static err_t
pppoe_output(struct pppoe_softc *sc, struct pbuf *pb)
{
struct eth_hdr *ethhdr;
u16_t etype;
err_t res;
if (!sc->sc_ethif) {
pbuf_free(pb);
return ERR_IF;
}
ethhdr = (struct eth_hdr *)pb->payload;
etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC;
ethhdr->type = htons(etype);
MEMCPY(ethhdr->dest.addr, sc->sc_dest.addr, sizeof(ethhdr->dest.addr));
MEMCPY(ethhdr->src.addr, ((struct eth_addr *)sc->sc_ethif->hwaddr)->addr, sizeof(ethhdr->src.addr));
PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n",
sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype,
sc->sc_state, sc->sc_session,
sc->sc_dest.addr[0], sc->sc_dest.addr[1], sc->sc_dest.addr[2], sc->sc_dest.addr[3], sc->sc_dest.addr[4], sc->sc_dest.addr[5],
pb->tot_len));
res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb);
pbuf_free(pb);
return res;
}
static err_t
pppoe_send_padi(struct pppoe_softc *sc)
{
struct pbuf *pb;
u8_t *p;
int len, l1 = 0, l2 = 0; /* XXX: gcc */
if (sc->sc_state >PPPOE_STATE_PADI_SENT) {
PPPDEBUG((LOG_ERR, "ERROR: pppoe_send_padi in state %d", sc->sc_state));
}
/* calculate length of frame (excluding ethernet header + pppoe header) */
len = 2 + 2 + 2 + 2 + sizeof sc; /* service name tag is required, host unique is send too */
if (sc->sc_service_name != NULL) {
l1 = strlen(sc->sc_service_name);
len += l1;
}
if (sc->sc_concentrator_name != NULL) {
l2 = strlen(sc->sc_concentrator_name);
len += 2 + 2 + l2;
}
/* allocate a buffer */
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);
/* fill in pkt */
PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 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_concentrator_name != NULL) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -