2 * Routines for ppp packet disassembly
4 * $Id: packet-ppp.c,v 1.42 2000/11/19 02:00:02 guy 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, tvbuff_t *tvb,
188 int offset, guint length, proto_tree *tree);
189 static void dissect_lcp_async_map_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
190 int offset, guint length, proto_tree *tree);
191 static void dissect_lcp_protocol_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
192 int offset, guint length, proto_tree *tree);
193 static void dissect_lcp_magicnumber_opt(const ip_tcp_opt *optp,
194 tvbuff_t *tvb, int offset, guint length,
196 static void dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp,
197 tvbuff_t *tvb, int offset, guint length,
199 static void dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp,
200 tvbuff_t *tvb, int offset, guint length,
202 static void dissect_lcp_self_describing_pad_opt(const ip_tcp_opt *optp,
203 tvbuff_t *tvb, int offset, guint length,
205 static void dissect_lcp_callback_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
206 int offset, guint length, proto_tree *tree);
207 static void dissect_lcp_multilink_mrru_opt(const ip_tcp_opt *optp,
208 tvbuff_t *tvb, int offset, guint length,
210 static void dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp,
211 tvbuff_t *tvb, int offset, guint length,
213 static void dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp,
214 tvbuff_t *tvb, int offset, guint length,
216 static void dissect_lcp_internationalization_opt(const ip_tcp_opt *optp,
217 tvbuff_t *tvb, 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, tvbuff_t *tvb,
431 int offset, guint length, proto_tree *tree);
432 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
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, tvbuff_t *tvb, int offset,
524 guint length, proto_tree *tree)
526 proto_tree_add_text(tree, tvb, offset, length, "MRU: %u",
527 tvb_get_ntohs(tvb, offset + 2));
531 dissect_lcp_async_map_opt(const ip_tcp_opt *optp, tvbuff_t *tvb, int offset,
532 guint length, proto_tree *tree)
534 proto_tree_add_text(tree, tvb, offset, length, "Async characters to map: 0x%08x",
535 tvb_get_ntohl(tvb, offset + 2));
539 dissect_lcp_protocol_opt(const ip_tcp_opt *optp, tvbuff_t *tvb, int offset,
540 guint length, proto_tree *tree)
544 proto_tree *field_tree = NULL;
546 tf = proto_tree_add_text(tree, tvb, offset, length, "%s: %u byte%s",
547 optp->name, length, plurality(length, "", "s"));
548 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
551 protocol = tvb_get_ntohs(tvb, offset);
552 proto_tree_add_text(field_tree, tvb, offset, 2, "%s: %s (0x%02x)", optp->name,
553 val_to_str(protocol, ppp_vals, "Unknown"), protocol);
557 proto_tree_add_text(field_tree, tvb, offset, length, "Data (%d byte%s)", length,
558 plurality(length, "", "s"));
562 dissect_lcp_magicnumber_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
563 int offset, guint length, proto_tree *tree)
565 proto_tree_add_text(tree, tvb, offset, length, "Magic number: 0x%08x",
566 tvb_get_ntohl(tvb, offset + 2));
570 dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
571 int offset, guint length, proto_tree *tree)
574 proto_tree *field_tree = NULL;
577 alternatives = tvb_get_guint8(tvb, offset + 2);
578 tf = proto_tree_add_text(tree, tvb, 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, tvb, 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, tvb, 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, tvb, 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, tvbuff_t *tvb,
595 int offset, guint length, proto_tree *tree)
597 proto_tree_add_text(tree, tvb, offset, length,
598 "Maximum octets of self-describing padding: %u",
599 tvb_get_guint8(tvb, offset + 2));
603 dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
604 int offset, guint length, proto_tree *tree)
607 proto_tree *field_tree = NULL;
609 tf = proto_tree_add_text(tree, tvb, 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, tvb, offset, 1, "Window: %u",
615 tvb_get_guint8(tvb, offset));
619 proto_tree_add_text(field_tree, tvb, 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, tvbuff_t *tvb, int offset,
634 guint length, proto_tree *tree)
637 proto_tree *field_tree = NULL;
640 tf = proto_tree_add_text(tree, tvb, offset, length, "%s: %u byte%s",
641 optp->name, length, plurality(length, "", "s"));
642 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
645 operation = tvb_get_guint8(tvb, offset);
646 proto_tree_add_text(field_tree, tvb, offset, 1, "Operation: %s (0x%02x)",
647 val_to_str(operation, callback_op_vals, "Unknown"),
652 proto_tree_add_text(field_tree, tvb, offset, length, "Message (%d byte%s)",
653 length, plurality(length, "", "s"));
657 dissect_lcp_multilink_mrru_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
658 int offset, guint length, proto_tree *tree)
660 proto_tree_add_text(tree, tvb, offset, length, "Multilink MRRU: %u",
661 tvb_get_ntohs(tvb, offset + 2));
665 #define CLASS_LOCAL 1
667 #define CLASS_IEEE_802_1 3
668 #define CLASS_PPP_MAGIC_NUMBER 4
669 #define CLASS_PSDN_DIRECTORY_NUMBER 5
671 static const value_string multilink_ep_disc_class_vals[] = {
672 {CLASS_NULL, "Null" },
673 {CLASS_LOCAL, "Locally assigned address" },
674 {CLASS_IP, "IP address" },
675 {CLASS_IEEE_802_1, "IEEE 802.1 globally assigned MAC address" },
676 {CLASS_PPP_MAGIC_NUMBER, "PPP magic-number block" },
677 {CLASS_PSDN_DIRECTORY_NUMBER, "Public switched network directory number" },
682 dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
683 int offset, guint length, proto_tree *tree)
686 proto_tree *field_tree = NULL;
687 guint8 ep_disc_class;
689 tf = proto_tree_add_text(tree, tvb, offset, length, "%s: %u byte%s",
690 optp->name, length, plurality(length, "", "s"));
691 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
694 ep_disc_class = tvb_get_guint8(tvb, offset);
695 proto_tree_add_text(field_tree, tvb, offset, 1, "Class: %s (%u)",
696 val_to_str(ep_disc_class, multilink_ep_disc_class_vals, "Unknown"),
701 switch (ep_disc_class) {
704 proto_tree_add_text(field_tree, tvb, offset, length,
705 "Address (%d byte%s), should have been empty",
706 length, plurality(length, "", "s"));
711 proto_tree_add_text(field_tree, tvb, offset, length,
712 "Address (%d byte%s), should have been <20",
713 length, plurality(length, "", "s"));
715 proto_tree_add_text(field_tree, tvb, offset, length,
716 "Address (%d byte%s)",
717 length, plurality(length, "", "s"));
723 proto_tree_add_text(field_tree, tvb, offset, length,
724 "Address (%d byte%s), should have been 4",
725 length, plurality(length, "", "s"));
727 proto_tree_add_text(field_tree, tvb, offset, length,
728 "Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
732 case CLASS_IEEE_802_1:
734 proto_tree_add_text(field_tree, tvb, offset, length,
735 "Address (%d byte%s), should have been 6",
736 length, plurality(length, "", "s"));
738 proto_tree_add_text(field_tree, tvb, offset, length,
739 "Address: %s", ether_to_str(tvb_get_ptr(tvb, offset, 6)));
743 case CLASS_PPP_MAGIC_NUMBER:
744 /* XXX - dissect as 32-bit magic numbers */
746 proto_tree_add_text(field_tree, tvb, offset, length,
747 "Address (%d byte%s), should have been <20",
748 length, plurality(length, "", "s"));
750 proto_tree_add_text(field_tree, tvb, 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, tvb, offset, length,
759 "Address (%d byte%s), should have been <20",
760 length, plurality(length, "", "s"));
762 proto_tree_add_text(field_tree, tvb, offset, length,
763 "Address (%d byte%s)",
764 length, plurality(length, "", "s"));
769 proto_tree_add_text(field_tree, tvb, offset, length,
770 "Address (%d byte%s)",
771 length, plurality(length, "", "s"));
778 dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
779 int offset, guint length, proto_tree *tree)
781 proto_tree_add_text(tree, tvb, offset, length,
782 "Link discriminator for BAP: 0x%04x",
783 tvb_get_ntohs(tvb, offset + 2));
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, tvbuff_t *tvb,
794 int offset, guint length, proto_tree *tree)
797 proto_tree *field_tree = NULL;
800 tf = proto_tree_add_text(tree, tvb, offset, length, "%s: %u byte%s",
801 optp->name, length, plurality(length, "", "s"));
802 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
805 charset = tvb_get_ntohl(tvb, offset);
806 proto_tree_add_text(field_tree, tvb, offset, 4, "Character set: %s (0x%04x)",
807 val_to_str(charset, charset_num_vals, "Unknown"),
812 /* XXX - should be displayed as an ASCII string */
813 proto_tree_add_text(field_tree, tvb, offset, length, "Language tag (%d byte%s)",
814 length, plurality(length, "", "s"));
819 dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
820 int offset, guint length, proto_tree *tree)
823 proto_tree *field_tree = NULL;
825 tf = proto_tree_add_text(tree, tvb, offset, length, "%s: %u byte%s",
826 optp->name, length, plurality(length, "", "s"));
827 field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
830 proto_tree_add_text(field_tree, tvb, offset, 4,
831 "Source IP address: %s",
832 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
835 proto_tree_add_text(field_tree, tvb, offset, 4,
836 "Destination IP address: %s",
837 ip_to_str(tvb_get_ptr(tvb, offset, 4)));
840 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
841 int offset, guint length, proto_tree *tree)
843 proto_tree_add_text(tree, tvb, offset, length, "%s: %s", optp->name,
844 ip_to_str(tvb_get_ptr(tvb, offset + 2, 4)));
848 dissect_cp( tvbuff_t *tvb, const char *proto_short_name,
849 const char *proto_long_name, int proto_subtree_index,
850 const value_string *proto_vals, int options_subtree_index,
851 const ip_tcp_opt *opts, int nopts, packet_info *pinfo, proto_tree *tree ) {
853 proto_tree *fh_tree = NULL;
855 proto_tree *field_tree;
862 code = tvb_get_guint8(tvb, 0);
863 id = tvb_get_guint8(tvb, 1);
864 length = tvb_get_ntohs(tvb, 2);
866 if(check_col(pinfo->fd, COL_INFO))
867 col_add_fstr(pinfo->fd, COL_INFO, "%sCP %s", proto_short_name,
868 val_to_str(code, proto_vals, "Unknown"));
871 ti = proto_tree_add_text(tree, tvb, 0, 4, "%s Control Protocol",
873 fh_tree = proto_item_add_subtree(ti, proto_subtree_index);
874 proto_tree_add_text(fh_tree, tvb, 0, 1, "Code: %s (0x%02x)",
875 val_to_str(code, proto_vals, "Unknown"), code);
876 proto_tree_add_text(fh_tree, tvb, 1, 1, "Identifier: 0x%02x",
878 proto_tree_add_text(fh_tree, tvb, 2, 2, "Length: %u",
891 tf = proto_tree_add_text(fh_tree, tvb, offset, length,
892 "Options: (%d byte%s)", length, plurality(length, "", "s"));
893 field_tree = proto_item_add_subtree(tf, options_subtree_index);
894 dissect_ip_tcp_options(tvb, offset, length, opts, nopts, -1,
905 proto_tree_add_text(fh_tree, tvb, offset, 4, "Magic number: 0x%08x",
906 tvb_get_ntohl(tvb, offset));
910 proto_tree_add_text(fh_tree, tvb, offset, length, "Message (%d byte%s)",
911 length, plurality(length, "", "s"));
917 proto_tree_add_text(fh_tree, tvb, offset, 4, "Magic number: 0x%08x",
918 tvb_get_ntohl(tvb, offset));
921 proto_tree_add_text(fh_tree, tvb, offset, 4, "Seconds remaining: %u",
922 tvb_get_ntohl(tvb, offset));
926 proto_tree_add_text(fh_tree, tvb, offset, length, "Message (%d byte%s)",
927 length, plurality(length, "", "s"));
933 protocol = tvb_get_ntohs(tvb, offset);
934 proto_tree_add_text(fh_tree, tvb, offset, 2, "Rejected protocol: %s (0x%04x)",
935 val_to_str(protocol, ppp_vals, "Unknown"), protocol);
939 proto_tree_add_text(fh_tree, tvb, offset, length, "Rejected packet (%d byte%s)",
940 length, plurality(length, "", "s"));
941 /* XXX - should be dissected as a PPP packet */
946 /* decode the rejected LCP packet here. */
948 proto_tree_add_text(fh_tree, tvb, offset, length, "Rejected packet (%d byte%s)",
949 length, plurality(length, "", "s"));
955 proto_tree_add_text(fh_tree, tvb, offset, length, "Data (%d byte%s)",
956 length, plurality(length, "", "s"));
961 proto_tree_add_text(fh_tree, tvb, offset, length, "Stuff (%d byte%s)",
962 length, plurality(length, "", "s"));
967 /* Protocol field compression */
971 dissect_ppp_stuff( tvbuff_t *tvb, packet_info *pinfo,
972 proto_tree *tree, proto_tree *fh_tree ) {
977 if (tvb_get_guint8(tvb, 0) & PFC_BIT) {
978 ppp_prot = tvb_get_guint8(tvb, 0);
981 ppp_prot = tvb_get_ntohs(tvb, 0);
986 proto_tree_add_text(fh_tree, tvb, 0, proto_len, "Protocol: %s (0x%04x)",
987 val_to_str(ppp_prot, ppp_vals, "Unknown"), ppp_prot);
990 next_tvb = tvb_new_subset(tvb, proto_len, -1, -1);
992 /* do lookup with the subdissector table */
993 if (dissector_try_port(subdissector_table, ppp_prot, next_tvb, pinfo, tree))
996 /* XXX - make "dissect_lcp()" and "dissect_ipcp()", have them just
997 call "dissect_cp()", and register them as well?
999 We can do that for "dissect_mp()", too. */
1002 dissect_mp(next_tvb, pinfo, tree);
1005 dissect_cp(next_tvb, "L", "Link", ett_lcp, lcp_vals, ett_lcp_options,
1006 lcp_opts, N_LCP_OPTS, pinfo, tree);
1009 dissect_cp(next_tvb, "IP", "IP", ett_ipcp, cp_vals, ett_ipcp_options,
1010 ipcp_opts, N_IPCP_OPTS, pinfo, tree);
1013 if (check_col(pinfo->fd, COL_INFO))
1014 col_add_fstr(pinfo->fd, COL_INFO, "PPP %s (0x%04x)",
1015 val_to_str(ppp_prot, ppp_vals, "Unknown"), ppp_prot);
1016 dissect_data(next_tvb, 0, pinfo, tree);
1021 #define MP_FRAG_MASK 0xC0
1022 #define MP_FRAG(bits) ((bits) & MP_FRAG_MASK)
1023 #define MP_FRAG_FIRST 0x80
1024 #define MP_FRAG_LAST 0x40
1025 #define MP_FRAG_RESERVED 0x3f
1027 /* According to RFC 1717, the length the MP header isn't indicated anywhere
1028 in the header itself. It starts out at four bytes and can be
1029 negotiated down to two using LCP. We currently assume that all
1030 headers are four bytes. - gcc
1033 dissect_mp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1035 proto_tree *mp_tree, *hdr_tree, *fh_tree = NULL;
1043 CHECK_DISPLAY_AS_DATA(proto_mp, tvb, pinfo, tree);
1045 flags = tvb_get_guint8(tvb, 0);
1046 first = flags && MP_FRAG_FIRST;
1047 last = flags && MP_FRAG_LAST;
1048 seq = tvb_get_ntoh24(tvb, 1);
1050 if (check_col(pinfo->fd, COL_INFO))
1051 col_add_fstr(pinfo->fd, COL_INFO, "PPP Multilink");
1061 case MP_FRAG_FIRST|MP_FRAG_LAST:
1062 flag_str = "First, Last";
1065 flag_str = "Unknown";
1068 ti = proto_tree_add_item(tree, proto_mp, tvb, 0, 4, FALSE);
1069 mp_tree = proto_item_add_subtree(ti, ett_mp);
1070 ti = proto_tree_add_text(mp_tree, tvb, 0, 1, "Fragment: 0x%2X (%s)",
1072 hdr_tree = proto_item_add_subtree(ti, ett_mp_flags);
1073 proto_tree_add_boolean_format(hdr_tree, hf_mp_frag_first, tvb, 0, 1, first,
1074 "%s", decode_boolean_bitfield(flags, MP_FRAG_FIRST, sizeof(flags) * 8,
1075 "first", "not first"));
1076 proto_tree_add_boolean_format(hdr_tree, hf_mp_frag_last, tvb, 0, 1, last,
1077 "%s", decode_boolean_bitfield(flags, MP_FRAG_LAST, sizeof(flags) * 8,
1078 "last", "not last"));
1079 proto_tree_add_text(hdr_tree, tvb, 0, 1, "%s",
1080 decode_boolean_bitfield(flags, MP_FRAG_RESERVED, sizeof(flags) * 8,
1081 "reserved", "reserved"));
1082 proto_tree_add_uint(mp_tree, hf_mp_sequence_num, tvb, 1, 3, seq);
1085 next_tvb = tvb_new_subset(tvb, 4, -1, -1);
1087 if (tvb_length(next_tvb) > 0) {
1089 ti = proto_tree_add_item(tree, proto_ppp, next_tvb, 0, 1, FALSE);
1090 fh_tree = proto_item_add_subtree(ti, ett_ppp);
1092 dissect_ppp_stuff(next_tvb, pinfo, tree, fh_tree);
1097 dissect_payload_ppp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
1099 proto_tree *fh_tree = NULL;
1102 /* XXX - the length shouldn't be 2, it should be based on the length
1103 of the protocol field. */
1105 ti = proto_tree_add_item(tree, proto_ppp, tvb, 0, 2, FALSE);
1106 fh_tree = proto_item_add_subtree(ti, ett_ppp);
1109 dissect_ppp_stuff(tvb, pinfo, tree, fh_tree);
1113 dissect_ppp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
1116 proto_tree *fh_tree = NULL;
1121 CHECK_DISPLAY_AS_DATA(proto_ppp, tvb, pinfo, tree);
1123 pinfo->current_proto = "PPP";
1124 byte0 = tvb_get_guint8(tvb, 0);
1126 if (byte0 == 0xff) {
1127 ph.ppp_addr = tvb_get_guint8(tvb, 0);
1128 ph.ppp_ctl = tvb_get_guint8(tvb, 1);
1129 ph.ppp_prot = tvb_get_ntohs(tvb, 2);
1133 /* address and control are compressed (NULL) */
1134 ph.ppp_prot = tvb_get_ntohs(tvb, 0);
1138 /* load the top pane info. This should be overwritten by
1139 the next protocol in the stack */
1141 if(check_col(pinfo->fd, COL_RES_DL_SRC))
1142 col_add_str(pinfo->fd, COL_RES_DL_SRC, "N/A" );
1143 if(check_col(pinfo->fd, COL_RES_DL_DST))
1144 col_add_str(pinfo->fd, COL_RES_DL_DST, "N/A" );
1145 if(check_col(pinfo->fd, COL_PROTOCOL))
1146 col_add_str(pinfo->fd, COL_PROTOCOL, "PPP" );
1149 ti = proto_tree_add_item(tree, proto_ppp, tvb, 0, 4, FALSE);
1150 fh_tree = proto_item_add_subtree(ti, ett_ppp);
1151 if (byte0 == 0xff) {
1152 proto_tree_add_text(fh_tree, tvb, 0, 1, "Address: %02x", ph.ppp_addr);
1153 proto_tree_add_text(fh_tree, tvb, 1, 1, "Control: %02x", ph.ppp_ctl);
1157 next_tvb = tvb_new_subset(tvb, proto_offset, -1, -1);
1159 if (!dissect_ppp_stuff(next_tvb, pinfo, tree, fh_tree)) {
1160 if (check_col(pinfo->fd, COL_PROTOCOL))
1161 col_add_fstr(pinfo->fd, COL_PROTOCOL, "0x%04x", ph.ppp_prot);
1166 proto_register_ppp(void)
1168 /* static hf_register_info hf[] = {
1170 { "Name", "ppp.abbreviation", TYPE, VALS_POINTER }},
1172 static gint *ett[] = {
1176 &ett_ipcp_ipaddrs_opt,
1177 &ett_ipcp_compressprot_opt,
1181 &ett_lcp_async_map_opt,
1182 &ett_lcp_authprot_opt,
1183 &ett_lcp_qualprot_opt,
1184 &ett_lcp_magicnum_opt,
1185 &ett_lcp_fcs_alternatives_opt,
1186 &ett_lcp_numbered_mode_opt,
1187 &ett_lcp_callback_opt,
1188 &ett_lcp_multilink_ep_disc_opt,
1189 &ett_lcp_internationalization_opt,
1192 proto_ppp = proto_register_protocol("Point-to-Point Protocol", "ppp");
1193 /* proto_register_field_array(proto_ppp, hf, array_length(hf));*/
1194 proto_register_subtree_array(ett, array_length(ett));
1196 /* subdissector code */
1197 subdissector_table = register_dissector_table("ppp.protocol");
1199 register_dissector("ppp", dissect_ppp);
1200 register_dissector("payload_ppp", dissect_payload_ppp);
1204 proto_register_mp(void)
1206 static hf_register_info hf[] = {
1207 { &hf_mp_frag_first,
1208 { "First fragment", "mp.first", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1212 { "Last fragment", "mp.last", FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1215 { &hf_mp_sequence_num,
1216 { "Sequence number", "mp.seq", FT_UINT24, BASE_DEC, NULL, 0x0,
1219 static gint *ett[] = {
1224 proto_mp = proto_register_protocol("PPP Multilink Protocol", "mp");
1225 proto_register_field_array(proto_mp, hf, array_length(hf));
1226 proto_register_subtree_array(ett, array_length(ett));