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 2005 Sun Microsystems, Inc. All rights reserved.
24 * Copyright 2012 David Hoeppner. All rights reserved.
25 */
26
27 #include <stdio.h>
28 #include <ctype.h>
29 #include <string.h>
30 #include <fcntl.h>
31 #include <string.h>
32 #include <sys/types.h>
33 #include <sys/time.h>
34
35 #include <sys/socket.h>
36 #include <sys/sockio.h>
37 #include <net/if.h>
38 #include <netinet/in_systm.h>
39 #include <netinet/in.h>
40 #include <netinet/ip.h>
41 #include <netinet/if_ether.h>
42 #include <netinet/dccp.h>
43 #include "snoop.h"
44
45 /*
46 * Snoop interpreter for DCCP (RFC4340)
47 *
48 */
49
50 extern char *dlc_header;
51
52 static char *get_type(uint8_t);
53 static void print_dccpoptions_summary(uchar_t *, uchar_t *);
54 static void print_dccpoptions(uchar_t *, uchar_t *);
55
56 static char *
57 get_type(uint8_t type)
58 {
59 switch (type) {
60 case 0:
61 return ("DCCP-Request");
62 case 1:
63 return ("DCCP-Response");
64 case 2:
65 return ("DCCP-Data");
66 case 3:
67 return ("DCCP-Ack");
68 case 4:
69 return ("DCCP-DataAck");
70 case 5:
71 return ("DCCP-CloseReq");
72 case 6:
73 return ("DCCP-Close");
74 case 7:
75 return ("DCCP-Reset");
76 case 8:
77 return ("DCCP-Sync");
78 case 9:
79 return ("DCCP-SyncAck");
80 case 10 ... 15:
81 return ("Reserved");
82
83 default:
84 return ("Unknown");
85 }
86 }
87
88 int
89 interpret_dccp(int flags, struct dccphdr *dccp, int iplen, int fraglen)
90 {
91 char *data;
92 char *line;
93 char *endline;
94 uint64_t seq;
95 uint64_t ack;
96 int hdrlen;
97 int dccplen;
98 int option_offset;
99 int i;
100
101 hdrlen = dccp->dh_offset * 4;
102 data = (char *)dccp + hdrlen;
103 dccplen = iplen - hdrlen;
104 fraglen -= hdrlen;
105
106 if (fraglen < 0) {
107 return (fraglen + hdrlen); /* Incomplete header */
108 }
109
110 if (fraglen > dccplen) {
111 fraglen = dccplen;
112 }
113
114 if (dccp->dh_x == 1) {
115 switch (dccp->dh_type) {
116 case 0: /* DCCP-Request */
117 option_offset = 20;
118 break;
119 case 1: /* DCCP-Response */
120 option_offset = 28;
121 break;
122 case 7: /* DCCP-Reset */
123 option_offset = 28;
124 break;
125 case 8: /* DCCP-Sync */
126 case 9: /* DCCP-SyncAck */
127 option_offset = 24;
128 break;
129
130 default:
131 option_offset = 20;
132 break;
133 }
134
135 /* Sequence number */
136 seq = ntohs(dccp->dh_seq);
137 seq <<= 32;
138 seq += (uint32_t)dccp + sizeof (struct dccphdr);
139
140 ack = (uint32_t)(dccp + 16) & 0xffff;
141 } else {
142 switch (dccp->dh_type) {
143 case 0: /* DCCP-Request */
144 case 1: /* DCCP-Response */
145 case 7: /* DCCP-Reset */
146 case 8: /* DCCP-Sync */
147 case 9: /* DCCP-SyncAck */
148 break;
149
150 default:
151 option_offset = 20;
152 break;
153 }
154
155 /* Sequence number */
156 seq = dccp->dh_res_seq << 16;
157 seq |= ntohs(dccp->dh_seq);
158 }
159
160 if (flags & F_SUM) {
161 line = get_sum_line();
162 endline = line + MAXLINE;
163
164 (void) snprintf(line, endline - line, "DCCP D=%d S=%d",
165 ntohs(dccp->dh_dport), ntohs(dccp->dh_sport));
166 line += strlen(line);
167
168 (void) snprintf(line, endline - line, "CCval=%d CsCov=%d",
169 dccp->dh_ccval, dccp->dh_cscov);
170
171 (void) snprintf(line, endline - line, " Seq=%u Len=%d",
172 seq, dccplen);
173 line += strlen(line);
174
175 /*
176 * All packets except DCCP-Request and DCCP-Data carry
177 * an acknowledgement number.
178 */
179 if (dccp->dh_type != 0 && dccp->dh_type != 2) {
180 (void) snprintf(line, endline - line, " Ack=%u",
181 seq, dccplen);
182 }
183 line += strlen(line);
184
185 print_dccpoptions_summary((uchar_t *)dccp + option_offset,
186 (uchar_t *)dccp + dccp->dh_offset * 4);
187 }
188
189
190 if (flags & F_DTAIL) {
191 show_header("DCCP: ", "DCCP Header", dccplen);
192 show_space();
193
194 (void) sprintf(get_line((char *)(uintptr_t)dccp->dh_sport -
195 dlc_header, 2), "Source port = %d",
196 ntohs(dccp->dh_sport));
197
198 (void) sprintf(get_line((char *)(uintptr_t)dccp->dh_dport -
199 dlc_header, 2), "Destination port = %d",
200 ntohs(dccp->dh_dport));
201
202 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_offset -
203 dlc_header) + 4, 1), "Data offset = %d bytes",
204 dccp->dh_offset * 4);
205
206 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_ccval -
207 dlc_header) + 4, 1), "CCVal = %d",
208 dccp->dh_ccval);
209
210 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_cscov -
211 dlc_header) + 4, 1), "Checksum coverage (CsCov) = %d",
212 dccp->dh_cscov);
213
214 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_sum -
215 dlc_header) + 4, 1), "Checksum = 0x%04x",
216 ntohs(dccp->dh_sum));
217
218 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_type -
219 dlc_header) + 4, 1), "Type = %d (%s)",
220 dccp->dh_type, get_type(dccp->dh_type));
221
222 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_x -
223 dlc_header) + 4, 1), "Extended sequence numbers = %d",
224 dccp->dh_x);
225
226 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_seq -
227 dlc_header) + 4, 1), "Sequence number = %d",
228 seq);
229
230 /*
231 * All packets except DCCP-Request and DCCP-Data carry
232 * an acknowledgement number.
233 */
234 if (dccp->dh_type != 0 && dccp->dh_type != 2) {
235 (void) sprintf(get_line(((char *)(uintptr_t)dccp->dh_seq -
236 dlc_header) + 4, 1), "Acknowledgement number = %d",
237 seq);
238 }
239
240 print_dccpoptions((uchar_t *)dccp + option_offset,
241 (uchar_t *)dccp + dccp->dh_offset * 4);
242
243 show_space();
244 }
245
246 return (dccplen);
247 }
248
249 static void
250 print_dccpoptions_summary(uchar_t *up, uchar_t *end)
251 {
252 uchar_t *value;
253 uint8_t option_type;
254 uint8_t option_length;
255 int len;
256 boolean_t mandatory = B_FALSE;
257
258 while (up != end) {
259 option_length = 0;
260 option_type = *up++;
261
262 /*
263 * Is this a variable length option?
264 */
265 if (option_type > 31) {
266 option_length = *up++;
267 option_length -= 2;
268 value = up;
269
270 up += option_length;
271 }
272 switch (option_type) {
273 case 0: /* Padding */
274 break;
275 case 1: /* Mandatory */
276 mandatory = B_TRUE;
277 break;
278 case 2: /* Slow receiver */
279 break;
280 case 3 ... 31: /* Reserved */
281 break;
282 case 32: /* Change L */
283 break;
284 case 33: /* Confirm L */
285 break;
286 case 34: /* Change R */
287 break;
288 case 35: /* Confirm R */
289 break;
290 case 36: /* Init cookie */
291 break;
292 case 37: /* NDP count */
293 break;
294 case 38: /* Ack Vector 0 */
295 break;
296 case 39: /* Ack vector 1 */
297 break;
298 case 40: /* Data dropped */
299 break;
300 case 41: /* Timestamp */
301 break;
302 case 42: /* Timestamp echo */
303 break;
304 case 43: /* Elapsed time */
305 break;
306 case 44: /* Data checksum */
307 break;
308
309 default:
310 break;
311 }
312
313 if (option_type != 1) {
314 mandatory = B_FALSE;
315 }
316 }
317 }
318
319 static void
320 print_dccpoptions(uchar_t *up, uchar_t *end)
321 {
322 uchar_t *value;
323 uint8_t option_type;
324 uint8_t option_length;
325 int len;
326 boolean_t mandatory = B_FALSE;
327
328 if (up == end) {
329 (void) sprintf(get_line((char *)&up - dlc_header, 1),
330 "No options");
331 return;
332 }
333
334 (void) sprintf(get_line((char *)&up - dlc_header, 1),
335 "Options: (%d bytes)", (int)(end - up));
336
337 while (up != end) {
338 option_length = 0;
339 option_type = *up++;
340
341 /*
342 * Is this a variable length option?
343 */
344 if (option_type > 31) {
345 option_length = *up++;
346 option_length -= 2;
347 value = up;
348
349 up += option_length;
350 }
351
352 switch (option_type) {
353 case 0: /* Padding */
354 (void) sprintf(get_line(((char *)(uintptr_t)up -
355 dlc_header) + 4, 1), "Padding");
356 break;
357 case 1: /* Mandatory */
358 (void) sprintf(get_line(((char *)(uintptr_t)up -
359 dlc_header) + 4, 1), "Mandatory");
360 mandatory = B_TRUE;
361 break;
362 case 2: /* Slow receiver */
363 (void) sprintf(get_line(((char *)(uintptr_t)up -
364 dlc_header) + 4, 1), "Slow receiver");
365 break;
366 case 3 ... 31: /* Reserved */
367 (void) sprintf(get_line(((char *)(uintptr_t)up -
368 dlc_header) + 4, 1), "Reserved");
369 break;
370 case 32: /* Change L */
371 (void) sprintf(get_line(((char *)(uintptr_t)up -
372 dlc_header) + 4, 1), "Change L");
373 break;
374 case 33: /* Confirm L */
375 (void) sprintf(get_line(((char *)(uintptr_t)up -
376 dlc_header) + 4, 1), "Confirm L");
377 break;
378 case 34: /* Change R */
379 (void) sprintf(get_line(((char *)(uintptr_t)up -
380 dlc_header) + 4, 1), "Change R");
381 break;
382 case 35: /* Confirm R */
383 (void) sprintf(get_line(((char *)(uintptr_t)up -
384 dlc_header) + 4, 1), "Confirm R");
385 break;
386 case 36: /* Init cookie */
387 (void) sprintf(get_line(((char *)(uintptr_t)up -
388 dlc_header) + 4, 1), "Init cookie");
389 break;
390 case 37: /* NDP count */
391 (void) sprintf(get_line(((char *)(uintptr_t)up -
392 dlc_header) + 4, 1), "NDP count");
393 break;
394 case 38: /* Ack vector 0 */
395 (void) sprintf(get_line(((char *)(uintptr_t)up -
396 dlc_header) + 4, 1), "Ack vector 0");
397 break;
398 case 39: /* Ack vector 1 */
399 (void) sprintf(get_line(((char *)(uintptr_t)up -
400 dlc_header) + 4, 1), "Ack vector 1");
401 break;
402 case 40: /* Data dropped */
403 (void) sprintf(get_line(((char *)(uintptr_t)up -
404 dlc_header) + 4, 1), "Data dropped");
405 break;
406 case 41: /* Timestamp */
407 (void) sprintf(get_line(((char *)(uintptr_t)up -
408 dlc_header) + 4, 1), "Timestamp");
409 break;
410 case 42: /* Timestamp echo */
411 (void) sprintf(get_line(((char *)(uintptr_t)up -
412 dlc_header) + 4, 1), "TImestamp echo");
413 break;
414 case 43: /* Elapsed time */
415 (void) sprintf(get_line(((char *)(uintptr_t)up -
416 dlc_header) + 4, 1), "Elapsed time");
417 break;
418 case 44: /* Data checksum */
419 (void) sprintf(get_line(((char *)(uintptr_t)up -
420 dlc_header) + 4, 1), "Data checksum");
421 break;
422
423 default:
424 (void) sprintf(get_line(((char *)(uintptr_t)up -
425 dlc_header) + 4, 1), "Unknown");
426 break;
427 }
428
429 if (option_type != 1) {
430 mandatory = B_FALSE;
431 }
432 }
433 }