diff options
author | Guy Harris <guy@alum.mit.edu> | 1999-10-13 06:47:49 +0000 |
---|---|---|
committer | Guy Harris <guy@alum.mit.edu> | 1999-10-13 06:47:49 +0000 |
commit | 93d58bf8242abd9026cecd2da313ac1de30d3fbe (patch) | |
tree | 5f38b50664f85709211104e3cca23e8f2d3174b5 /packet-pim.c | |
parent | 98ce0fcfabac47d81a2d3513b751b3174b6101f3 (diff) | |
download | wireshark-93d58bf8242abd9026cecd2da313ac1de30d3fbe.tar.gz wireshark-93d58bf8242abd9026cecd2da313ac1de30d3fbe.tar.bz2 wireshark-93d58bf8242abd9026cecd2da313ac1de30d3fbe.zip |
Jun-ichiro itojun Hagino's code for PIM, and some fixes from him as
well.
Add some more protocols to the list of value/string pairs for IP
protocol types.
svn path=/trunk/; revision=822
Diffstat (limited to 'packet-pim.c')
-rw-r--r-- | packet-pim.c | 559 |
1 files changed, 559 insertions, 0 deletions
diff --git a/packet-pim.c b/packet-pim.c new file mode 100644 index 0000000000..468717982e --- /dev/null +++ b/packet-pim.c @@ -0,0 +1,559 @@ +/* packet-pim.c + * Routines for PIM disassembly + * (c) Copyright Jun-ichiro itojun Hagino <itojun@itojun.org> + * + * $Id: packet-pim.c,v 1.1 1999/10/13 06:47:45 guy Exp $ + * + * Ethereal - Network traffic analyzer + * By Gerald Combs <gerald@zing.org> + * Copyright 1998 Gerald Combs + * + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +#include <glib.h> +#include "packet.h" +#include "packet-ipv6.h" + +#ifndef offsetof +#define offsetof(type, member) ((size_t)(&((type *)0)->member)) +#endif + +struct pim { + guint8 pim_typever; +#define PIM_TYPE(x) ((x) & 0x0f) +#define PIM_VER(x) (((x) & 0xf0) >> 4) + guint8 pim_rsv; /* Reserved */ + guint16 pim_cksum; /* IP style check sum */ +}; + +enum pimv2_addrtype { + pimv2_unicast, pimv2_group, pimv2_source +}; + +static int proto_pim = -1; + +static const char * +dissect_pim_addr(const u_char *bp, const u_char *ep, enum pimv2_addrtype at, + int *advance) { + static char buf[512]; + int af; + int len = 0; + + if (bp >= ep) + return NULL; + + switch (bp[0]) { + case 1: + af = 4; + break; + case 2: + af = 6; + break; + default: + return NULL; + } + + if (bp[1] != 0) + return NULL; + + switch (at) { + case pimv2_unicast: + if (af == 4) { + len = 4; + if (bp + 2 + len > ep) + return NULL; + (void)snprintf(buf, sizeof(buf), "%s", ip_to_str(bp + 2)); + } + else if (af == 6) { + len = 16; + if (bp + 2 + len > ep) + return NULL; + (void)snprintf(buf, sizeof(buf), "%s", + ip6_to_str((struct e_in6_addr *)(bp + 2))); + } + if (advance) + *advance = 2 + len; + break; + + case pimv2_group: + if (af == 4) { + len = 4; + if (bp + 4 + len > ep) + return NULL; + (void)snprintf(buf, sizeof(buf), "%s/%u", ip_to_str(bp + 4), bp[3]); + } + else if (af == 6) { + len = 16; + if (bp + 4 + len > ep) + return NULL; + (void)snprintf(buf, sizeof(buf), "%s/%u", + ip6_to_str((struct e_in6_addr *)(bp + 4)), bp[3]); + } + if (advance) + *advance = 4 + len; + break; + case pimv2_source: + if (af == 4) { + len = 4; + if (bp + 4 + len > ep) + return NULL; + (void)snprintf(buf, sizeof(buf), "%s/%u", ip_to_str(bp + 4), bp[3]); + } + else if (af == 6) { + len = 16; + if (bp + 4 + len > ep) + return NULL; + (void)snprintf(buf, sizeof(buf), "%s/%u", + ip6_to_str((struct e_in6_addr *)(bp + 4)), bp[3]); + } + if (bp[2]) { + (void)snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), + " (%s%s%s)", + bp[2] & 0x04 ? "S" : "", + bp[2] & 0x02 ? "W" : "", + bp[2] & 0x01 ? "R" : ""); + } + if (advance) + *advance = 4 + len; + break; + default: + return NULL; + } + + return buf; +} + +void +dissect_pim(const u_char *pd, int offset, frame_data *fd, proto_tree *tree) { + struct pim pim; + char *packet_type1[] = { + "Query", "Register", "Register-Stop", "Join/Prune", "RP-Reachable", + "Assert", "Graft", "Graft-Ack", "Mode" + }; + char *packet_type2[] = { + "Hello", "Register", "Register-Stop", "Join/Prune", "Bootstrap", + "Assert", "Graft", "Graft-Ack", "Candidate-RP-Advertisement" + }; + char *typestr; + proto_tree *pim_tree = NULL; + proto_item *ti; + proto_tree *pimopt_tree = NULL; + proto_item *tiopt; + + /* avoid alignment problem */ + memcpy(&pim, &pd[offset], sizeof(pim)); + + typestr = NULL; + switch (PIM_VER(pim.pim_typever)) { + case 1: + if (PIM_TYPE(pim.pim_typever) < sizeof(packet_type1) / sizeof(packet_type1[0])) { + typestr = packet_type1[PIM_TYPE(pim.pim_typever)]; + } + break; + case 2: + if (PIM_TYPE(pim.pim_typever) < sizeof(packet_type2) / sizeof(packet_type2[0])) { + typestr = packet_type2[PIM_TYPE(pim.pim_typever)]; + } + break; + } + + if (check_col(fd, COL_PROTOCOL)) { + col_add_fstr(fd, COL_PROTOCOL, "PIM version %d", + PIM_VER(pim.pim_typever)); + } + if (check_col(fd, COL_INFO)) { + if (typestr) + col_add_str(fd, COL_INFO, typestr); + else { + col_add_fstr(fd, COL_INFO, "unknown type %d", + PIM_TYPE(pim.pim_typever)); + } + } + + if (tree) { + ti = proto_tree_add_item(tree, proto_pim, offset, END_OF_FRAME, NULL); + pim_tree = proto_item_add_subtree(ti, ETT_PIM); + + proto_tree_add_text(pim_tree, offset, 1, + "Version: %d", PIM_VER(pim.pim_typever)); + if (typestr) { + proto_tree_add_text(pim_tree, offset, 1, + "Type: %d (%s)", PIM_TYPE(pim.pim_typever), typestr); + } else { + proto_tree_add_text(pim_tree, offset, 1, + "Type: %d (unknown)", PIM_TYPE(pim.pim_typever)); + } + + proto_tree_add_text(pim_tree, offset + offsetof(struct pim, pim_cksum), + sizeof(pim.pim_cksum), + "Checksum: 0x%04x", ntohs(pim.pim_cksum)); + + if (sizeof(struct pim) < END_OF_FRAME) { + tiopt = proto_tree_add_text(pim_tree, + offset + sizeof(struct pim), END_OF_FRAME, + "PIM parameters", PIM_TYPE(pim.pim_typever), typestr); + pimopt_tree = proto_item_add_subtree(tiopt, ETT_PIM); + } else + goto done; + + if (PIM_VER(pim.pim_typever) != 2) + goto done; + + /* version 2 decoder */ + switch (PIM_TYPE(pim.pim_typever)) { + case 0: /*hello*/ + { + guint16 *w; + w = (guint16 *)&pd[offset + sizeof(struct pim)]; + while ((guint8 *)w < &pd[offset + END_OF_FRAME]) { + if (ntohs(w[0]) == 1 && ntohs(w[1]) == 2 + && (guint8 *)&w[3] <= &pd[offset + END_OF_FRAME]) { + proto_tree_add_text(pimopt_tree, (guint8 *)w - pd, 6, + "Holdtime: %u%s", ntohs(w[2]), + ntohs(w[2]) == 0xffff ? " (infty)" : ""); + w += 3; + } else + break; + } + break; + } + + case 1: /* register */ + { + const guint8 *ip; + proto_tree *flag_tree = NULL; + proto_item *tiflag; + int flagoff; + + flagoff = offset + sizeof(struct pim); + tiflag = proto_tree_add_text(pimopt_tree, flagoff, 4, + "Flags: 0x%08x", ntohl(*(guint32 *)&pd[flagoff])); + flag_tree = proto_item_add_subtree(tiflag, ETT_PIM); + proto_tree_add_text(flag_tree, flagoff, 1, "%s", + decode_boolean_bitfield(pd[flagoff], 0x80000000, 32, + "Border", "Not border")); + proto_tree_add_text(flag_tree, flagoff, 1, "%s", + decode_boolean_bitfield(pd[flagoff], 0x40000000, 32, + "Null-Register", "Not Null-Register")); + + ip = &pd[flagoff + sizeof(guint32)]; + switch((*ip & 0xf0) >> 4) { + case 4: /* IPv4 */ + dissect_ip(pd, ip - pd, fd, pimopt_tree); + break; + case 6: /* IPv6 */ + dissect_ipv6(pd, ip - pd, fd, pimopt_tree); + break; + default: + proto_tree_add_text(pimopt_tree, + ip - pd, END_OF_FRAME, + "Unknown IP version %d", (*ip & 0xf0) >> 4); + break; + } + break; + } + + case 2: /* register-stop */ + { + int advance; + const guint8 *ep; + const char *s; + + ep = &pd[offset + END_OF_FRAME]; + offset += sizeof(struct pim); + s = dissect_pim_addr(&pd[offset], ep, pimv2_group, &advance); + if (s == NULL) + break; + proto_tree_add_text(pimopt_tree, offset, advance, "Group: %s", s); + offset += advance; + s = dissect_pim_addr(&pd[offset], ep, pimv2_unicast, &advance); + if (s == NULL) + break; + proto_tree_add_text(pimopt_tree, offset, advance, "Source: %s", s); + break; + } + + case 3: /* join/prune */ + case 6: /* graft */ + case 7: /* graft-ack */ + { + int advance; + const guint8 *ep; + int off; + const char *s; + int ngroup, i, njoin, nprune, j; + proto_tree *grouptree = NULL; + proto_item *tigroup; + proto_tree *subtree = NULL; + proto_item *tisub; + + ep = &pd[offset + END_OF_FRAME]; + offset += sizeof(struct pim); + if (PIM_TYPE(pim.pim_typever) != 7) { + /* not graft-ack */ + s = dissect_pim_addr(&pd[offset], ep, pimv2_unicast, &advance); + if (s == NULL) + break; + proto_tree_add_text(pimopt_tree, offset, advance, + "Upstream-neighbor: %s", s); + offset += advance; + } + + if (&pd[offset + 2] > ep) + break; + ngroup = pd[offset + 1]; + proto_tree_add_text(pimopt_tree, offset + 1, 1, + "Groups: %u", pd[offset + 1]); + offset += 2; + + if (&pd[offset + 2] > ep) + break; + if (PIM_TYPE(pim.pim_typever) != 7) { + /* not graft-ack */ + proto_tree_add_text(pimopt_tree, offset, 2, + "Holdtime: %u%s", ntohs(*(guint16 *)&pd[offset]), + ntohs(*(guint16 *)&pd[offset]) == 0xffff ? " (infty)" : ""); + } + offset += 2; + + for (i = 0; i < ngroup; i++) { + if (&pd[offset] >= ep) + goto breakbreak3; + + s = dissect_pim_addr(&pd[offset], ep, pimv2_group, &advance); + if (s == NULL) + goto breakbreak3; + tigroup = proto_tree_add_text(pimopt_tree, offset, advance, + "Group %d: %s", i, s); + grouptree = proto_item_add_subtree(tigroup, ETT_PIM); + offset += advance; + + if (&pd[offset + 4] > ep) + goto breakbreak3; + njoin = ntohs(*(guint16 *)&pd[offset]); + nprune = ntohs(*(guint16 *)&pd[offset + 2]); + + tisub = proto_tree_add_text(grouptree, offset, 2, + "Join: %d", njoin); + subtree = proto_item_add_subtree(tisub, ETT_PIM); + off = offset + 4; + for (j = 0; j < nprune; j++) { + s = dissect_pim_addr(&pd[off], ep, pimv2_source, + &advance); + if (s == NULL) + goto breakbreak3; + proto_tree_add_text(subtree, off, advance, + "IP address: %s", s); + off += advance; + } + + tisub = proto_tree_add_text(grouptree, offset + 2, 2, + "Prune: %d", nprune); + subtree = proto_item_add_subtree(tisub, ETT_PIM); + for (j = 0; j < nprune; j++) { + s = dissect_pim_addr(&pd[off], ep, pimv2_source, + &advance); + if (s == NULL) + goto breakbreak3; + proto_tree_add_text(subtree, off, advance, + "IP address: %s", s); + off += advance; + } + } + breakbreak3: + break; + } + + case 4: /* bootstrap */ + { + const char *s; + int advance; + int i, j; + int frpcnt; + proto_tree *grouptree = NULL; + proto_item *tigroup; + + offset += sizeof(struct pim); + + if (END_OF_FRAME < 2) + break; + proto_tree_add_text(pimopt_tree, offset, 2, + "Fragment tag: 0x%04x", ntohs(*(guint16 *)&pd[offset])); + offset += 2; + + if (END_OF_FRAME < 2) + break; + proto_tree_add_text(pimopt_tree, offset, 1, + "Hash mask len: %u", pd[offset]); + proto_tree_add_text(pimopt_tree, offset + 1, 1, + "BSR priority: %u", pd[offset + 1]); + offset += 2; + + s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME], + pimv2_unicast, &advance); + if (s == NULL) + break; + proto_tree_add_text(pimopt_tree, offset, advance, "BSR: %s", s); + offset += advance; + + for (i = 0; END_OF_FRAME > 0; i++) { + s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME], + pimv2_group, &advance); + if (s == NULL) + goto breakbreak4; + tigroup = proto_tree_add_text(pimopt_tree, offset, advance, + "Group %d: %s", i, s); + grouptree = proto_item_add_subtree(tigroup, ETT_PIM); + offset += advance; + + if (END_OF_FRAME < 2) + goto breakbreak4; + proto_tree_add_text(grouptree, offset, 1, + "RP count: %u", pd[offset]); + proto_tree_add_text(grouptree, offset + 1, 1, + "FRP count: %u", pd[offset + 1]); + frpcnt = pd[offset + 1]; + offset += 4; + + for (j = 0; j < frpcnt && END_OF_FRAME > 0; j++) { + s = dissect_pim_addr(&pd[offset], + &pd[offset + END_OF_FRAME], pimv2_unicast, &advance); + if (s == NULL) + goto breakbreak4; + proto_tree_add_text(grouptree, offset, advance, + "RP %d: %s", j, s); + offset += advance; + + if (END_OF_FRAME < 4) + goto breakbreak4; + proto_tree_add_text(grouptree, offset, 2, + "Holdtime: %u%s", ntohs(*(guint16 *)&pd[offset]), + ntohs(*(guint16 *)&pd[offset]) == 0xffff ? " (infty)" : ""); + proto_tree_add_text(grouptree, offset + 3, 1, + "Priority: %u", pd[offset + 3]); + + offset += 4; + } + } + + breakbreak4: + break; + } + + case 5: /* assert */ + { + const char *s; + int advance; + + offset += sizeof(struct pim); + + s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME], + pimv2_group, &advance); + if (s == NULL) + break; + proto_tree_add_text(pimopt_tree, offset, advance, "Group: %s", s); + offset += advance; + + s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME], + pimv2_unicast, &advance); + if (s == NULL) + break; + proto_tree_add_text(pimopt_tree, offset, advance, "Source: %s", s); + offset += advance; + + if (END_OF_FRAME < 4) + break; + proto_tree_add_text(pimopt_tree, offset, 1, "%s", + decode_boolean_bitfield(pd[offset], 0x80, 8, + "RP Tree", "Not RP Tree")); + proto_tree_add_text(pimopt_tree, offset, 4, "Preference: %u", + ntohl(*(guint32 *)&pd[offset] & 0x7fffffff)); + offset += 4; + + if (END_OF_FRAME < 4) + break; + proto_tree_add_text(pimopt_tree, offset, 4, "Metric: %u", + ntohl(*(guint32 *)&pd[offset])); + + break; + } + + case 8: /* Candidate-RP-Advertisement */ + { + const char *s; + int advance; + int pfxcnt; + int i; + + offset += sizeof(struct pim); + if (END_OF_FRAME < 4) + break; + pfxcnt = pd[offset]; + proto_tree_add_text(pimopt_tree, offset, 1, + "Prefix-count: %u", pd[offset]); + proto_tree_add_text(pimopt_tree, offset + 1, 1, + "Priority: %u", pd[offset + 1]); + proto_tree_add_text(pimopt_tree, offset + 2, 2, + "Holdtime: %u%s", ntohs(*(guint16 *)&pd[offset + 2]), + ntohs(*(guint16 *)&pd[offset + 2]) == 0xffff ? " (infty)" : ""); + offset += 4; + + if (END_OF_FRAME <= 0) + break; + s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME], + pimv2_unicast, &advance); + if (s == NULL) + break; + proto_tree_add_text(pimopt_tree, offset, advance, "RP: %s", s); + offset += advance; + + for (i = 0; i < pfxcnt && END_OF_FRAME > 0; i++) { + s = dissect_pim_addr(&pd[offset], &pd[offset + END_OF_FRAME], + pimv2_group, &advance); + if (s == NULL) + goto breakbreak8; + proto_tree_add_text(pimopt_tree, offset, advance, + "Group %d: %s", i, s); + offset += advance; + } + breakbreak8: + break; + } + + default: + break; + } + } +done:; +} + +void +proto_register_pim(void) +{ + proto_pim = proto_register_protocol("Protocol Independent Multicast", + "pim"); +} |