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