/********************************************************************** *%FUNCTION: parsePacket *%ARGUMENTS: * packet -- the PPPoE discovery packet to parse * func -- function called for each tag in the packet * extra -- an opaque data pointer supplied to parsing function *%RETURNS: * 0 if everything went well; -1 if there was an error *%DESCRIPTION: * Parses a PPPoE discovery packet, calling "func" for each tag in the packet. * "func" is passed the additional argument "extra". ***********************************************************************/ int parsePacket(PPPoEPacket *packet, ParseFunc *func, void *extra) { UINT16_t len = ntohs(packet->length); unsigned char *curTag; UINT16_t tagType, tagLen; if (PPPOE_VER(packet->vertype) != 1) { fprintf(stderr, "Invalid PPPoE version (%d)\n", PPPOE_VER(packet->vertype)); return -1; } if (PPPOE_TYPE(packet->vertype) != 1) { fprintf(stderr, "Invalid PPPoE type (%d)\n", PPPOE_TYPE(packet->vertype)); return -1; } /* Do some sanity checks on packet */ if (len > ETH_JUMBO_LEN - PPPOE_OVERHEAD) { /* 6-byte overhead for PPPoE header */ fprintf(stderr, "Invalid PPPoE packet length (%u)\n", len); return -1; } /* Step through the tags */ curTag = packet->payload; while(curTag - packet->payload < len) { /* Alignment is not guaranteed, so do this by hand... */ tagType = (curTag[0] << 8) + curTag[1]; tagLen = (curTag[2] << 8) + curTag[3]; if (tagType == TAG_END_OF_LIST) { return 0; } if ((curTag - packet->payload) + tagLen + TAG_HDR_SIZE > len) { fprintf(stderr, "Invalid PPPoE tag length (%u)\n", tagLen); return -1; } func(tagType, tagLen, curTag+TAG_HDR_SIZE, extra); curTag = curTag + TAG_HDR_SIZE + tagLen; } return 0; }
/* Print out a PPPOE packet for debugging */ void pppoe_printpkt(PPPoEPacket *packet, void (*printer)(void *, char *, ...), void *arg) { int len = ntohs(packet->length); int i, tag, tlen, text; switch (ntohs(packet->ethHdr.h_proto)) { case ETH_PPPOE_DISCOVERY: printer(arg, "PPPOE Discovery V%dT%d ", PPPOE_VER(packet->vertype), PPPOE_TYPE(packet->vertype)); switch (packet->code) { case CODE_PADI: printer(arg, "PADI"); break; case CODE_PADO: printer(arg, "PADO"); break; case CODE_PADR: printer(arg, "PADR"); break; case CODE_PADS: printer(arg, "PADS"); break; case CODE_PADT: printer(arg, "PADT"); break; default: printer(arg, "unknown code %x", packet->code); } printer(arg, " session 0x%x length %d\n", ntohs(packet->session), len); break; case ETH_PPPOE_SESSION: printer(arg, "PPPOE Session V%dT%d", PPPOE_VER(packet->vertype), PPPOE_TYPE(packet->vertype)); printer(arg, " code 0x%x session 0x%x length %d\n", packet->code, ntohs(packet->session), len); break; default: printer(arg, "Unknown ethernet frame with proto = 0x%x\n", ntohs(packet->ethHdr.h_proto)); } printer(arg, " dst %02x:%02x:%02x:%02x:%02x:%02x ", EH(packet->ethHdr.h_dest)); printer(arg, " src %02x:%02x:%02x:%02x:%02x:%02x\n", EH(packet->ethHdr.h_source)); if (ntohs(packet->ethHdr.h_proto) != ETH_PPPOE_DISCOVERY) return; for (i = 0; i + TAG_HDR_SIZE <= len; i += tlen) { tag = (packet->payload[i] << 8) + packet->payload[i+1]; tlen = (packet->payload[i+2] << 8) + packet->payload[i+3]; if (i + tlen + TAG_HDR_SIZE > len) break; text = 0; i += TAG_HDR_SIZE; printer(arg, " ["); switch (tag) { case TAG_END_OF_LIST: printer(arg, "end-of-list"); break; case TAG_SERVICE_NAME: printer(arg, "service-name"); text = 1; break; case TAG_AC_NAME: printer(arg, "AC-name"); text = 1; break; case TAG_HOST_UNIQ: printer(arg, "host-uniq"); break; case TAG_AC_COOKIE: printer(arg, "AC-cookie"); break; case TAG_VENDOR_SPECIFIC: printer(arg, "vendor-specific"); break; case TAG_RELAY_SESSION_ID: printer(arg, "relay-session-id"); break; case TAG_PPP_MAX_PAYLOAD: printer(arg, "PPP-max-payload"); break; case TAG_SERVICE_NAME_ERROR: printer(arg, "service-name-error"); text = 1; break; case TAG_AC_SYSTEM_ERROR: printer(arg, "AC-system-error"); text = 1; break; case TAG_GENERIC_ERROR: printer(arg, "generic-error"); text = 1; break; default: printer(arg, "unknown tag 0x%x", tag); } if (tlen) { if (text) printer(arg, " %.*v", tlen, &packet->payload[i]); else if (tlen <= 32) printer(arg, " %.*B", tlen, &packet->payload[i]); else printer(arg, " %.32B... (length %d)", &packet->payload[i], tlen); } printer(arg, "]"); } printer(arg, "\n"); }