10f74e101Schristos /* 20f74e101Schristos * Copyright (c) 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997 30f74e101Schristos * The Regents of the University of California. All rights reserved. 40f74e101Schristos * 50f74e101Schristos * Redistribution and use in source and binary forms, with or without 60f74e101Schristos * modification, are permitted provided that: (1) source code distributions 70f74e101Schristos * retain the above copyright notice and this paragraph in its entirety, (2) 80f74e101Schristos * distributions including binary code include the above copyright notice and 90f74e101Schristos * this paragraph in its entirety in the documentation or other materials 100f74e101Schristos * provided with the distribution, and (3) all advertising materials mentioning 110f74e101Schristos * features or use of this software display the following acknowledgement: 120f74e101Schristos * ``This product includes software developed by the University of California, 130f74e101Schristos * Lawrence Berkeley Laboratory and its contributors.'' Neither the name of 140f74e101Schristos * the University nor the names of its contributors may be used to endorse 150f74e101Schristos * or promote products derived from this software without specific prior 160f74e101Schristos * written permission. 170f74e101Schristos * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED 180f74e101Schristos * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF 190f74e101Schristos * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 200f74e101Schristos * 210f74e101Schristos * Original code by Greg Stark <gsstark@mit.edu> 220f74e101Schristos */ 230f74e101Schristos 2411b3aaa1Schristos #include <sys/cdefs.h> 250f74e101Schristos #ifndef lint 26*26ba0b50Schristos __RCSID("$NetBSD: print-pppoe.c,v 1.9 2024/09/02 16:15:32 christos Exp $"); 270f74e101Schristos #endif 280f74e101Schristos 29dc860a36Sspz /* \summary: PPP-over-Ethernet (PPPoE) printer */ 30dc860a36Sspz 31c74ad251Schristos #include <config.h> 320f74e101Schristos 33c74ad251Schristos #include "netdissect-stdinc.h" 340f74e101Schristos 35c74ad251Schristos #include "netdissect-ctype.h" 36c74ad251Schristos 37c74ad251Schristos #define ND_LONGJMP_FROM_TCHECK 38fdccd7e4Schristos #include "netdissect.h" 39fdccd7e4Schristos #include "extract.h" 400f74e101Schristos 410f74e101Schristos /* Codes */ 420f74e101Schristos enum { 430f74e101Schristos PPPOE_PADI = 0x09, 440f74e101Schristos PPPOE_PADO = 0x07, 450f74e101Schristos PPPOE_PADR = 0x19, 460f74e101Schristos PPPOE_PADS = 0x65, 470f74e101Schristos PPPOE_PADT = 0xa7 480f74e101Schristos }; 490f74e101Schristos 50870189d2Schristos static const struct tok pppoecode2str[] = { 510f74e101Schristos { PPPOE_PADI, "PADI" }, 520f74e101Schristos { PPPOE_PADO, "PADO" }, 530f74e101Schristos { PPPOE_PADR, "PADR" }, 540f74e101Schristos { PPPOE_PADS, "PADS" }, 550f74e101Schristos { PPPOE_PADT, "PADT" }, 560f74e101Schristos { 0, "" }, /* PPP Data */ 570f74e101Schristos { 0, NULL } 580f74e101Schristos }; 590f74e101Schristos 600f74e101Schristos /* Tags */ 610f74e101Schristos enum { 620f74e101Schristos PPPOE_EOL = 0, 630f74e101Schristos PPPOE_SERVICE_NAME = 0x0101, 640f74e101Schristos PPPOE_AC_NAME = 0x0102, 650f74e101Schristos PPPOE_HOST_UNIQ = 0x0103, 660f74e101Schristos PPPOE_AC_COOKIE = 0x0104, 670f74e101Schristos PPPOE_VENDOR = 0x0105, 680f74e101Schristos PPPOE_RELAY_SID = 0x0110, 690e9868baSchristos PPPOE_MAX_PAYLOAD = 0x0120, 700f74e101Schristos PPPOE_SERVICE_NAME_ERROR = 0x0201, 710f74e101Schristos PPPOE_AC_SYSTEM_ERROR = 0x0202, 720f74e101Schristos PPPOE_GENERIC_ERROR = 0x0203 730f74e101Schristos }; 740f74e101Schristos 75870189d2Schristos static const struct tok pppoetag2str[] = { 760f74e101Schristos { PPPOE_EOL, "EOL" }, 770f74e101Schristos { PPPOE_SERVICE_NAME, "Service-Name" }, 780f74e101Schristos { PPPOE_AC_NAME, "AC-Name" }, 790f74e101Schristos { PPPOE_HOST_UNIQ, "Host-Uniq" }, 800f74e101Schristos { PPPOE_AC_COOKIE, "AC-Cookie" }, 810f74e101Schristos { PPPOE_VENDOR, "Vendor-Specific" }, 820f74e101Schristos { PPPOE_RELAY_SID, "Relay-Session-ID" }, 830e9868baSchristos { PPPOE_MAX_PAYLOAD, "PPP-Max-Payload" }, 840f74e101Schristos { PPPOE_SERVICE_NAME_ERROR, "Service-Name-Error" }, 850f74e101Schristos { PPPOE_AC_SYSTEM_ERROR, "AC-System-Error" }, 860f74e101Schristos { PPPOE_GENERIC_ERROR, "Generic-Error" }, 870f74e101Schristos { 0, NULL } 880f74e101Schristos }; 890f74e101Schristos 900f74e101Schristos #define PPPOE_HDRLEN 6 910f74e101Schristos #define MAXTAGPRINT 80 920f74e101Schristos 93c74ad251Schristos void 94c74ad251Schristos pppoe_if_print(netdissect_options *ndo, const struct pcap_pkthdr *h, const u_char *p) 950f74e101Schristos { 96c74ad251Schristos ndo->ndo_protocol = "pppoe"; 97c74ad251Schristos ndo->ndo_ll_hdr_len += pppoe_print(ndo, p, h->len); 980f74e101Schristos } 990f74e101Schristos 1000f74e101Schristos u_int 101c74ad251Schristos pppoe_print(netdissect_options *ndo, const u_char *bp, u_int length) 1020f74e101Schristos { 103b3a00663Schristos uint16_t pppoe_ver, pppoe_type, pppoe_code, pppoe_sessionid; 1040f74e101Schristos u_int pppoe_length; 1050f74e101Schristos const u_char *pppoe_packet, *pppoe_payload; 1060f74e101Schristos 107c74ad251Schristos ndo->ndo_protocol = "pppoe"; 1080f74e101Schristos if (length < PPPOE_HDRLEN) { 109c74ad251Schristos ND_PRINT(" (length %u < %u)", length, PPPOE_HDRLEN); 110c74ad251Schristos goto invalid; 1110f74e101Schristos } 1120f74e101Schristos length -= PPPOE_HDRLEN; 1130f74e101Schristos pppoe_packet = bp; 114c74ad251Schristos ND_TCHECK_LEN(pppoe_packet, PPPOE_HDRLEN); 115c74ad251Schristos pppoe_ver = (GET_U_1(pppoe_packet) & 0xF0) >> 4; 116c74ad251Schristos pppoe_type = (GET_U_1(pppoe_packet) & 0x0F); 117c74ad251Schristos pppoe_code = GET_U_1(pppoe_packet + 1); 118c74ad251Schristos pppoe_sessionid = GET_BE_U_2(pppoe_packet + 2); 119c74ad251Schristos pppoe_length = GET_BE_U_2(pppoe_packet + 4); 1200f74e101Schristos pppoe_payload = pppoe_packet + PPPOE_HDRLEN; 1210f74e101Schristos 1220f74e101Schristos if (pppoe_ver != 1) { 123c74ad251Schristos ND_PRINT(" [ver %u]",pppoe_ver); 1240f74e101Schristos } 1250f74e101Schristos if (pppoe_type != 1) { 126c74ad251Schristos ND_PRINT(" [type %u]",pppoe_type); 1270f74e101Schristos } 1280f74e101Schristos 129c74ad251Schristos ND_PRINT("PPPoE %s", tok2str(pppoecode2str, "PAD-%x", pppoe_code)); 1300f74e101Schristos if (pppoe_code == PPPOE_PADI && pppoe_length > 1484 - PPPOE_HDRLEN) { 131c74ad251Schristos ND_PRINT(" [len %u!]",pppoe_length); 1320f74e101Schristos } 1330f74e101Schristos if (pppoe_length > length) { 134c74ad251Schristos ND_PRINT(" [len %u > %u!]", pppoe_length, length); 1350f74e101Schristos pppoe_length = length; 1360f74e101Schristos } 1370f74e101Schristos if (pppoe_sessionid) { 138c74ad251Schristos ND_PRINT(" [ses 0x%x]", pppoe_sessionid); 1390f74e101Schristos } 1400f74e101Schristos 1410f74e101Schristos if (pppoe_code) { 1420f74e101Schristos /* PPP session packets don't contain tags */ 1430f74e101Schristos u_short tag_type = 0xffff, tag_len; 1440f74e101Schristos const u_char *p = pppoe_payload; 1450f74e101Schristos 1460f74e101Schristos /* 1470f74e101Schristos * loop invariant: 1480f74e101Schristos * p points to current tag, 1490f74e101Schristos * tag_type is previous tag or 0xffff for first iteration 1500f74e101Schristos */ 1510f74e101Schristos while (tag_type && p < pppoe_payload + pppoe_length) { 152c74ad251Schristos tag_type = GET_BE_U_2(p); 153c74ad251Schristos tag_len = GET_BE_U_2(p + 2); 1540f74e101Schristos p += 4; 1550f74e101Schristos /* p points to tag_value */ 1560f74e101Schristos 1570f74e101Schristos if (tag_len) { 158fdccd7e4Schristos unsigned ascii_count = 0, garbage_count = 0; 159870189d2Schristos const u_char *v; 1600f74e101Schristos char tag_str[MAXTAGPRINT]; 1610f74e101Schristos unsigned tag_str_len = 0; 1620f74e101Schristos 1630f74e101Schristos /* TODO print UTF-8 decoded text */ 164c74ad251Schristos ND_TCHECK_LEN(p, tag_len); 1650f74e101Schristos for (v = p; v < p + tag_len && tag_str_len < MAXTAGPRINT-1; v++) 166c74ad251Schristos if (ND_ASCII_ISPRINT(GET_U_1(v))) { 167c74ad251Schristos tag_str[tag_str_len++] = GET_U_1(v); 168fdccd7e4Schristos ascii_count++; 1690f74e101Schristos } else { 1700f74e101Schristos tag_str[tag_str_len++] = '.'; 171fdccd7e4Schristos garbage_count++; 1720f74e101Schristos } 1730f74e101Schristos tag_str[tag_str_len] = 0; 1740f74e101Schristos 175fdccd7e4Schristos if (ascii_count > garbage_count) { 176c74ad251Schristos ND_PRINT(" [%s \"%*.*s\"]", 1770f74e101Schristos tok2str(pppoetag2str, "TAG-0x%x", tag_type), 1780f74e101Schristos (int)tag_str_len, 1790f74e101Schristos (int)tag_str_len, 180c74ad251Schristos tag_str); 1810f74e101Schristos } else { 1820f74e101Schristos /* Print hex, not fast to abuse printf but this doesn't get used much */ 183c74ad251Schristos ND_PRINT(" [%s 0x", tok2str(pppoetag2str, "TAG-0x%x", tag_type)); 1840f74e101Schristos for (v=p; v<p+tag_len; v++) { 185c74ad251Schristos ND_PRINT("%02X", GET_U_1(v)); 1860f74e101Schristos } 187c74ad251Schristos ND_PRINT("]"); 1880f74e101Schristos } 1890f74e101Schristos 1900f74e101Schristos 1910f74e101Schristos } else 192c74ad251Schristos ND_PRINT(" [%s]", tok2str(pppoetag2str, 193c74ad251Schristos "TAG-0x%x", tag_type)); 1940f74e101Schristos 1950f74e101Schristos p += tag_len; 1960f74e101Schristos /* p points to next tag */ 1970f74e101Schristos } 198c74ad251Schristos return PPPOE_HDRLEN; 1990f74e101Schristos } else { 2000f74e101Schristos /* PPPoE data */ 201c74ad251Schristos ND_PRINT(" "); 202b3a00663Schristos return (PPPOE_HDRLEN + ppp_print(ndo, pppoe_payload, pppoe_length)); 2030f74e101Schristos } 204c74ad251Schristos /* NOTREACHED */ 2050f74e101Schristos 206c74ad251Schristos invalid: 207c74ad251Schristos nd_print_invalid(ndo); 208c74ad251Schristos return 0; 2090f74e101Schristos } 210