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