2 * Routines for ppp packet disassembly
4 * $Id: packet-ppp.c,v 1.37 2000/06/15 03:48:42 gram Exp $
6 * Ethereal - Network traffic analyzer
7 * By Gerald Combs <gerald@zing.org>
9 * This file created and by Mike Hall <mlh@io.com>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
37 #include "packet-ppp.h"
39 #include "packet-atalk.h"
40 #include "packet-ip.h"
41 #include "packet-ipv6.h"
42 #include "packet-ipx.h"
43 #include "packet-vines.h"
45 static int proto_ppp = -1;
47 static gint ett_ppp = -1;
48 static gint ett_ipcp = -1;
49 static gint ett_ipcp_options = -1;
50 static gint ett_ipcp_ipaddrs_opt = -1;
51 static gint ett_ipcp_compressprot_opt = -1;
52 static gint ett_lcp = -1;
53 static gint ett_lcp_options = -1;
54 static gint ett_lcp_mru_opt = -1;
55 static gint ett_lcp_async_map_opt = -1;
56 static gint ett_lcp_authprot_opt = -1;
57 static gint ett_lcp_qualprot_opt = -1;
58 static gint ett_lcp_magicnum_opt = -1;
59 static gint ett_lcp_fcs_alternatives_opt = -1;
60 static gint ett_lcp_numbered_mode_opt = -1;
61 static gint ett_lcp_callback_opt = -1;
62 static gint ett_lcp_multilink_ep_disc_opt = -1;
63 static gint ett_lcp_internationalization_opt = -1;
65 static dissector_table_t subdissector_table;
67 static int proto_mp = -1;
68 static int hf_mp_frag_first = -1;
69 static int hf_mp_frag_last = -1;
70 static int hf_mp_sequence_num = -1;
72 static int ett_mp = -1;
73 static int ett_mp_flags = -1;
75 /* PPP structs and definitions */
77 typedef struct _e_ppphdr {
83 static const value_string ppp_vals[] = {
85 {PPP_AT, "Appletalk" },
86 {PPP_IPX, "Netware IPX/SPX"},
87 {PPP_VJC_COMP, "VJ compressed TCP"},
88 {PPP_VJC_UNCOMP,"VJ uncompressed TCP"},
89 {PPP_VINES, "Vines" },
90 {PPP_MP, "Multilink"},
92 {PPP_COMP, "compressed packet" },
93 {PPP_IPCP, "IP Control Protocol" },
94 {PPP_ATCP, "AppleTalk Control Protocol" },
95 {PPP_IPXCP, "IPX Control Protocol" },
96 {PPP_CCP, "Compression Control Protocol" },
97 {PPP_LCP, "Link Control Protocol" },
98 {PPP_PAP, "Password Authentication Protocol" },
99 {PPP_LQR, "Link Quality Report protocol" },
100 {PPP_CHAP, "Cryptographic Handshake Auth. Protocol" },
101 {PPP_CBCP, "Callback Control Protocol" },
105 /* CP (LCP, IPCP, etc.) codes.
108 #define CONFREQ 1 /* Configuration Request */
109 #define CONFACK 2 /* Configuration Ack */
110 #define CONFNAK 3 /* Configuration Nak */
111 #define CONFREJ 4 /* Configuration Reject */
112 #define TERMREQ 5 /* Termination Request */
113 #define TERMACK 6 /* Termination Ack */
114 #define CODEREJ 7 /* Code Reject */
116 static const value_string cp_vals[] = {
117 {CONFREQ, "Configuration Request" },
118 {CONFACK, "Configuration Ack" },
119 {CONFNAK, "Configuration Nak" },
120 {CONFREJ, "Configuration Reject" },
121 {TERMREQ, "Termination Request" },
122 {TERMACK, "Termination Ack" },
123 {CODEREJ, "Code Reject" },
127 * LCP-specific packet types.
129 #define PROTREJ 8 /* Protocol Reject */
130 #define ECHOREQ 9 /* Echo Request */
131 #define ECHOREP 10 /* Echo Reply */
132 #define DISCREQ 11 /* Discard Request */
133 #define IDENT 12 /* Identification */
134 #define TIMEREMAIN 13 /* Time remaining */
136 #define CBCP_OPT 6 /* Use callback control protocol */
138 static const value_string lcp_vals[] = {
139 {CONFREQ, "Configuration Request" },
140 {CONFACK, "Configuration Ack" },
141 {CONFNAK, "Configuration Nak" },
142 {CONFREJ, "Configuration Reject" },
143 {TERMREQ, "Termination Request" },
144 {TERMACK, "Termination Ack" },
145 {CODEREJ, "Code Reject" },
146 {PROTREJ, "Protocol Reject" },
147 {ECHOREQ, "Echo Request" },
148 {ECHOREP, "Echo Reply" },
149 {DISCREQ, "Discard Request" },
150 {IDENT, "Identification" },
151 {TIMEREMAIN, "Time Remaining" },
158 #define CI_MRU 1 /* Maximum Receive Unit */
159 #define CI_ASYNCMAP 2 /* Async Control Character Map */
160 #define CI_AUTHTYPE 3 /* Authentication Type */
161 #define CI_QUALITY 4 /* Quality Protocol */
162 #define CI_MAGICNUMBER 5 /* Magic Number */
163 #define CI_PCOMPRESSION 7 /* Protocol Field Compression */
164 #define CI_ACCOMPRESSION 8 /* Address/Control Field Compression */
165 #define CI_FCS_ALTERNATIVES 9 /* FCS Alternatives (RFC 1570) */
166 #define CI_SELF_DESCRIBING_PAD 10 /* Self-Describing Pad (RFC 1570) */
167 #define CI_NUMBERED_MODE 11 /* Numbered Mode (RFC 1663) */
168 #define CI_CALLBACK 13 /* Callback (RFC 1570) */
169 #define CI_COMPOUND_FRAMES 15 /* Compound frames (RFC 1570) */
170 #define CI_MULTILINK_MRRU 17 /* Multilink MRRU (RFC 1717) */
171 #define CI_MULTILINK_SSNH 18 /* Multilink Short Sequence Number
173 #define CI_MULTILINK_EP_DISC 19 /* Multilink Endpoint Discriminator
175 #define CI_DCE_IDENTIFIER 21 /* DCE Identifier */
176 #define CI_MULTILINK_PLUS_PROC 22 /* Multilink Plus Procedure */
177 #define CI_LINK_DISC_FOR_BACP 23 /* Link Discriminator for BACP
179 #define CI_LCP_AUTHENTICATION 24 /* LCP Authentication Option */
180 #define CI_COBS 25 /* Consistent Overhead Byte
182 #define CI_PREFIX_ELISION 26 /* Prefix elision */
183 #define CI_MULTILINK_HDR_FMT 27 /* Multilink header format */
184 #define CI_INTERNATIONALIZATION 28 /* Internationalization (RFC 2484) */
185 #define CI_SDL_ON_SONET_SDH 29 /* Simple Data Link on SONET/SDH */
187 static void dissect_lcp_mru_opt(const ip_tcp_opt *optp, const u_char *opd,
188 int offset, guint length, proto_tree *tree);
189 static void dissect_lcp_async_map_opt(const ip_tcp_opt *optp, const u_char *opd,
190 int offset, guint length, proto_tree *tree);
191 static void dissect_lcp_protocol_opt(const ip_tcp_opt *optp, const u_char *opd,
192 int offset, guint length, proto_tree *tree);
193 static void dissect_lcp_magicnumber_opt(const ip_tcp_opt *optp,
194 const u_char *opd, int offset, guint length,
196 static void dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp,
197 const u_char *opd, int offset, guint length,
199 static void dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp,
200 const u_char *opd, int offset, guint length,
202 static void dissect_lcp_self_describing_pad_opt(const ip_tcp_opt *optp,
203 const u_char *opd, int offset, guint length,
205 static void dissect_lcp_callback_opt(const ip_tcp_opt *optp, const u_char *opd,
206 int offset, guint length, proto_tree *tree);
207 static void dissect_lcp_multilink_mrru_opt(const ip_tcp_opt *optp,
208 const u_char *opd, int offset, guint length,
210 static void dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp,
211 const u_char *opd, int offset, guint length,
213 static void dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp,
214 const u_char *opd, int offset, guint length,
216 static void dissect_lcp_internationalization_opt(const ip_tcp_opt *optp,
217 const u_char *opd, int offset, guint length,
219 static void dissect_mp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
221 static const ip_tcp_opt lcp_opts[] = {
224 "Maximum Receive Unit",
232 "Async Control Character Map",
233 &ett_lcp_async_map_opt,
236 dissect_lcp_async_map_opt
240 "Authentication protocol",
241 &ett_lcp_authprot_opt,
244 dissect_lcp_protocol_opt
249 &ett_lcp_qualprot_opt,
252 dissect_lcp_protocol_opt
257 &ett_lcp_magicnum_opt,
260 dissect_lcp_magicnumber_opt
264 "Protocol field compression",
272 "Address/control field compression",
281 &ett_lcp_fcs_alternatives_opt,
284 dissect_lcp_fcs_alternatives_opt
287 CI_SELF_DESCRIBING_PAD,
292 dissect_lcp_self_describing_pad_opt
297 &ett_lcp_numbered_mode_opt,
300 dissect_lcp_numbered_mode_opt
305 &ett_lcp_callback_opt,
308 dissect_lcp_callback_opt,
324 dissect_lcp_multilink_mrru_opt
328 "Use short sequence number headers",
335 CI_MULTILINK_EP_DISC,
336 "Multilink endpoint discriminator",
337 &ett_lcp_multilink_ep_disc_opt,
340 dissect_lcp_multilink_ep_disc_opt,
351 CI_MULTILINK_PLUS_PROC,
352 "Multilink Plus Procedure",
359 CI_LINK_DISC_FOR_BACP,
364 dissect_lcp_bap_link_discriminator_opt
367 CI_LCP_AUTHENTICATION,
368 "LCP authentication",
376 "Consistent Overhead Byte Stuffing",
391 CI_MULTILINK_HDR_FMT,
392 "Multilink header format",
399 CI_INTERNATIONALIZATION,
400 "Internationalization",
401 &ett_lcp_internationalization_opt,
404 dissect_lcp_internationalization_opt
408 "Simple data link on SONET/SDH",
416 #define N_LCP_OPTS (sizeof lcp_opts / sizeof lcp_opts[0])
421 #define CI_ADDRS 1 /* IP Addresses (deprecated) (RFC 1172) */
422 #define CI_COMPRESSTYPE 2 /* Compression Type (RFC 1332) */
423 #define CI_ADDR 3 /* IP Address (RFC 1332) */
424 #define CI_MOBILE_IPv4 4 /* Mobile IPv4 (RFC 2290) */
425 #define CI_MS_DNS1 129 /* Primary DNS value (RFC 1877) */
426 #define CI_MS_WINS1 130 /* Primary WINS value (RFC 1877) */
427 #define CI_MS_DNS2 131 /* Secondary DNS value (RFC 1877) */
428 #define CI_MS_WINS2 132 /* Secondary WINS value (RFC 1877) */
430 static void dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, const u_char *opd,
431 int offset, guint length, proto_tree *tree);
432 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, const u_char *opd,
433 int offset, guint length, proto_tree *tree);
435 static const ip_tcp_opt ipcp_opts[] = {
438 "IP addresses (deprecated)",
439 &ett_ipcp_ipaddrs_opt,
442 dissect_ipcp_addrs_opt
446 "IP compression protocol",
447 &ett_ipcp_compressprot_opt,
450 dissect_lcp_protocol_opt
458 dissect_ipcp_addr_opt
462 "Mobile node's home IP address",
466 dissect_ipcp_addr_opt
470 "Primary DNS server IP address",
474 dissect_ipcp_addr_opt
478 "Primary WINS server IP address",
482 dissect_ipcp_addr_opt
486 "Secondary DNS server IP address",
490 dissect_ipcp_addr_opt
494 "Secondary WINS server IP address",
498 dissect_ipcp_addr_opt
502 #define N_IPCP_OPTS (sizeof ipcp_opts / sizeof ipcp_opts[0])
505 capture_ppp( const u_char *pd, int offset, packet_counts *ld ) {
506 switch (pntohs(&pd[offset + 2])) {
508 capture_ip(pd, offset + 4, ld);
511 capture_ipx(pd, offset + 4, ld);
514 capture_vines(pd, offset + 4, ld);
523 dissect_lcp_mru_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
524 guint length, proto_tree *tree)
526 proto_tree_add_text(tree, NullTVB, offset, length, "MRU: %u", pntohs(opd));
530 dissect_lcp_async_map_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
531 guint length, proto_tree *tree)
533 proto_tree_add_text(tree, NullTVB, offset, length, "Async characters to map: 0x%08x",
538 dissect_lcp_protocol_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
539 guint length, proto_tree *tree)
543 proto_tree *field_tree = NULL;
545 tf = proto_tree_add_text(tree, NullTVB, offset, length, "%s: %u byte%s",
546 optp->name, length, plurality(length, "", "s"));
547 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
550 protocol = pntohs(opd);
551 proto_tree_add_text(field_tree, NullTVB, offset, 2, "%s: %s (0x%02x)", optp->name,
552 val_to_str(protocol, ppp_vals, "Unknown"), protocol);
557 proto_tree_add_text(field_tree, NullTVB, offset, length, "Data (%d byte%s)", length,
558 plurality(length, "", "s"));
562 dissect_lcp_magicnumber_opt(const ip_tcp_opt *optp, const u_char *opd,
563 int offset, guint length, proto_tree *tree)
565 proto_tree_add_text(tree, NullTVB, offset, length, "Magic number: 0x%08x",
570 dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp, const u_char *opd,
571 int offset, guint length, proto_tree *tree)
574 proto_tree *field_tree = NULL;
578 tf = proto_tree_add_text(tree, NullTVB, offset, length, "%s: 0x%02x",
579 optp->name, alternatives);
580 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
582 if (alternatives & 0x1)
583 proto_tree_add_text(field_tree, NullTVB, offset + 2, 1, "%s",
584 decode_boolean_bitfield(alternatives, 0x1, 8, "Null FCS", NULL));
585 if (alternatives & 0x2)
586 proto_tree_add_text(field_tree, NullTVB, offset + 2, 1, "%s",
587 decode_boolean_bitfield(alternatives, 0x2, 8, "CCITT 16-bit FCS", NULL));
588 if (alternatives & 0x4)
589 proto_tree_add_text(field_tree, NullTVB, offset + 2, 1, "%s",
590 decode_boolean_bitfield(alternatives, 0x4, 8, "CCITT 32-bit FCS", NULL));
594 dissect_lcp_self_describing_pad_opt(const ip_tcp_opt *optp, const u_char *opd,
595 int offset, guint length, proto_tree *tree)
597 proto_tree_add_text(tree, NullTVB, offset, length,
598 "Maximum octets of self-describing padding: %u",
603 dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp, const u_char *opd,
604 int offset, guint length, proto_tree *tree)
607 proto_tree *field_tree = NULL;
609 tf = proto_tree_add_text(tree, NullTVB, offset, length, "%s: %u byte%s",
610 optp->name, length, plurality(length, "", "s"));
611 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
614 proto_tree_add_text(field_tree, NullTVB, offset, 1, "Window: %u", *opd);
619 proto_tree_add_text(field_tree, NullTVB, offset, length, "Address (%d byte%s)",
620 length, plurality(length, "", "s"));
623 static const value_string callback_op_vals[] = {
624 {0, "Location is determined by user authentication" },
625 {1, "Message is dialing string" },
626 {2, "Message is location identifier" },
627 {3, "Message is E.164" },
628 {4, "Message is distinguished name" },
633 dissect_lcp_callback_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
634 guint length, proto_tree *tree)
637 proto_tree *field_tree = NULL;
639 tf = proto_tree_add_text(tree, NullTVB, offset, length, "%s: %u byte%s",
640 optp->name, length, plurality(length, "", "s"));
641 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
644 proto_tree_add_text(field_tree, NullTVB, offset, 1, "Operation: %s (0x%02x)",
645 val_to_str(*opd, callback_op_vals, "Unknown"),
651 proto_tree_add_text(field_tree, NullTVB, offset, length, "Message (%d byte%s)",
652 length, plurality(length, "", "s"));
656 dissect_lcp_multilink_mrru_opt(const ip_tcp_opt *optp, const u_char *opd,
657 int offset, guint length, proto_tree *tree)
659 proto_tree_add_text(tree, NullTVB, offset, length, "Multilink MRRU: %u",
664 #define CLASS_LOCAL 1
666 #define CLASS_IEEE_802_1 3
667 #define CLASS_PPP_MAGIC_NUMBER 4
668 #define CLASS_PSDN_DIRECTORY_NUMBER 5
670 static const value_string multilink_ep_disc_class_vals[] = {
671 {CLASS_NULL, "Null" },
672 {CLASS_LOCAL, "Locally assigned address" },
673 {CLASS_IP, "IP address" },
674 {CLASS_IEEE_802_1, "IEEE 802.1 globally assigned MAC address" },
675 {CLASS_PPP_MAGIC_NUMBER, "PPP magic-number block" },
676 {CLASS_PSDN_DIRECTORY_NUMBER, "Public switched network directory number" },
681 dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp, const u_char *opd,
682 int offset, guint length, proto_tree *tree)
685 proto_tree *field_tree = NULL;
686 guint8 ep_disc_class;
688 tf = proto_tree_add_text(tree, NullTVB, offset, length, "%s: %u byte%s",
689 optp->name, length, plurality(length, "", "s"));
690 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
693 ep_disc_class = *opd;
694 proto_tree_add_text(field_tree, NullTVB, offset, 1, "Class: %s (%u)",
695 val_to_str(ep_disc_class, multilink_ep_disc_class_vals, "Unknown"),
701 switch (ep_disc_class) {
704 proto_tree_add_text(field_tree, NullTVB, offset, length,
705 "Address (%d byte%s), should have been empty",
706 length, plurality(length, "", "s"));
711 proto_tree_add_text(field_tree, NullTVB, offset, length,
712 "Address (%d byte%s), should have been <20",
713 length, plurality(length, "", "s"));
715 proto_tree_add_text(field_tree, NullTVB, offset, length,
716 "Address (%d byte%s)",
717 length, plurality(length, "", "s"));
723 proto_tree_add_text(field_tree, NullTVB, offset, length,
724 "Address (%d byte%s), should have been 4",
725 length, plurality(length, "", "s"));
727 proto_tree_add_text(field_tree, NullTVB, offset, length,
728 "Address: %s", ip_to_str(opd));
732 case CLASS_IEEE_802_1:
734 proto_tree_add_text(field_tree, NullTVB, offset, length,
735 "Address (%d byte%s), should have been 6",
736 length, plurality(length, "", "s"));
738 proto_tree_add_text(field_tree, NullTVB, offset, length,
739 "Address: %s", ether_to_str(opd));
743 case CLASS_PPP_MAGIC_NUMBER:
744 /* XXX - dissect as 32-bit magic numbers */
746 proto_tree_add_text(field_tree, NullTVB, offset, length,
747 "Address (%d byte%s), should have been <20",
748 length, plurality(length, "", "s"));
750 proto_tree_add_text(field_tree, NullTVB, offset, length,
751 "Address (%d byte%s)",
752 length, plurality(length, "", "s"));
756 case CLASS_PSDN_DIRECTORY_NUMBER:
758 proto_tree_add_text(field_tree, NullTVB, offset, length,
759 "Address (%d byte%s), should have been <20",
760 length, plurality(length, "", "s"));
762 proto_tree_add_text(field_tree, NullTVB, offset, length,
763 "Address (%d byte%s)",
764 length, plurality(length, "", "s"));
769 proto_tree_add_text(field_tree, NullTVB, offset, length,
770 "Address (%d byte%s)",
771 length, plurality(length, "", "s"));
778 dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp, const u_char *opd,
779 int offset, guint length, proto_tree *tree)
781 proto_tree_add_text(tree, NullTVB, offset, length,
782 "Link discriminator for BAP: 0x%04x",
786 /* Character set numbers from the IANA charset registry. */
787 static const value_string charset_num_vals[] = {
793 dissect_lcp_internationalization_opt(const ip_tcp_opt *optp, const u_char *opd,
794 int offset, guint length, proto_tree *tree)
797 proto_tree *field_tree = NULL;
799 tf = proto_tree_add_text(tree, NullTVB, offset, length, "%s: %u byte%s",
800 optp->name, length, plurality(length, "", "s"));
801 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
804 proto_tree_add_text(field_tree, NullTVB, offset, 4, "Character set: %s (0x%04x)",
805 val_to_str(pntohl(opd), charset_num_vals, "Unknown"),
811 /* XXX - should be displayed as an ASCII string */
812 proto_tree_add_text(field_tree, NullTVB, offset, length, "Language tag (%d byte%s)",
813 length, plurality(length, "", "s"));
818 dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, const u_char *opd,
819 int offset, guint length, proto_tree *tree)
822 proto_tree *field_tree = NULL;
824 tf = proto_tree_add_text(tree, NullTVB, offset, length, "%s: %u byte%s",
825 optp->name, length, plurality(length, "", "s"));
826 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
829 proto_tree_add_text(field_tree, NullTVB, offset, 4,
830 "Source IP address: %s", ip_to_str(opd));
834 proto_tree_add_text(field_tree, NullTVB, offset, 4,
835 "Destination IP address: %s", ip_to_str(opd));
838 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, const u_char *opd,
839 int offset, guint length, proto_tree *tree)
841 proto_tree_add_text(tree, NullTVB, offset, length, "%s: %s", optp->name,
842 ip_to_str((guint8 *)opd));
846 dissect_cp( tvbuff_t *tvb, const char *proto_short_name,
847 const char *proto_long_name, int proto_subtree_index,
848 const value_string *proto_vals, int options_subtree_index,
849 const ip_tcp_opt *opts, int nopts, packet_info *pinfo, proto_tree *tree ) {
851 proto_tree *fh_tree = NULL;
853 proto_tree *field_tree;
860 code = tvb_get_guint8(tvb, 0);
861 id = tvb_get_guint8(tvb, 1);
862 length = tvb_get_ntohs(tvb, 2);
864 if(check_col(pinfo->fd, COL_INFO))
865 col_add_fstr(pinfo->fd, COL_INFO, "%sCP %s", proto_short_name,
866 val_to_str(code, proto_vals, "Unknown"));
869 ti = proto_tree_add_text(tree, tvb, 0, 4, "%s Control Protocol",
871 fh_tree = proto_item_add_subtree(ti, proto_subtree_index);
872 proto_tree_add_text(fh_tree, tvb, 0, 1, "Code: %s (0x%02x)",
873 val_to_str(code, proto_vals, "Unknown"), code);
874 proto_tree_add_text(fh_tree, tvb, 1, 1, "Identifier: 0x%02x",
876 proto_tree_add_text(fh_tree, tvb, 2, 2, "Length: %u",
889 const guint8 *this_pd;
892 tvb_compat(tvb, &this_pd, &this_offset);
894 tf = proto_tree_add_text(fh_tree, tvb, offset, length,
895 "Options: (%d byte%s)", length, plurality(length, "", "s"));
896 field_tree = proto_item_add_subtree(tf, options_subtree_index);
897 dissect_ip_tcp_options(&this_pd[this_offset + offset],this_offset + offset,
898 length, opts, nopts, -1, field_tree);
908 proto_tree_add_text(fh_tree, tvb, offset, 4, "Magic number: 0x%08x",
909 tvb_get_ntohl(tvb, offset));
913 proto_tree_add_text(fh_tree, tvb, offset, length, "Message (%d byte%s)",
914 length, plurality(length, "", "s"));
920 proto_tree_add_text(fh_tree, tvb, offset, 4, "Magic number: 0x%08x",
921 tvb_get_ntohl(tvb, offset));
924 proto_tree_add_text(fh_tree, tvb, offset, 4, "Seconds remaining: %u",
925 tvb_get_ntohl(tvb, offset));
929 proto_tree_add_text(fh_tree, tvb, offset, length, "Message (%d byte%s)",
930 length, plurality(length, "", "s"));
936 protocol = tvb_get_ntohs(tvb, offset);
937 proto_tree_add_text(fh_tree, tvb, offset, 2, "Rejected protocol: %s (0x%04x)",
938 val_to_str(protocol, ppp_vals, "Unknown"), protocol);
942 proto_tree_add_text(fh_tree, tvb, offset, length, "Rejected packet (%d byte%s)",
943 length, plurality(length, "", "s"));
944 /* XXX - should be dissected as a PPP packet */
949 /* decode the rejected LCP packet here. */
951 proto_tree_add_text(fh_tree, tvb, offset, length, "Rejected packet (%d byte%s)",
952 length, plurality(length, "", "s"));
958 proto_tree_add_text(fh_tree, tvb, offset, length, "Data (%d byte%s)",
959 length, plurality(length, "", "s"));
964 proto_tree_add_text(fh_tree, tvb, offset, length, "Stuff (%d byte%s)",
965 length, plurality(length, "", "s"));
970 /* Protocol field compression */
974 dissect_ppp_stuff( tvbuff_t *tvb, packet_info *pinfo,
975 proto_tree *tree, proto_tree *fh_tree ) {
979 const guint8 *next_pd;
982 if (tvb_get_guint8(tvb, 0) & PFC_BIT) {
983 ppp_prot = tvb_get_guint8(tvb, 0);
986 ppp_prot = tvb_get_ntohs(tvb, 0);
991 proto_tree_add_text(fh_tree, tvb, 0, proto_len, "Protocol: %s (0x%04x)",
992 val_to_str(ppp_prot, ppp_vals, "Unknown"), ppp_prot);
995 next_tvb = tvb_new_subset(tvb, proto_len, -1, -1);
996 tvb_compat(next_tvb, &next_pd, &next_offset);
998 /* do lookup with the subdissector table */
999 if (dissector_try_port(subdissector_table, ppp_prot, next_pd, next_offset, pinfo->fd, tree))
1002 /* XXX - make "dissect_lcp()" and "dissect_ipcp()", have them just
1003 call "dissect_cp()", and register them as well?
1005 We can do that for "dissect_mp()", too. */
1008 dissect_mp(next_tvb, pinfo, tree);
1011 dissect_cp(next_tvb, "L", "Link", ett_lcp, lcp_vals, ett_lcp_options,
1012 lcp_opts, N_LCP_OPTS, pinfo, tree);
1015 dissect_cp(next_tvb, "IP", "IP", ett_ipcp, cp_vals, ett_ipcp_options,
1016 ipcp_opts, N_IPCP_OPTS, pinfo, tree);
1019 if (check_col(pinfo->fd, COL_INFO))
1020 col_add_fstr(pinfo->fd, COL_INFO, "PPP %s (0x%04x)",
1021 val_to_str(ppp_prot, ppp_vals, "Unknown"), ppp_prot);
1022 dissect_data_tvb(next_tvb, pinfo, tree);
1027 #define MP_FRAG_MASK 0xC0
1028 #define MP_FRAG(bits) ((bits) & MP_FRAG_MASK)
1029 #define MP_FRAG_FIRST 0x80
1030 #define MP_FRAG_LAST 0x40
1031 #define MP_FRAG_RESERVED 0x3f
1033 /* According to RFC 1717, the length the MP header isn't indicated anywhere
1034 in the header itself. It starts out at four bytes and can be
1035 negotiated down to two using LCP. We currently assume that all
1036 headers are four bytes. - gcc
1039 dissect_mp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1041 proto_tree *mp_tree, *hdr_tree, *fh_tree = NULL;
1049 flags = tvb_get_guint8(tvb, 0);
1050 first = flags && MP_FRAG_FIRST;
1051 last = flags && MP_FRAG_LAST;
1052 seq = tvb_get_ntoh24(tvb, 1);
1054 if (check_col(pinfo->fd, COL_INFO))
1055 col_add_fstr(pinfo->fd, COL_INFO, "PPP Multilink");
1065 case MP_FRAG_FIRST|MP_FRAG_LAST:
1066 flag_str = "First, Last";
1069 flag_str = "Unknown";
1072 ti = proto_tree_add_item(tree, proto_mp, tvb, 0, 4, FALSE);
1073 mp_tree = proto_item_add_subtree(ti, ett_mp);
1074 ti = proto_tree_add_text(mp_tree, tvb, 0, 1, "Fragment: 0x%2X (%s)",
1076 hdr_tree = proto_item_add_subtree(ti, ett_mp_flags);
1077 proto_tree_add_boolean_format(hdr_tree, hf_mp_frag_first, tvb, 0, 1, first,
1078 "%s", decode_boolean_bitfield(flags, MP_FRAG_FIRST, sizeof(flags) * 8,
1079 "first", "not first"));
1080 proto_tree_add_boolean_format(hdr_tree, hf_mp_frag_last, tvb, 0, 1, last,
1081 "%s", decode_boolean_bitfield(flags, MP_FRAG_LAST, sizeof(flags) * 8,
1082 "last", "not last"));
1083 proto_tree_add_text(hdr_tree, tvb, 0, 1, "%s",
1084 decode_boolean_bitfield(flags, MP_FRAG_RESERVED, sizeof(flags) * 8,
1085 "reserved", "reserved"));
1086 proto_tree_add_uint(mp_tree, hf_mp_sequence_num, tvb, 1, 3, seq);
1089 next_tvb = tvb_new_subset(tvb, 4, -1, -1);
1091 if (tvb_length(next_tvb) > 0) {
1093 ti = proto_tree_add_item(tree, proto_ppp, next_tvb, 0, 1, FALSE);
1094 fh_tree = proto_item_add_subtree(ti, ett_ppp);
1096 dissect_ppp_stuff(next_tvb, pinfo, tree, fh_tree);
1101 dissect_payload_ppp( const u_char *pd, int offset, frame_data *fd, proto_tree *tree ) {
1103 proto_tree *fh_tree = NULL;
1106 /* populate a tree in the second pane with the status of the link
1109 ti = proto_tree_add_item(tree, proto_ppp, NullTVB, 0+offset, 2, FALSE);
1110 fh_tree = proto_item_add_subtree(ti, ett_ppp);
1113 next_tvb = tvb_create_from_top(offset);
1114 dissect_ppp_stuff(next_tvb, &pi, tree, fh_tree);
1118 dissect_ppp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
1121 proto_tree *fh_tree = NULL;
1126 pinfo->current_proto = "PPP";
1127 byte0 = tvb_get_guint8(tvb, 0);
1129 if (byte0 == 0xff) {
1130 ph.ppp_addr = tvb_get_guint8(tvb, 0);
1131 ph.ppp_ctl = tvb_get_guint8(tvb, 1);
1132 ph.ppp_prot = tvb_get_ntohs(tvb, 2);
1136 /* address and control are compressed (NULL) */
1137 ph.ppp_prot = tvb_get_ntohs(tvb, 0);
1141 /* load the top pane info. This should be overwritten by
1142 the next protocol in the stack */
1144 if(check_col(pinfo->fd, COL_RES_DL_SRC))
1145 col_add_str(pinfo->fd, COL_RES_DL_SRC, "N/A" );
1146 if(check_col(pinfo->fd, COL_RES_DL_DST))
1147 col_add_str(pinfo->fd, COL_RES_DL_DST, "N/A" );
1148 if(check_col(pinfo->fd, COL_PROTOCOL))
1149 col_add_str(pinfo->fd, COL_PROTOCOL, "PPP" );
1151 /* populate a tree in the second pane with the status of the link
1154 ti = proto_tree_add_item(tree, proto_ppp, tvb, 0, 4, FALSE);
1155 fh_tree = proto_item_add_subtree(ti, ett_ppp);
1156 if (byte0 == 0xff) {
1157 proto_tree_add_text(fh_tree, tvb, 0, 1, "Address: %02x", ph.ppp_addr);
1158 proto_tree_add_text(fh_tree, tvb, 1, 1, "Control: %02x", ph.ppp_ctl);
1162 next_tvb = tvb_new_subset(tvb, proto_offset, -1, -1);
1164 if (!dissect_ppp_stuff(next_tvb, pinfo, tree, fh_tree)) {
1165 if (check_col(pinfo->fd, COL_PROTOCOL))
1166 col_add_fstr(pinfo->fd, COL_PROTOCOL, "0x%04x", ph.ppp_prot);
1171 proto_register_ppp(void)
1173 /* static hf_register_info hf[] = {
1175 { "Name", "ppp.abbreviation", TYPE, VALS_POINTER }},
1177 static gint *ett[] = {
1181 &ett_ipcp_ipaddrs_opt,
1182 &ett_ipcp_compressprot_opt,
1186 &ett_lcp_async_map_opt,
1187 &ett_lcp_authprot_opt,
1188 &ett_lcp_qualprot_opt,
1189 &ett_lcp_magicnum_opt,
1190 &ett_lcp_fcs_alternatives_opt,
1191 &ett_lcp_numbered_mode_opt,
1192 &ett_lcp_callback_opt,
1193 &ett_lcp_multilink_ep_disc_opt,
1194 &ett_lcp_internationalization_opt,
1197 proto_ppp = proto_register_protocol("Point-to-Point Protocol", "ppp");
1198 /* proto_register_field_array(proto_ppp, hf, array_length(hf));*/
1199 proto_register_subtree_array(ett, array_length(ett));
1201 /* subdissector code */
1202 subdissector_table = register_dissector_table("ppp.protocol");
1206 proto_register_mp(void)
1208 static hf_register_info hf[] = {
1209 { &hf_mp_frag_first,
1210 { "First fragment", "mp.first", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1214 { "Last fragment", "mp.last", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1217 { &hf_mp_sequence_num,
1218 { "Sequence number", "mp.seq", FT_UINT24, BASE_DEC, NULL, 0x0,
1221 static gint *ett[] = {
1226 proto_mp = proto_register_protocol("PPP Multilink Protocol", "mp");
1227 proto_register_field_array(proto_mp, hf, array_length(hf));
1228 proto_register_subtree_array(ett, array_length(ett));