2 * Routines for IP and miscellaneous IP protocol packet disassembly
4 * $Id: packet-ip.c,v 1.17 1999/03/09 02:52:37 guy Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
8 * Copyright 1998 Gerald Combs
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
34 #ifdef HAVE_SYS_TYPES_H
35 # include <sys/types.h>
38 #ifdef HAVE_NETINET_IN_H
39 # include <netinet/in.h>
48 extern packet_info pi;
51 capture_ip(const u_char *pd, int offset, guint32 cap_len, packet_counts *ld) {
52 switch (pd[offset + 9]) {
68 dissect_ipopt_security(GtkWidget *opt_tree, const char *name,
69 const u_char *opd, int offset, guint optlen)
71 GtkWidget *field_tree = NULL, *tf;
73 static const value_string secl_vals[] = {
74 {IPSEC_UNCLASSIFIED, "Unclassified"},
75 {IPSEC_CONFIDENTIAL, "Confidential"},
76 {IPSEC_EFTO, "EFTO" },
77 {IPSEC_MMMM, "MMMM" },
78 {IPSEC_RESTRICTED, "Restricted" },
79 {IPSEC_SECRET, "Secret" },
80 {IPSEC_TOPSECRET, "Top secret" },
81 {IPSEC_RESERVED1, "Reserved" },
82 {IPSEC_RESERVED2, "Reserved" },
83 {IPSEC_RESERVED3, "Reserved" },
84 {IPSEC_RESERVED4, "Reserved" },
85 {IPSEC_RESERVED5, "Reserved" },
86 {IPSEC_RESERVED6, "Reserved" },
87 {IPSEC_RESERVED7, "Reserved" },
88 {IPSEC_RESERVED8, "Reserved" },
91 tf = add_item_to_tree(opt_tree, offset, optlen, "%s:", name);
92 field_tree = gtk_tree_new();
93 add_subtree(tf, field_tree, ETT_IP_OPTION_SEC);
97 add_item_to_tree(field_tree, offset, 2,
98 "Security: %s", val_to_str(val, secl_vals, "Unknown (0x%x)"));
103 add_item_to_tree(field_tree, offset, 2,
104 "Compartments: %d", val);
108 add_item_to_tree(field_tree, offset, 2,
109 "Handling restrictions: %c%c", opd[0], opd[1]);
113 add_item_to_tree(field_tree, offset, 3,
114 "Transmission control code: %c%c%c", opd[0], opd[1], opd[2]);
118 dissect_ipopt_route(GtkWidget *opt_tree, const char *name,
119 const u_char *opd, int offset, guint optlen)
121 GtkWidget *field_tree = NULL, *tf;
126 tf = add_item_to_tree(opt_tree, offset, optlen, "%s (%d bytes)", name,
128 field_tree = gtk_tree_new();
129 add_subtree(tf, field_tree, ETT_IP_OPTION_ROUTE);
131 optoffset += 2; /* skip past type and length */
132 optlen -= 2; /* subtract size of type and length */
135 add_item_to_tree(field_tree, offset + optoffset, 1,
136 "Pointer: %d%s", ptr,
137 ((ptr < 4) ? " (points before first address)" :
138 ((ptr & 3) ? " (points to middle of address)" : "")));
142 ptr--; /* ptr is 1-origin */
146 add_item_to_tree(field_tree, offset, optlen,
147 "(suboption would go past end of option)");
151 /* Avoids alignment problems on many architectures. */
152 memcpy((char *)&addr, (char *)opd, sizeof(addr));
154 add_item_to_tree(field_tree, offset + optoffset, 4,
156 ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
157 ((optoffset == ptr) ? " <- (current)" : ""));
165 dissect_ipopt_sid(GtkWidget *opt_tree, const char *name, const u_char *opd,
166 int offset, guint optlen)
168 add_item_to_tree(opt_tree, offset, optlen,
169 "%s: %d", name, pntohs(opd));
174 dissect_ipopt_timestamp(GtkWidget *opt_tree, const char *name, const u_char *opd,
175 int offset, guint optlen)
177 GtkWidget *field_tree = NULL, *tf;
181 static const value_string flag_vals[] = {
182 {IPOPT_TS_TSONLY, "Time stamps only" },
183 {IPOPT_TS_TSANDADDR, "Time stamp and address" },
184 {IPOPT_TS_PRESPEC, "Time stamps for prespecified addresses"},
190 tf = add_item_to_tree(opt_tree, offset, optlen, "%s:", name);
191 field_tree = gtk_tree_new();
192 add_subtree(tf, field_tree, ETT_IP_OPTION_TIMESTAMP);
194 optoffset += 2; /* skip past type and length */
195 optlen -= 2; /* subtract size of type and length */
198 add_item_to_tree(field_tree, offset + optoffset, 1,
199 "Pointer: %d%s", ptr,
200 ((ptr < 5) ? " (points before first address)" :
201 (((ptr - 1) & 3) ? " (points to middle of address)" : "")));
205 ptr--; /* ptr is 1-origin */
208 add_item_to_tree(field_tree, offset + optoffset, 1,
209 "Overflow: %d", flg >> 4);
211 add_item_to_tree(field_tree, offset + optoffset, 1,
212 "Flag: %s", val_to_str(flg, flag_vals, "Unknown (0x%x)"));
218 if (flg == IPOPT_TS_TSANDADDR) {
220 add_item_to_tree(field_tree, offset + optoffset, optlen,
221 "(suboption would go past end of option)");
224 /* XXX - check whether it goes past end of packet */
229 add_item_to_tree(field_tree, offset + optoffset, optlen,
230 "(suboption would go past end of option)");
233 /* XXX - check whether it goes past end of packet */
234 memcpy((char *)&addr, (char *)opd, sizeof(addr));
237 add_item_to_tree(field_tree, offset, 8,
238 "Address = %s, time stamp = %u",
239 ((addr.s_addr == 0) ? "-" : (char *)get_hostname(addr.s_addr)),
244 add_item_to_tree(field_tree, offset + optoffset, optlen,
245 "(suboption would go past end of option)");
248 /* XXX - check whether it goes past end of packet */
252 add_item_to_tree(field_tree, offset + optoffset, 4,
253 "Time stamp = %u", ts);
259 static ip_tcp_opt ipopts[] = {
279 dissect_ipopt_security
283 "Strict source route",
290 "Loose source route",
313 IPOLEN_TIMESTAMP_MIN,
314 dissect_ipopt_timestamp
318 #define N_IP_OPTS (sizeof ipopts / sizeof ipopts[0])
320 /* Dissect the IP or TCP options in a packet. */
322 dissect_ip_tcp_options(GtkWidget *opt_tree, const u_char *opd, int offset,
323 guint length, ip_tcp_opt *opttab, int nopts, int eol)
331 for (optp = &opttab[0]; optp < &opttab[nopts]; optp++) {
332 if (optp->optcode == opt)
335 if (optp == &opttab[nopts]) {
336 add_item_to_tree(opt_tree, offset, 1, "Unknown");
337 /* We don't know how long this option is, so we don't know how much
338 of it to skip, so we just bail. */
341 --length; /* account for type byte */
342 if (optp->len_type != NO_LENGTH) {
343 /* Option has a length. Is it in the packet? */
345 /* Bogus - packet must at least include option code byte and
347 add_item_to_tree(opt_tree, offset, 1,
348 "%s (length byte past end of header)", optp->name);
351 len = *opd++; /* total including type, len */
352 --length; /* account for length byte */
354 /* Bogus - option length is too short to include option code and
356 add_item_to_tree(opt_tree, offset, 2,
357 "%s (with too-short option length = %u bytes)", optp->name, 2);
359 } else if (len - 2 > length) {
360 /* Bogus - option goes past the end of the header. */
361 add_item_to_tree(opt_tree, offset, length,
362 "%s (option goes past end of header)", optp->name);
364 } else if (optp->len_type == FIXED_LENGTH && len != optp->optlen) {
365 /* Bogus - option length isn't what it's supposed to be for this
367 add_item_to_tree(opt_tree, offset, len,
368 "%s (with option length = %u bytes; should be %u)", optp->name,
371 } else if (optp->len_type == VARIABLE_LENGTH && len < optp->optlen) {
372 /* Bogus - option length is less than what it's supposed to be for
374 add_item_to_tree(opt_tree, offset, len,
375 "%s (with option length = %u bytes; should be >= %u)", optp->name,
379 if (optp->dissect != NULL) {
380 /* Option has a dissector. */
381 (*optp->dissect)(opt_tree, optp->name, opd, offset, len);
383 /* Option has no data, hence no dissector. */
384 add_item_to_tree(opt_tree, offset, len, "%s", optp->name);
386 len -= 2; /* subtract size of type and length */
392 add_item_to_tree(opt_tree, offset, 1, "%s", optp->name);
401 dissect_ip(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
403 GtkWidget *ip_tree, *ti, *field_tree, *tf;
406 static const value_string proto_vals[] = { {IP_PROTO_ICMP, "ICMP"},
407 {IP_PROTO_IGMP, "IGMP"},
408 {IP_PROTO_TCP, "TCP" },
409 {IP_PROTO_UDP, "UDP" },
410 {IP_PROTO_OSPF, "OSPF"},
412 static const value_string precedence_vals[] = {
413 { IPTOS_PREC_ROUTINE, "routine" },
414 { IPTOS_PREC_PRIORITY, "priority" },
415 { IPTOS_PREC_IMMEDIATE, "immediate" },
416 { IPTOS_PREC_FLASH, "flash" },
417 { IPTOS_PREC_FLASHOVERRIDE, "flash override" },
418 { IPTOS_PREC_CRITIC_ECP, "CRITIC/ECP" },
419 { IPTOS_PREC_INTERNETCONTROL, "internetwork control" },
420 { IPTOS_PREC_NETCONTROL, "network control" },
423 /* To do: check for runts, errs, etc. */
424 /* Avoids alignment problems on many architectures. */
425 memcpy(&iph, &pd[offset], sizeof(e_ip));
426 iph.ip_len = ntohs(iph.ip_len);
427 iph.ip_id = ntohs(iph.ip_id);
428 iph.ip_off = ntohs(iph.ip_off);
429 iph.ip_sum = ntohs(iph.ip_sum);
431 hlen = lo_nibble(iph.ip_v_hl) * 4; /* IP header length, in bytes */
439 /* Names are set in the associated dissect_* routines */
442 if (check_col(fd, COL_PROTOCOL))
443 col_add_str(fd, COL_PROTOCOL, "IP");
444 if (check_col(fd, COL_INFO))
445 col_add_fstr(fd, COL_INFO, "Unknown IP protocol (%02x)", iph.ip_p);
448 if (check_col(fd, COL_RES_NET_SRC))
449 col_add_str(fd, COL_RES_NET_SRC, get_hostname(iph.ip_src));
450 if (check_col(fd, COL_UNRES_NET_SRC))
451 col_add_str(fd, COL_UNRES_NET_SRC, ip_to_str((guint8 *) &iph.ip_src));
452 if (check_col(fd, COL_RES_NET_DST))
453 col_add_str(fd, COL_RES_NET_DST, get_hostname(iph.ip_dst));
454 if (check_col(fd, COL_UNRES_NET_DST))
455 col_add_str(fd, COL_UNRES_NET_DST, ip_to_str((guint8 *) &iph.ip_dst));
457 iph.ip_tos = IPTOS_TOS(iph.ip_tos);
458 switch (iph.ip_tos) {
460 strcpy(tos_str, "None");
463 strcpy(tos_str, "Minimize cost");
465 case IPTOS_RELIABILITY:
466 strcpy(tos_str, "Maximize reliability");
468 case IPTOS_THROUGHPUT:
469 strcpy(tos_str, "Maximize throughput");
472 strcpy(tos_str, "Minimize delay");
475 strcpy(tos_str, "Maximize security");
478 strcpy(tos_str, "Unknown. Malformed?");
483 ti = add_item_to_tree(GTK_WIDGET(tree), offset, hlen, "Internet Protocol");
484 ip_tree = gtk_tree_new();
485 add_subtree(ti, ip_tree, ETT_IP);
486 add_item_to_tree(ip_tree, offset, 1, "Version: %d", hi_nibble(iph.ip_v_hl));
487 add_item_to_tree(ip_tree, offset, 1, "Header length: %d bytes", hlen);
488 tf = add_item_to_tree(ip_tree, offset + 1, 1, "Type of service: 0x%02x (%s)",
489 iph.ip_tos, tos_str);
490 field_tree = gtk_tree_new();
491 add_subtree(tf, field_tree, ETT_IP_TOS);
492 add_item_to_tree(field_tree, offset + 1, 1, "%s",
493 decode_enumerated_bitfield(iph.ip_tos, IPTOS_PREC_MASK,
494 sizeof (iph.ip_tos)*8, precedence_vals,
496 add_item_to_tree(field_tree, offset + 1, 1, "%s",
497 decode_boolean_bitfield(iph.ip_tos, IPTOS_LOWDELAY,
498 sizeof (iph.ip_tos)*8, "low delay", "normal delay"));
499 add_item_to_tree(field_tree, offset + 1, 1, "%s",
500 decode_boolean_bitfield(iph.ip_tos, IPTOS_THROUGHPUT,
501 sizeof (iph.ip_tos)*8, "high throughput", "normal throughput"));
502 add_item_to_tree(field_tree, offset + 1, 1, "%s",
503 decode_boolean_bitfield(iph.ip_tos, IPTOS_RELIABILITY,
504 sizeof (iph.ip_tos)*8, "high reliability", "normal reliability"));
505 add_item_to_tree(field_tree, offset + 1, 1, "%s",
506 decode_boolean_bitfield(iph.ip_tos, IPTOS_LOWCOST,
507 sizeof (iph.ip_tos)*8, "low cost", "normal cost"));
508 add_item_to_tree(ip_tree, offset + 2, 2, "Total length: %d", iph.ip_len);
509 add_item_to_tree(ip_tree, offset + 4, 2, "Identification: 0x%04x",
511 tf = add_item_to_tree(ip_tree, offset + 6, 2, "Flags: 0x%x",
512 (iph.ip_off & (IP_DF|IP_MF)) >> 12);
513 field_tree = gtk_tree_new();
514 add_subtree(tf, field_tree, ETT_IP_OFF);
515 add_item_to_tree(field_tree, offset + 6, 2, "%s",
516 decode_boolean_bitfield(iph.ip_off >> 8, IP_DF >> 8, 8, "don't fragment",
518 add_item_to_tree(field_tree, offset + 6, 2, "%s",
519 decode_boolean_bitfield(iph.ip_off >> 8, IP_MF >> 8, 8, "more fragments",
521 add_item_to_tree(ip_tree, offset + 6, 2, "Fragment offset: %d",
522 iph.ip_off & IP_OFFSET);
523 add_item_to_tree(ip_tree, offset + 8, 1, "Time to live: %d",
525 add_item_to_tree(ip_tree, offset + 9, 1, "Protocol: %s",
526 val_to_str(iph.ip_p, proto_vals, "Unknown (%x)"));
527 add_item_to_tree(ip_tree, offset + 10, 2, "Header checksum: 0x%04x",
529 add_item_to_tree(ip_tree, offset + 12, 4, "Source address: %s (%s)",
530 get_hostname(iph.ip_src),
531 ip_to_str((guint8 *) &iph.ip_src));
532 add_item_to_tree(ip_tree, offset + 16, 4, "Destination address: %s (%s)",
533 get_hostname(iph.ip_dst),
534 ip_to_str((guint8 *) &iph.ip_dst));
536 /* Decode IP options, if any. */
537 if (hlen > sizeof (e_ip)) {
538 /* There's more than just the fixed-length header. Decode the
540 optlen = hlen - sizeof (e_ip); /* length of options, in bytes */
541 tf = add_item_to_tree(ip_tree, offset + 20, optlen,
542 "Options: (%d bytes)", optlen);
543 field_tree = gtk_tree_new();
544 add_subtree(tf, field_tree, ETT_IP_OPTIONS);
545 dissect_ip_tcp_options(field_tree, &pd[offset + 20], offset + 20, optlen,
546 ipopts, N_IP_OPTS, IPOPT_END);
550 pi.srcip = ip_to_str( (guint8 *) &iph.ip_src);
551 pi.destip = ip_to_str( (guint8 *) &iph.ip_dst);
552 pi.ipproto = iph.ip_p;
553 pi.iplen = iph.ip_len;
554 pi.iphdrlen = lo_nibble(iph.ip_v_hl);
555 pi.ip_src = iph.ip_src;
560 dissect_icmp(pd, offset, fd, tree);
563 dissect_igmp(pd, offset, fd, tree);
566 dissect_tcp(pd, offset, fd, tree);
569 dissect_udp(pd, offset, fd, tree);
572 dissect_ospf(pd, offset, fd, tree);
578 static const gchar *unreach_str[] = {"Network unreachable",
580 "Protocol unreachable",
582 "Fragmentation needed",
583 "Source route failed",
584 "Administratively prohibited",
585 "Network unreachable for TOS",
586 "Host unreachable for TOS",
587 "Communication administratively filtered",
588 "Host precedence violation",
589 "Precedence cutoff in effect"};
591 #define N_UNREACH (sizeof unreach_str / sizeof unreach_str[0])
593 static const gchar *redir_str[] = {"Redirect for network",
595 "Redirect for TOS and network",
596 "Redirect for TOS and host"};
598 #define N_REDIRECT (sizeof redir_str / sizeof redir_str[0])
600 static const gchar *ttl_str[] = {"TTL equals 0 during transit",
601 "TTL equals 0 during reassembly"};
603 #define N_TIMXCEED (sizeof ttl_str / sizeof ttl_str[0])
605 static const gchar *par_str[] = {"IP header bad", "Required option missing"};
607 #define N_PARAMPROB (sizeof par_str / sizeof par_str[0])
610 dissect_icmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
612 GtkWidget *icmp_tree, *ti;
614 gchar type_str[64], code_str[64] = "";
616 /* Avoids alignment problems on many architectures. */
617 memcpy(&ih, &pd[offset], sizeof(e_icmp));
618 /* To do: check for runts, errs, etc. */
619 cksum = ntohs(ih.icmp_cksum);
621 switch (ih.icmp_type) {
623 strcpy(type_str, "Echo (ping) reply");
626 strcpy(type_str, "Destination unreachable");
627 if (ih.icmp_code < N_UNREACH) {
628 sprintf(code_str, "(%s)", unreach_str[ih.icmp_code]);
630 strcpy(code_str, "(Unknown - error?)");
633 case ICMP_SOURCEQUENCH:
634 strcpy(type_str, "Source quench (flow control)");
637 strcpy(type_str, "Redirect");
638 if (ih.icmp_code < N_REDIRECT) {
639 sprintf(code_str, "(%s)", redir_str[ih.icmp_code]);
641 strcpy(code_str, "(Unknown - error?)");
645 strcpy(type_str, "Echo (ping) request");
648 strcpy(type_str, "Time-to-live exceeded");
649 if (ih.icmp_code < N_TIMXCEED) {
650 sprintf(code_str, "(%s)", ttl_str[ih.icmp_code]);
652 strcpy(code_str, "(Unknown - error?)");
656 strcpy(type_str, "Parameter problem");
657 if (ih.icmp_code < N_PARAMPROB) {
658 sprintf(code_str, "(%s)", par_str[ih.icmp_code]);
660 strcpy(code_str, "(Unknown - error?)");
664 strcpy(type_str, "Timestamp request");
666 case ICMP_TSTAMPREPLY:
667 strcpy(type_str, "Timestamp reply");
670 strcpy(type_str, "Information request");
673 strcpy(type_str, "Information reply");
676 strcpy(type_str, "Address mask request");
679 strcpy(type_str, "Address mask reply");
682 strcpy(type_str, "Unknown ICMP (obsolete or malformed?)");
685 if (check_col(fd, COL_PROTOCOL))
686 col_add_str(fd, COL_PROTOCOL, "ICMP");
687 if (check_col(fd, COL_INFO))
688 col_add_str(fd, COL_INFO, type_str);
691 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
692 "Internet Control Message Protocol");
693 icmp_tree = gtk_tree_new();
694 add_subtree(ti, icmp_tree, ETT_ICMP);
695 add_item_to_tree(icmp_tree, offset, 1, "Type: %d (%s)",
696 ih.icmp_type, type_str);
697 add_item_to_tree(icmp_tree, offset + 1, 1, "Code: %d %s",
698 ih.icmp_code, code_str);
699 add_item_to_tree(icmp_tree, offset + 2, 2, "Checksum: 0x%04x",
702 /* Decode the second 4 byte of the packet. */
703 switch (ih.icmp_type) {
707 case ICMP_TSTAMPREPLY:
712 add_item_to_tree(icmp_tree, offset + 4, 2, "Identifier: 0x%04x",
713 pntohs(&pd[offset + 4]));
714 add_item_to_tree(icmp_tree, offset + 6, 2, "Sequence number: %u",
715 pntohs(&pd[offset + 6]));
719 add_item_to_tree(icmp_tree, offset + 4, 1, "Pointer: %u",
724 add_item_to_tree(icmp_tree, offset + 4, 4, "Gateway address: %s",
725 ip_to_str((guint8 *)&pd[offset + 4]));
729 /* Decode the additional information in the packet. */
730 switch (ih.icmp_type) {
734 case ICMP_SOURCEQUENCH:
736 /* Decode the IP header and first 64 bits of data from the
739 XXX - for now, just display it as data; not all dissection
740 routines can handle a short packet without exploding. */
741 dissect_data(pd, offset + 8, fd, (GtkTree *)icmp_tree);
746 dissect_data(pd, offset + 8, fd, (GtkTree *)icmp_tree);
750 case ICMP_TSTAMPREPLY:
751 add_item_to_tree(icmp_tree, offset + 8, 4, "Originate timestamp: %u",
752 pntohl(&pd[offset + 8]));
753 add_item_to_tree(icmp_tree, offset + 12, 4, "Originate timestamp: %u",
754 pntohl(&pd[offset + 12]));
755 add_item_to_tree(icmp_tree, offset + 16, 4, "Receive timestamp: %u",
756 pntohl(&pd[offset + 16]));
757 add_item_to_tree(icmp_tree, offset + 20, 4, "Transmit timestamp: %u",
758 pntohl(&pd[offset + 20]));
763 add_item_to_tree(icmp_tree, offset + 8, 4, "Address mask: %s (0x%8x)",
764 ip_to_str((guint8 *)&pd[offset + 8]), pntohl(&pd[offset + 8]));
771 dissect_igmp(const u_char *pd, int offset, frame_data *fd, GtkTree *tree) {
773 GtkWidget *igmp_tree, *ti;
775 gchar type_str[64] = "";
777 /* Avoids alignment problems on many architectures. */
778 memcpy(&ih, &pd[offset], sizeof(e_igmp));
779 /* To do: check for runts, errs, etc. */
780 cksum = ntohs(ih.igmp_cksum);
782 switch (lo_nibble(ih.igmp_v_t)) {
784 strcpy(type_str, "Router query");
787 strcpy(type_str, "Host response (v1)");
790 strcpy(type_str, "Leave group (v2)");
793 strcpy(type_str, "DVMRP");
796 strcpy(type_str, "PIM");
799 strcpy(type_str, "Host reponse (v2)");
802 strcpy(type_str, "Traceroute response");
805 strcpy(type_str, "Traceroute message");
808 strcpy(type_str, "Unknown IGMP");
811 if (check_col(fd, COL_PROTOCOL))
812 col_add_str(fd, COL_PROTOCOL, "IGMP");
813 if (check_col(fd, COL_INFO))
814 col_add_str(fd, COL_INFO, type_str);
817 ti = add_item_to_tree(GTK_WIDGET(tree), offset, 4,
818 "Internet Group Management Protocol");
819 igmp_tree = gtk_tree_new();
820 add_subtree(ti, igmp_tree, ETT_IGMP);
821 add_item_to_tree(igmp_tree, offset, 1, "Version: %d",
822 hi_nibble(ih.igmp_v_t));
823 add_item_to_tree(igmp_tree, offset , 1, "Type: %d (%s)",
824 lo_nibble(ih.igmp_v_t), type_str);
825 add_item_to_tree(igmp_tree, offset + 1, 1, "Unused: 0x%02x",
827 add_item_to_tree(igmp_tree, offset + 2, 2, "Checksum: 0x%04x",
829 add_item_to_tree(igmp_tree, offset + 4, 4, "Group address: %s",
830 ip_to_str((guint8 *) &ih.igmp_gaddr));