1 0 stevel /* 2 0 stevel * CDDL HEADER START 3 0 stevel * 4 0 stevel * The contents of this file are subject to the terms of the 5 0 stevel * Common Development and Distribution License, Version 1.0 only 6 0 stevel * (the "License"). You may not use this file except in compliance 7 0 stevel * with the License. 8 0 stevel * 9 0 stevel * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 0 stevel * or http://www.opensolaris.org/os/licensing. 11 0 stevel * See the License for the specific language governing permissions 12 0 stevel * and limitations under the License. 13 0 stevel * 14 0 stevel * When distributing Covered Code, include this CDDL HEADER in each 15 0 stevel * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 0 stevel * If applicable, add the following below this CDDL HEADER, with the 17 0 stevel * fields enclosed by brackets "[]" replaced with your own identifying 18 0 stevel * information: Portions Copyright [yyyy] [name of copyright owner] 19 0 stevel * 20 0 stevel * CDDL HEADER END 21 0 stevel */ 22 0 stevel /* 23 0 stevel * Copyright (c) 2001 by Sun Microsystems, Inc. 24 0 stevel * All rights reserved. 25 0 stevel */ 26 0 stevel 27 0 stevel #pragma ident "%Z%%M% %I% %E% SMI" 28 0 stevel 29 0 stevel #include <stdio.h> 30 0 stevel #include <string.h> 31 0 stevel #include <sys/types.h> 32 0 stevel #include <sys/socket.h> 33 0 stevel #include <sys/sysmacros.h> 34 0 stevel #include <netinet/in.h> 35 0 stevel #include <arpa/inet.h> 36 0 stevel #include <net/pppoe.h> 37 0 stevel #include "snoop.h" 38 0 stevel 39 0 stevel /* 40 0 stevel * These two macros extract the version and type fields respectively from 41 0 stevel * the first byte of the PPPoE header. 42 0 stevel */ 43 0 stevel #define POE_VERS(x) (((x) >> 4) & 0x0f) 44 0 stevel #define POE_TYPE(x) ((x) & 0x0f) 45 0 stevel 46 0 stevel typedef void interpret_func_t(uint8_t *, uint16_t); 47 0 stevel 48 0 stevel typedef struct taginfo { 49 0 stevel char *tag_name; 50 0 stevel uint16_t tag_type; 51 0 stevel interpret_func_t *interpret_tagvalue; 52 0 stevel } taginfo_t; 53 0 stevel 54 0 stevel 55 0 stevel static char *pppoe_codetoname(int, boolean_t); 56 0 stevel static taginfo_t *pppoe_gettaginfo(uint16_t); 57 0 stevel static void print_hexdata(char *, uint8_t *, uint16_t); 58 0 stevel static void print_utf8string(char *, char *, uint16_t); 59 0 stevel static char *print_linetag(char *); 60 0 stevel static interpret_func_t interpret_tags; 61 0 stevel static interpret_func_t interpret_hexdata; 62 0 stevel static interpret_func_t interpret_service; 63 0 stevel static interpret_func_t interpret_access; 64 0 stevel static interpret_func_t interpret_cookie; 65 0 stevel static interpret_func_t interpret_vendor; 66 0 stevel static interpret_func_t interpret_relay; 67 0 stevel static interpret_func_t interpret_error; 68 0 stevel static interpret_func_t interpret_hurl; 69 0 stevel static interpret_func_t interpret_motm; 70 0 stevel static interpret_func_t interpret_rteadd; 71 0 stevel 72 0 stevel 73 0 stevel static taginfo_t taginfo_array[] = { 74 0 stevel { "End-Of-List", POETT_END, interpret_hexdata }, 75 0 stevel { "Service-Name", POETT_SERVICE, interpret_service }, 76 0 stevel { "AC-Name", POETT_ACCESS, interpret_access }, 77 0 stevel { "Host-Uniq", POETT_UNIQ, interpret_hexdata }, 78 0 stevel { "AC-Cookie", POETT_COOKIE, interpret_cookie }, 79 0 stevel { "Vendor-Specific", POETT_VENDOR, interpret_vendor }, 80 0 stevel { "Relay-Session-Id", POETT_RELAY, interpret_relay }, 81 0 stevel { "Service-Name-Error", POETT_NAMERR, interpret_error }, 82 0 stevel { "AC-System-Error", POETT_SYSERR, interpret_error }, 83 0 stevel { "Generic-Error", POETT_GENERR, interpret_error }, 84 0 stevel { "Multicast-Capable", POETT_MULTI, interpret_hexdata }, 85 0 stevel { "Host-URL", POETT_HURL, interpret_hurl }, 86 0 stevel { "Message-Of-The-Minute", POETT_MOTM, interpret_motm }, 87 0 stevel { "IP-Route-Add", POETT_RTEADD, interpret_rteadd }, 88 0 stevel { "Unknown TAG", 0, NULL } 89 0 stevel }; 90 0 stevel 91 0 stevel 92 0 stevel int 93 0 stevel interpret_pppoe(int flags, poep_t *poep, int len) 94 0 stevel { 95 0 stevel uint8_t code = poep->poep_code; 96 0 stevel uint8_t *payload; 97 0 stevel 98 0 stevel if (len < sizeof (poep_t)) 99 0 stevel return (len); 100 0 stevel 101 0 stevel payload = (uint8_t *)poep + sizeof (poep_t); 102 0 stevel 103 0 stevel if (flags & F_SUM) { 104 0 stevel (void) sprintf(get_sum_line(), "PPPoE %s", 105 0 stevel pppoe_codetoname(code, B_FALSE)); 106 0 stevel } else { /* flags & F_DTAIL */ 107 0 stevel show_header("PPPoE: ", "PPP Over Ethernet", len); 108 0 stevel show_space(); 109 0 stevel 110 0 stevel (void) sprintf(get_line(0, 0), 111 0 stevel "Version = %d", POE_VERS(poep->poep_version_type)); 112 0 stevel 113 0 stevel (void) sprintf(get_line(0, 0), 114 0 stevel "Type = %d", POE_TYPE(poep->poep_version_type)); 115 0 stevel 116 0 stevel (void) sprintf(get_line(0, 0), 117 0 stevel "Code = %d (%s)", code, pppoe_codetoname(code, B_TRUE)); 118 0 stevel 119 0 stevel (void) sprintf(get_line(0, 0), 120 0 stevel "Session Id = %d", ntohs(poep->poep_session_id)); 121 0 stevel 122 0 stevel (void) sprintf(get_line(0, 0), 123 0 stevel "Length = %d bytes", ntohs(poep->poep_length)); 124 0 stevel 125 0 stevel show_space(); 126 0 stevel 127 0 stevel len -= sizeof (poep_t); 128 0 stevel len = MIN(len, ntohs(poep->poep_length)); 129 0 stevel 130 0 stevel if (poep->poep_code != 0 && poep->poep_length > 0) { 131 0 stevel interpret_tags(payload, len); 132 0 stevel } 133 0 stevel } 134 0 stevel 135 0 stevel if (poep->poep_code == 0) { 136 0 stevel return (interpret_ppp(flags, payload, len)); 137 0 stevel } 138 0 stevel return (len); 139 0 stevel } 140 0 stevel 141 0 stevel 142 0 stevel /* 143 0 stevel * interpret_tags() prints PPPoE Discovery Stage TAGs in detail. 144 0 stevel */ 145 0 stevel static void 146 0 stevel interpret_tags(uint8_t *payload, uint16_t length) 147 0 stevel { 148 0 stevel uint8_t *tagptr = payload; 149 0 stevel uint16_t tag_length; 150 0 stevel uint16_t tag_type; 151 0 stevel uint8_t *tag_value; 152 0 stevel taginfo_t *tinfo; 153 0 stevel 154 0 stevel while (length >= POET_HDRLEN) { 155 0 stevel tag_type = POET_GET_TYPE(tagptr); 156 0 stevel tag_length = POET_GET_LENG(tagptr); 157 0 stevel 158 0 stevel tinfo = pppoe_gettaginfo(tag_type); 159 0 stevel 160 0 stevel show_header("PPPoE: ", tinfo->tag_name, 161 0 stevel tag_length + POET_HDRLEN); 162 0 stevel 163 0 stevel (void) sprintf(get_line(0, 0), 164 0 stevel "Tag Type = %d", tag_type); 165 0 stevel 166 0 stevel (void) sprintf(get_line(0, 0), 167 0 stevel "Tag Length = %d bytes", tag_length); 168 0 stevel 169 0 stevel length -= POET_HDRLEN; 170 0 stevel if (tag_length > length) { 171 0 stevel (void) sprintf(get_line(0, 0), 172 0 stevel "Warning: Truncated Packet"); 173 0 stevel show_space(); 174 0 stevel break; 175 0 stevel } 176 0 stevel 177 0 stevel /* 178 0 stevel * unknown tags or tags which should always have 0 length 179 0 stevel * are not interpreted any further. 180 0 stevel */ 181 0 stevel tag_value = POET_DATA(tagptr); 182 0 stevel if (tag_length != 0 && tinfo->interpret_tagvalue != NULL) 183 0 stevel tinfo->interpret_tagvalue(tag_value, tag_length); 184 0 stevel 185 0 stevel show_space(); 186 0 stevel length -= tag_length; 187 0 stevel tagptr = POET_NEXT(tagptr); 188 0 stevel } 189 0 stevel } 190 0 stevel 191 0 stevel static char * 192 0 stevel pppoe_codetoname(int code, boolean_t verbose) 193 0 stevel { 194 0 stevel char *name; 195 0 stevel 196 0 stevel switch (code) { 197 0 stevel case POECODE_DATA: 198 0 stevel name = "Session"; 199 0 stevel break; 200 0 stevel case POECODE_PADO: 201 0 stevel if (verbose) 202 0 stevel name = "Active Discovery Offer"; 203 0 stevel else 204 0 stevel name = "PADO"; 205 0 stevel break; 206 0 stevel case POECODE_PADI: 207 0 stevel if (verbose) 208 0 stevel name = "Active Discovery Initiation"; 209 0 stevel else 210 0 stevel name = "PADI"; 211 0 stevel break; 212 0 stevel case POECODE_PADR: 213 0 stevel if (verbose) 214 0 stevel name = "Active Discovery Request"; 215 0 stevel else 216 0 stevel name = "PADR"; 217 0 stevel break; 218 0 stevel case POECODE_PADS: 219 0 stevel if (verbose) 220 0 stevel name = "Active Discovery Session-Confirmation"; 221 0 stevel else 222 0 stevel name = "PADS"; 223 0 stevel break; 224 0 stevel case POECODE_PADT: 225 0 stevel if (verbose) 226 0 stevel name = "Active Discovery Terminate"; 227 0 stevel else 228 0 stevel name = "PADT"; 229 0 stevel break; 230 0 stevel case POECODE_PADM: 231 0 stevel if (verbose) 232 0 stevel name = "Active Discovery Message"; 233 0 stevel else 234 0 stevel name = "PADM"; 235 0 stevel break; 236 0 stevel case POECODE_PADN: 237 0 stevel if (verbose) 238 0 stevel name = "Active Discovery Network"; 239 0 stevel else 240 0 stevel name = "PADN"; 241 0 stevel break; 242 0 stevel default: 243 0 stevel name = "Unknown Code"; 244 0 stevel } 245 0 stevel 246 0 stevel return (name); 247 0 stevel } 248 0 stevel 249 0 stevel static taginfo_t * 250 0 stevel pppoe_gettaginfo(uint16_t type) 251 0 stevel { 252 0 stevel taginfo_t *taginfo_ptr = &taginfo_array[0]; 253 0 stevel int i = 0; 254 0 stevel 255 0 stevel while (taginfo_ptr->tag_type != type && 256 0 stevel taginfo_ptr->interpret_tagvalue != NULL) { 257 0 stevel taginfo_ptr = &taginfo_array[++i]; 258 0 stevel } 259 0 stevel 260 0 stevel return (taginfo_ptr); 261 0 stevel } 262 0 stevel 263 0 stevel static void 264 0 stevel interpret_hexdata(uint8_t *tag_value, uint16_t tag_length) 265 0 stevel { 266 0 stevel char *endofline; 267 0 stevel 268 0 stevel endofline = print_linetag("Data = "); 269 0 stevel print_hexdata(endofline, tag_value, tag_length); 270 0 stevel } 271 0 stevel 272 0 stevel static void 273 0 stevel interpret_service(uint8_t *tag_value, uint16_t tag_length) 274 0 stevel { 275 0 stevel char *endofline; 276 0 stevel 277 0 stevel endofline = print_linetag("Service Name = "); 278 0 stevel print_utf8string(endofline, (char *)tag_value, tag_length); 279 0 stevel } 280 0 stevel 281 0 stevel static void 282 0 stevel interpret_access(uint8_t *tag_value, uint16_t tag_length) 283 0 stevel { 284 0 stevel char *endofline; 285 0 stevel 286 0 stevel endofline = print_linetag("AC Name = "); 287 0 stevel print_utf8string(endofline, (char *)tag_value, tag_length); 288 0 stevel } 289 0 stevel 290 0 stevel static void 291 0 stevel interpret_cookie(uint8_t *tag_value, uint16_t tag_length) 292 0 stevel { 293 0 stevel char *endofline; 294 0 stevel 295 0 stevel endofline = print_linetag("Cookie = "); 296 0 stevel print_hexdata(endofline, tag_value, tag_length); 297 0 stevel } 298 0 stevel 299 0 stevel static void 300 0 stevel interpret_vendor(uint8_t *tag_value, uint16_t tag_length) 301 0 stevel { 302 0 stevel uint8_t *vendor_data; 303 0 stevel uint32_t vendorid; 304 0 stevel char *endofline; 305 0 stevel 306 0 stevel vendorid = ntohl(*(uint32_t *)tag_value); 307 0 stevel (void) sprintf(get_line(0, 0), 308 0 stevel "Vendor ID = %d", vendorid); 309 0 stevel 310 0 stevel if (tag_length > 4) { 311 0 stevel vendor_data = tag_value + 4; 312 0 stevel endofline = print_linetag("Vendor Data = "); 313 0 stevel print_hexdata(endofline, vendor_data, tag_length - 4); 314 0 stevel } 315 0 stevel } 316 0 stevel 317 0 stevel static void 318 0 stevel interpret_relay(uint8_t *tag_value, uint16_t tag_length) 319 0 stevel { 320 0 stevel char *endofline; 321 0 stevel 322 0 stevel endofline = print_linetag("ID = "); 323 0 stevel print_hexdata(endofline, tag_value, tag_length); 324 0 stevel } 325 0 stevel 326 0 stevel static void 327 0 stevel interpret_error(uint8_t *tag_value, uint16_t tag_length) 328 0 stevel { 329 0 stevel char *endofline; 330 0 stevel 331 0 stevel endofline = print_linetag("Error = "); 332 0 stevel print_utf8string(endofline, (char *)tag_value, tag_length); 333 0 stevel } 334 0 stevel 335 0 stevel static void 336 0 stevel interpret_hurl(uint8_t *tag_value, uint16_t tag_length) 337 0 stevel { 338 0 stevel char *endofline; 339 0 stevel 340 0 stevel endofline = print_linetag("URL = "); 341 0 stevel print_utf8string(endofline, (char *)tag_value, tag_length); 342 0 stevel } 343 0 stevel 344 0 stevel static void 345 0 stevel interpret_motm(uint8_t *tag_value, uint16_t tag_length) 346 0 stevel { 347 0 stevel char *endofline; 348 0 stevel 349 0 stevel endofline = print_linetag("Message = "); 350 0 stevel print_utf8string(endofline, (char *)tag_value, tag_length); 351 0 stevel } 352 0 stevel 353 0 stevel static void 354 0 stevel interpret_rteadd(uint8_t *tag_value, uint16_t tag_length) 355 0 stevel { 356 0 stevel char dest[INET_ADDRSTRLEN]; 357 0 stevel char mask[INET_ADDRSTRLEN]; 358 0 stevel char gateway[INET_ADDRSTRLEN]; 359 0 stevel uint32_t metric; 360 0 stevel 361 0 stevel if (tag_length == 16) { 362 0 stevel (void) inet_ntop(AF_INET, tag_value, dest, 363 0 stevel INET_ADDRSTRLEN); 364 0 stevel (void) inet_ntop(AF_INET, &tag_value[4], mask, 365 0 stevel INET_ADDRSTRLEN); 366 0 stevel (void) inet_ntop(AF_INET, &tag_value[8], gateway, 367 0 stevel INET_ADDRSTRLEN); 368 0 stevel metric = ntohl(*(uint32_t *)&tag_value[12]); 369 0 stevel sprintf(get_line(0, 0), 370 0 stevel "Destination\tNetmask\tGateway\tMetric"); 371 0 stevel sprintf(get_line(0, 0), 372 0 stevel "%s\t%s\t%s\t%d", dest, mask, gateway, metric); 373 0 stevel } 374 0 stevel } 375 0 stevel 376 0 stevel static void 377 0 stevel print_hexdata(char *line, uint8_t *data, uint16_t length) 378 0 stevel { 379 0 stevel uint16_t index = 0; 380 0 stevel 381 0 stevel line += sprintf(line, "0x"); 382 0 stevel 383 0 stevel while (index < length) { 384 0 stevel line += sprintf(line, "%02x", data[index++]); 385 0 stevel } 386 0 stevel } 387 0 stevel 388 0 stevel static void 389 0 stevel print_utf8string(char *firstline, char *string, uint16_t length) 390 0 stevel { 391 0 stevel (void) sprintf(firstline, "%.*s", length, string); 392 0 stevel } 393 0 stevel 394 0 stevel static char * 395 0 stevel print_linetag(char *string) 396 0 stevel { 397 0 stevel char *line = get_line(0, 0); 398 0 stevel return (line + sprintf(line, string)); 399 0 stevel } 400