/** * Handle incoming PPPoE packets. */ int pppoe_handler (const pppoe_Packet *pkt) { const BYTE *buf; const void *src; const void *dst; WORD proto, len; BOOL bcast, delivered = FALSE; if (pkt->type != 1 || pkt->ver != 1) return (0); src = MAC_SRC (pkt); dst = MAC_DST (pkt); proto = MAC_TYP (pkt); bcast = !memcmp (dst, _eth_brdcast, _eth_mac_len); if (proto == PPPOE_SESS_TYPE && state == StateSession) { if (pkt->code == PPPOE_CODE_SESS && pkt->session == session && !bcast && !memcmp(dst, _eth_addr, _eth_mac_len) && /* to us? */ !memcmp(src, ac_macAddr, _eth_mac_len)) { len = intel16 (pkt->length); buf = &pkt->data[0]; ppp_input (buf, len); /* assume ppp_input() traces it */ delivered = TRUE; } } else if (!bcast && proto == PPPOE_DISC_TYPE && state == StateDiscovery) { if (pkt->code == PPPOE_CODE_PADO) /* Offer (can this be bcast?) */ { got_PADO = TRUE; memcpy (ac_macAddr, src, _eth_mac_len); } else if (pkt->code == PPPOE_CODE_PADT && /* Terminate */ pkt->session == session) { if (cfg.trace) outsnl (_LANG("PPPoE: session terminated")); got_PADT = TRUE; session = 0; } else if (pkt->code == PPPOE_CODE_PADS) /* Session-confirmation */ { got_PADS = TRUE; session = pkt->session; } else if (pkt->code == PPPOE_CODE_PADM) /* Message (what to do?) */ { got_PADM = TRUE; } } if (!delivered) DEBUG_RX (NULL, pkt); return (1); }
/* Called when an AAL5 PDU comes in */ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb) { struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc); pr_debug("\n"); if (skb == NULL) { /* VCC was closed */ pr_debug("removing ATMPPP VCC %p\n", pvcc); pppoatm_unassign_vcc(atmvcc); atmvcc->push(atmvcc, NULL); /* Pass along bad news */ return; } atm_return(atmvcc, skb->truesize); switch (pvcc->encaps) { case e_llc: if (skb->len < LLC_LEN || memcmp(skb->data, pppllc, LLC_LEN)) goto error; skb_pull(skb, LLC_LEN); break; case e_autodetect: if (pvcc->chan.ppp == NULL) { /* Not bound yet! */ kfree_skb(skb); return; } if (skb->len >= sizeof(pppllc) && !memcmp(skb->data, pppllc, sizeof(pppllc))) { pvcc->encaps = e_llc; skb_pull(skb, LLC_LEN); break; } if (skb->len >= (sizeof(pppllc) - LLC_LEN) && !memcmp(skb->data, &pppllc[LLC_LEN], sizeof(pppllc) - LLC_LEN)) { pvcc->encaps = e_vc; pvcc->chan.mtu += LLC_LEN; break; } pr_debug("Couldn't autodetect yet (skb: %02X %02X %02X %02X %02X %02X)\n", skb->data[0], skb->data[1], skb->data[2], skb->data[3], skb->data[4], skb->data[5]); goto error; case e_vc: break; } ppp_input(&pvcc->chan, skb); return; error: kfree_skb(skb); ppp_input_error(&pvcc->chan, 0); }