Small patch for the win32 makefile that improves the dependencies and
[obnox/wireshark/wip.git] / packet-ppp.c
1 /* packet-ppp.c
2  * Routines for ppp packet disassembly
3  *
4  * $Id: packet-ppp.c,v 1.37 2000/06/15 03:48:42 gram Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  *
9  * This file created and by Mike Hall <mlh@io.com>
10  * Copyright 1998
11  * 
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.
16  * 
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.
21  * 
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.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #include <glib.h>
36 #include "packet.h"
37 #include "packet-ppp.h"
38 #include "ppptypes.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"
44
45 static int proto_ppp = -1;
46
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;
64
65 static dissector_table_t subdissector_table;
66
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;
71
72 static int ett_mp = -1;
73 static int ett_mp_flags = -1;
74
75 /* PPP structs and definitions */
76
77 typedef struct _e_ppphdr {
78   guint8  ppp_addr;
79   guint8  ppp_ctl;
80   guint16 ppp_prot;
81 } e_ppphdr;
82
83 static const value_string ppp_vals[] = {
84         {PPP_IP,        "IP"             },
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"},
91         {PPP_IPV6,      "IPv6"           },
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" },
102         {0,             NULL            }
103 };
104
105 /* CP (LCP, IPCP, etc.) codes.
106  * from pppd fsm.h 
107  */
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 */
115
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" },
124         {0,          NULL            } };
125
126 /*
127  * LCP-specific packet types.
128  */
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 */
135
136 #define CBCP_OPT  6 /* Use callback control protocol */
137
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" },
152         {0,          NULL }
153 };
154
155 /*
156  * Options.  (LCP)
157  */
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
172                                            Header (RFC 1717) */
173 #define CI_MULTILINK_EP_DISC    19      /* Multilink Endpoint Discriminator
174                                            (RFC 1717) */
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
178                                            (RFC 2125) */
179 #define CI_LCP_AUTHENTICATION   24      /* LCP Authentication Option */
180 #define CI_COBS                 25      /* Consistent Overhead Byte
181                                            Stuffing */
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 */
186
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,
195                         proto_tree *tree);
196 static void dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp,
197                         const u_char *opd, int offset, guint length,
198                         proto_tree *tree);
199 static void dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp,
200                         const u_char *opd, int offset, guint length,
201                         proto_tree *tree);
202 static void dissect_lcp_self_describing_pad_opt(const ip_tcp_opt *optp,
203                         const u_char *opd, int offset, guint length,
204                         proto_tree *tree);
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,
209                         proto_tree *tree);
210 static void dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp,
211                         const u_char *opd, int offset, guint length,
212                         proto_tree *tree);
213 static void dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp,
214                         const u_char *opd, int offset, guint length,
215                         proto_tree *tree);
216 static void dissect_lcp_internationalization_opt(const ip_tcp_opt *optp,
217                         const u_char *opd, int offset, guint length,
218                         proto_tree *tree);
219 static void dissect_mp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
220
221 static const ip_tcp_opt lcp_opts[] = {
222         {
223                 CI_MRU,
224                 "Maximum Receive Unit",
225                 &ett_lcp_mru_opt,
226                 FIXED_LENGTH,
227                 4,
228                 dissect_lcp_mru_opt
229         },
230         {
231                 CI_ASYNCMAP,
232                 "Async Control Character Map",
233                 &ett_lcp_async_map_opt,
234                 FIXED_LENGTH,
235                 6,
236                 dissect_lcp_async_map_opt
237         },
238         {
239                 CI_AUTHTYPE,
240                 "Authentication protocol",
241                 &ett_lcp_authprot_opt,
242                 VARIABLE_LENGTH,
243                 4,
244                 dissect_lcp_protocol_opt
245         },
246         {
247                 CI_QUALITY,
248                 "Quality protocol",
249                 &ett_lcp_qualprot_opt,
250                 VARIABLE_LENGTH,
251                 4,
252                 dissect_lcp_protocol_opt
253         },
254         {
255                 CI_MAGICNUMBER,
256                 NULL,
257                 &ett_lcp_magicnum_opt,
258                 FIXED_LENGTH,
259                 6,
260                 dissect_lcp_magicnumber_opt
261         },
262         {
263                 CI_PCOMPRESSION,
264                 "Protocol field compression",
265                 NULL,
266                 FIXED_LENGTH,
267                 2,
268                 NULL
269         },
270         {
271                 CI_ACCOMPRESSION,
272                 "Address/control field compression",
273                 NULL,
274                 FIXED_LENGTH,
275                 2,
276                 NULL
277         },
278         {
279                 CI_FCS_ALTERNATIVES,
280                 NULL,
281                 &ett_lcp_fcs_alternatives_opt,
282                 FIXED_LENGTH,
283                 3,
284                 dissect_lcp_fcs_alternatives_opt
285         },
286         {
287                 CI_SELF_DESCRIBING_PAD,
288                 NULL,
289                 NULL,
290                 FIXED_LENGTH,
291                 3,
292                 dissect_lcp_self_describing_pad_opt
293         },
294         {
295                 CI_NUMBERED_MODE,
296                 "Numbered mode",
297                 &ett_lcp_numbered_mode_opt,
298                 VARIABLE_LENGTH,
299                 4,
300                 dissect_lcp_numbered_mode_opt
301         },
302         {
303                 CI_CALLBACK,
304                 "Callback",
305                 &ett_lcp_callback_opt,
306                 VARIABLE_LENGTH,
307                 3,
308                 dissect_lcp_callback_opt,
309         },
310         {
311                 CI_COMPOUND_FRAMES,
312                 "Compound frames",
313                 NULL,
314                 FIXED_LENGTH,
315                 2,
316                 NULL
317         },
318         {
319                 CI_MULTILINK_MRRU,
320                 NULL,
321                 NULL,
322                 FIXED_LENGTH,
323                 4,
324                 dissect_lcp_multilink_mrru_opt
325         },
326         {
327                 CI_MULTILINK_SSNH,
328                 "Use short sequence number headers",
329                 NULL,
330                 FIXED_LENGTH,
331                 2,
332                 NULL
333         },
334         {
335                 CI_MULTILINK_EP_DISC,
336                 "Multilink endpoint discriminator",
337                 &ett_lcp_multilink_ep_disc_opt,
338                 VARIABLE_LENGTH,
339                 3,
340                 dissect_lcp_multilink_ep_disc_opt,
341         },
342         {
343                 CI_DCE_IDENTIFIER,
344                 "DCE identifier",
345                 NULL,
346                 VARIABLE_LENGTH,
347                 2,
348                 NULL
349         },
350         {
351                 CI_MULTILINK_PLUS_PROC,
352                 "Multilink Plus Procedure",
353                 NULL,
354                 VARIABLE_LENGTH,
355                 2,
356                 NULL
357         },
358         {
359                 CI_LINK_DISC_FOR_BACP,
360                 NULL,
361                 NULL,
362                 FIXED_LENGTH,
363                 4,
364                 dissect_lcp_bap_link_discriminator_opt
365         },
366         {
367                 CI_LCP_AUTHENTICATION,
368                 "LCP authentication",
369                 NULL,
370                 VARIABLE_LENGTH,
371                 2,
372                 NULL
373         },
374         {
375                 CI_COBS,
376                 "Consistent Overhead Byte Stuffing",
377                 NULL,
378                 VARIABLE_LENGTH,
379                 2,
380                 NULL
381         },
382         {
383                 CI_PREFIX_ELISION,
384                 "Prefix elision",
385                 NULL,
386                 VARIABLE_LENGTH,
387                 2,
388                 NULL
389         },
390         {
391                 CI_MULTILINK_HDR_FMT,
392                 "Multilink header format",
393                 NULL,
394                 VARIABLE_LENGTH,
395                 2,
396                 NULL
397         },
398         {
399                 CI_INTERNATIONALIZATION,
400                 "Internationalization",
401                 &ett_lcp_internationalization_opt,
402                 VARIABLE_LENGTH,
403                 7,
404                 dissect_lcp_internationalization_opt
405         },
406         {
407                 CI_SDL_ON_SONET_SDH,
408                 "Simple data link on SONET/SDH",
409                 NULL,
410                 VARIABLE_LENGTH,
411                 2,
412                 NULL
413         }
414 };
415
416 #define N_LCP_OPTS      (sizeof lcp_opts / sizeof lcp_opts[0])
417
418 /*
419  * Options.  (IPCP)
420  */
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) */
429
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);
434
435 static const ip_tcp_opt ipcp_opts[] = {
436         {
437                 CI_ADDRS,
438                 "IP addresses (deprecated)",
439                 &ett_ipcp_ipaddrs_opt,
440                 FIXED_LENGTH,
441                 10,
442                 dissect_ipcp_addrs_opt
443         },
444         {
445                 CI_COMPRESSTYPE,
446                 "IP compression protocol",
447                 &ett_ipcp_compressprot_opt,
448                 VARIABLE_LENGTH,
449                 4,
450                 dissect_lcp_protocol_opt
451         },
452         {
453                 CI_ADDR,
454                 "IP address",
455                 NULL,
456                 FIXED_LENGTH,
457                 6,
458                 dissect_ipcp_addr_opt
459         },
460         {
461                 CI_MOBILE_IPv4,
462                 "Mobile node's home IP address",
463                 NULL,
464                 FIXED_LENGTH,
465                 6,
466                 dissect_ipcp_addr_opt
467         },
468         {
469                 CI_MS_DNS1,
470                 "Primary DNS server IP address",
471                 NULL,
472                 FIXED_LENGTH,
473                 6,
474                 dissect_ipcp_addr_opt
475         },
476         {
477                 CI_MS_WINS1,
478                 "Primary WINS server IP address",
479                 NULL,
480                 FIXED_LENGTH,
481                 6,
482                 dissect_ipcp_addr_opt
483         },
484         {
485                 CI_MS_DNS2,
486                 "Secondary DNS server IP address",
487                 NULL,
488                 FIXED_LENGTH,
489                 6,
490                 dissect_ipcp_addr_opt
491         },
492         {
493                 CI_MS_WINS2,
494                 "Secondary WINS server IP address",
495                 NULL,
496                 FIXED_LENGTH,
497                 6,
498                 dissect_ipcp_addr_opt
499         }
500 };
501
502 #define N_IPCP_OPTS     (sizeof ipcp_opts / sizeof ipcp_opts[0])
503
504 void
505 capture_ppp( const u_char *pd, int offset, packet_counts *ld ) {
506   switch (pntohs(&pd[offset + 2])) {
507     case PPP_IP:
508       capture_ip(pd, offset + 4, ld);
509       break;
510     case PPP_IPX:
511       capture_ipx(pd, offset + 4, ld);
512       break;
513     case PPP_VINES:
514       capture_vines(pd, offset + 4, ld);
515       break;
516     default:
517       ld->other++;
518       break;
519   }
520 }
521
522 static void
523 dissect_lcp_mru_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
524                         guint length, proto_tree *tree)
525 {
526   proto_tree_add_text(tree, NullTVB, offset, length, "MRU: %u", pntohs(opd));
527 }
528
529 static void
530 dissect_lcp_async_map_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
531                         guint length, proto_tree *tree)
532 {
533   proto_tree_add_text(tree, NullTVB, offset, length, "Async characters to map: 0x%08x",
534                         pntohl(opd));
535 }
536
537 static void
538 dissect_lcp_protocol_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
539                         guint length, proto_tree *tree)
540 {
541   guint16 protocol;
542   proto_item *tf;
543   proto_tree *field_tree = NULL;
544   
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);
548   offset += 2;
549   length -= 2;
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);
553   offset += 2;
554   opd += 2;
555   length -= 2;
556   if (length > 0)
557     proto_tree_add_text(field_tree, NullTVB, offset, length, "Data (%d byte%s)", length,
558                         plurality(length, "", "s"));
559 }
560
561 static void
562 dissect_lcp_magicnumber_opt(const ip_tcp_opt *optp, const u_char *opd,
563                         int offset, guint length, proto_tree *tree)
564 {
565   proto_tree_add_text(tree, NullTVB, offset, length, "Magic number: 0x%08x",
566                         pntohl(opd));
567 }
568
569 static void
570 dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp, const u_char *opd,
571                         int offset, guint length, proto_tree *tree)
572 {
573   proto_item *tf;
574   proto_tree *field_tree = NULL;
575   guint8 alternatives;
576   
577   alternatives = *opd;
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);
581   offset += 2;
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));
591 }
592
593 static void
594 dissect_lcp_self_describing_pad_opt(const ip_tcp_opt *optp, const u_char *opd,
595                         int offset, guint length, proto_tree *tree)
596 {
597   proto_tree_add_text(tree, NullTVB, offset, length,
598                         "Maximum octets of self-describing padding: %u",
599                         *opd);
600 }
601
602 static void
603 dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp, const u_char *opd,
604                         int offset, guint length, proto_tree *tree)
605 {
606   proto_item *tf;
607   proto_tree *field_tree = NULL;
608   
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);
612   offset += 2;
613   length -= 2;
614   proto_tree_add_text(field_tree, NullTVB, offset, 1, "Window: %u", *opd);
615   offset += 1;
616   opd += 1;
617   length -= 1;
618   if (length > 0)
619     proto_tree_add_text(field_tree, NullTVB, offset, length, "Address (%d byte%s)",
620                         length, plurality(length, "", "s"));
621 }
622
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" },
629         {0, NULL }
630 };
631
632 static void
633 dissect_lcp_callback_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
634                         guint length, proto_tree *tree)
635 {
636   proto_item *tf;
637   proto_tree *field_tree = NULL;
638   
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);
642   offset += 2;
643   length -= 2;
644   proto_tree_add_text(field_tree, NullTVB, offset, 1, "Operation: %s (0x%02x)",
645                 val_to_str(*opd, callback_op_vals, "Unknown"),
646                 *opd);
647   offset += 1;
648   opd += 1;
649   length -= 1;
650   if (length > 0)
651     proto_tree_add_text(field_tree, NullTVB, offset, length, "Message (%d byte%s)",
652                         length, plurality(length, "", "s"));
653 }
654
655 static void
656 dissect_lcp_multilink_mrru_opt(const ip_tcp_opt *optp, const u_char *opd,
657                         int offset, guint length, proto_tree *tree)
658 {
659   proto_tree_add_text(tree, NullTVB, offset, length, "Multilink MRRU: %u",
660                         pntohs(opd));
661 }
662
663 #define CLASS_NULL                      0
664 #define CLASS_LOCAL                     1
665 #define CLASS_IP                        2
666 #define CLASS_IEEE_802_1                3
667 #define CLASS_PPP_MAGIC_NUMBER          4
668 #define CLASS_PSDN_DIRECTORY_NUMBER     5
669
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" },
677         {0,                           NULL }
678 };
679
680 static void
681 dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp, const u_char *opd,
682                         int offset, guint length, proto_tree *tree)
683 {
684   proto_item *tf;
685   proto_tree *field_tree = NULL;
686   guint8 ep_disc_class;
687
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);
691   offset += 2;
692   length -= 2;
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"),
696                 ep_disc_class);
697   offset += 1;
698   opd += 1;
699   length -= 1;
700   if (length > 0) {
701     switch (ep_disc_class) {
702
703     case CLASS_NULL:
704       proto_tree_add_text(field_tree, NullTVB, offset, length,
705                         "Address (%d byte%s), should have been empty",
706                         length, plurality(length, "", "s"));
707       break;
708
709     case CLASS_LOCAL:
710       if (length > 20) {
711         proto_tree_add_text(field_tree, NullTVB, offset, length,
712                         "Address (%d byte%s), should have been <20",
713                         length, plurality(length, "", "s"));
714       } else {
715         proto_tree_add_text(field_tree, NullTVB, offset, length,
716                         "Address (%d byte%s)",
717                         length, plurality(length, "", "s"));
718       }
719       break;
720
721     case CLASS_IP:
722       if (length != 4) {
723         proto_tree_add_text(field_tree, NullTVB, offset, length,
724                         "Address (%d byte%s), should have been 4",
725                         length, plurality(length, "", "s"));
726       } else {
727         proto_tree_add_text(field_tree, NullTVB, offset, length,
728                         "Address: %s", ip_to_str(opd));
729       }
730       break;
731
732     case CLASS_IEEE_802_1:
733       if (length != 6) {
734         proto_tree_add_text(field_tree, NullTVB, offset, length,
735                         "Address (%d byte%s), should have been 6",
736                         length, plurality(length, "", "s"));
737       } else {
738         proto_tree_add_text(field_tree, NullTVB, offset, length,
739                         "Address: %s", ether_to_str(opd));
740       }
741       break;
742
743     case CLASS_PPP_MAGIC_NUMBER:
744       /* XXX - dissect as 32-bit magic numbers */
745       if (length > 20) {
746         proto_tree_add_text(field_tree, NullTVB, offset, length,
747                         "Address (%d byte%s), should have been <20",
748                         length, plurality(length, "", "s"));
749       } else {
750         proto_tree_add_text(field_tree, NullTVB, offset, length,
751                         "Address (%d byte%s)",
752                         length, plurality(length, "", "s"));
753       }
754       break;
755
756     case CLASS_PSDN_DIRECTORY_NUMBER:
757       if (length > 15) {
758         proto_tree_add_text(field_tree, NullTVB, offset, length,
759                         "Address (%d byte%s), should have been <20",
760                         length, plurality(length, "", "s"));
761       } else {
762         proto_tree_add_text(field_tree, NullTVB, offset, length,
763                         "Address (%d byte%s)",
764                         length, plurality(length, "", "s"));
765       }
766       break;
767
768     default:
769       proto_tree_add_text(field_tree, NullTVB, offset, length,
770                         "Address (%d byte%s)",
771                         length, plurality(length, "", "s"));
772       break;
773     }
774   }
775 }
776
777 static void
778 dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp, const u_char *opd,
779                         int offset, guint length, proto_tree *tree)
780 {
781   proto_tree_add_text(tree, NullTVB, offset, length,
782                         "Link discriminator for BAP: 0x%04x",
783                         pntohs(opd));
784 }
785
786 /* Character set numbers from the IANA charset registry. */
787 static const value_string charset_num_vals[] = {
788         {105, "UTF-8" },
789         {0,   NULL }
790 };
791
792 static void
793 dissect_lcp_internationalization_opt(const ip_tcp_opt *optp, const u_char *opd,
794                         int offset, guint length, proto_tree *tree)
795 {
796   proto_item *tf;
797   proto_tree *field_tree = NULL;
798   
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);
802   offset += 2;
803   length -= 2;
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"),
806                 pntohl(opd));
807   offset += 4;
808   opd += 4;
809   length -= 4;
810   if (length > 0) {
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"));
814   }
815 }
816
817 static void
818 dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, const u_char *opd,
819                         int offset, guint length, proto_tree *tree)
820 {
821   proto_item *tf;
822   proto_tree *field_tree = NULL;
823   
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);
827   offset += 2;
828   length -= 2;
829   proto_tree_add_text(field_tree, NullTVB, offset, 4,
830                         "Source IP address: %s", ip_to_str(opd));
831   offset += 4;
832   opd += 4;
833   length -= 4;
834   proto_tree_add_text(field_tree, NullTVB, offset, 4,
835                         "Destination IP address: %s", ip_to_str(opd));
836 }
837
838 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, const u_char *opd,
839                         int offset, guint length, proto_tree *tree)
840 {
841   proto_tree_add_text(tree, NullTVB, offset, length, "%s: %s", optp->name,
842                         ip_to_str((guint8 *)opd));
843 }
844
845 static void
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 ) {
850   proto_item *ti;
851   proto_tree *fh_tree = NULL;
852   proto_item *tf;
853   proto_tree *field_tree;
854
855   guint8 code;
856   guint8 id;
857   int length, offset;
858   guint16 protocol;
859
860   code = tvb_get_guint8(tvb, 0);
861   id = tvb_get_guint8(tvb, 1);
862   length = tvb_get_ntohs(tvb, 2);
863
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"));
867
868   if(tree) {
869     ti = proto_tree_add_text(tree, tvb, 0, 4, "%s Control Protocol",
870                                 proto_long_name);
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",
875                         id);
876     proto_tree_add_text(fh_tree, tvb, 2, 2, "Length: %u",
877                         length);
878   }
879   offset = 4;
880   length -= 4;
881
882   switch (code) {
883     case CONFREQ:
884     case CONFACK:
885     case CONFNAK:
886     case CONFREJ:
887       if(tree) {
888         if (length > 0) {
889           const guint8  *this_pd;
890           int           this_offset;
891
892           tvb_compat(tvb, &this_pd, &this_offset);
893
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);
899         }
900       }
901       break;
902
903     case ECHOREQ:
904     case ECHOREP:
905     case DISCREQ:
906     case IDENT:
907       if(tree) {
908         proto_tree_add_text(fh_tree, tvb, offset, 4, "Magic number: 0x%08x",
909                         tvb_get_ntohl(tvb, offset));
910         offset += 4;
911         length -= 4;
912         if (length > 0)
913           proto_tree_add_text(fh_tree, tvb, offset, length, "Message (%d byte%s)",
914                                 length, plurality(length, "", "s"));
915       }
916       break;
917
918     case TIMEREMAIN:
919       if(tree) {
920         proto_tree_add_text(fh_tree, tvb, offset, 4, "Magic number: 0x%08x",
921                         tvb_get_ntohl(tvb, offset));
922         offset += 4;
923         length -= 4;
924         proto_tree_add_text(fh_tree, tvb, offset, 4, "Seconds remaining: %u",
925                         tvb_get_ntohl(tvb, offset));
926         offset += 4;
927         length -= 4;
928         if (length > 0)
929           proto_tree_add_text(fh_tree, tvb, offset, length, "Message (%d byte%s)",
930                                 length, plurality(length, "", "s"));
931       }
932       break;
933
934     case PROTREJ:
935       if(tree) {
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);
939         offset += 2;
940         length -= 2;
941         if (length > 0)
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 */
945       }
946       break;
947
948     case CODEREJ:
949                 /* decode the rejected LCP packet here. */
950       if (length > 0)
951         proto_tree_add_text(fh_tree, tvb, offset, length, "Rejected packet (%d byte%s)",
952                                 length, plurality(length, "", "s"));
953       break;
954
955     case TERMREQ:
956     case TERMACK:
957       if (length > 0)
958         proto_tree_add_text(fh_tree, tvb, offset, length, "Data (%d byte%s)",
959                                 length, plurality(length, "", "s"));
960       break;
961
962     default:
963       if (length > 0)
964         proto_tree_add_text(fh_tree, tvb, offset, length, "Stuff (%d byte%s)",
965                                 length, plurality(length, "", "s"));
966       break;
967   }
968 }
969
970 /* Protocol field compression */
971 #define PFC_BIT 0x01
972
973 static gboolean
974 dissect_ppp_stuff( tvbuff_t *tvb, packet_info *pinfo,
975                 proto_tree *tree, proto_tree *fh_tree ) {
976   guint16 ppp_prot;
977   int     proto_len;
978   tvbuff_t      *next_tvb;
979   const guint8  *next_pd;
980   int           next_offset;
981
982   if (tvb_get_guint8(tvb, 0) & PFC_BIT) {
983     ppp_prot = tvb_get_guint8(tvb, 0);
984     proto_len = 1;
985   } else {
986     ppp_prot = tvb_get_ntohs(tvb, 0);
987     proto_len = 2;
988   }
989
990   if (tree) {
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);
993   }
994
995   next_tvb = tvb_new_subset(tvb, proto_len, -1, -1);
996   tvb_compat(next_tvb, &next_pd, &next_offset);
997
998   /* do lookup with the subdissector table */
999   if (dissector_try_port(subdissector_table, ppp_prot, next_pd, next_offset, pinfo->fd, tree))
1000       return TRUE;
1001
1002   /* XXX - make "dissect_lcp()" and "dissect_ipcp()", have them just
1003      call "dissect_cp()", and register them as well?
1004
1005      We can do that for "dissect_mp()", too. */
1006   switch (ppp_prot) {
1007     case PPP_MP:
1008       dissect_mp(next_tvb, pinfo, tree);
1009       return TRUE;
1010     case PPP_LCP:
1011       dissect_cp(next_tvb, "L", "Link", ett_lcp, lcp_vals, ett_lcp_options,
1012                 lcp_opts, N_LCP_OPTS, pinfo, tree);
1013       return TRUE;
1014     case PPP_IPCP:
1015       dissect_cp(next_tvb, "IP", "IP", ett_ipcp, cp_vals, ett_ipcp_options,
1016                 ipcp_opts, N_IPCP_OPTS, pinfo, tree);
1017       return TRUE;
1018     default:
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);
1023       return FALSE;
1024   }
1025 }
1026
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
1032
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
1037  */
1038 static void
1039 dissect_mp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1040 {
1041   proto_tree *mp_tree, *hdr_tree, *fh_tree = NULL;
1042   proto_item *ti;
1043   guint8      flags;
1044   guint32     seq;
1045   gchar       *flag_str;
1046   int         first, last;
1047   tvbuff_t      *next_tvb;
1048
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);
1053
1054   if (check_col(pinfo->fd, COL_INFO))
1055     col_add_fstr(pinfo->fd, COL_INFO, "PPP Multilink");
1056
1057   if (tree) {
1058     switch (flags) {
1059       case MP_FRAG_FIRST:
1060         flag_str = "First";
1061         break;
1062       case MP_FRAG_LAST:
1063         flag_str = "Last";
1064         break;
1065       case MP_FRAG_FIRST|MP_FRAG_LAST:
1066         flag_str = "First, Last";
1067         break;
1068       default:
1069         flag_str = "Unknown";
1070         break;
1071     }
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)",
1075       flags, flag_str);
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);
1087  }
1088
1089   next_tvb = tvb_new_subset(tvb, 4, -1, -1);
1090
1091   if (tvb_length(next_tvb) > 0) {
1092           if (tree) {
1093             ti = proto_tree_add_item(tree, proto_ppp, next_tvb, 0, 1, FALSE);
1094             fh_tree = proto_item_add_subtree(ti, ett_ppp);
1095           }
1096           dissect_ppp_stuff(next_tvb, pinfo, tree, fh_tree);
1097   }
1098 }
1099
1100 void
1101 dissect_payload_ppp( const u_char *pd, int offset, frame_data *fd, proto_tree *tree ) {
1102   proto_item *ti;
1103   proto_tree *fh_tree = NULL;
1104   tvbuff_t   *next_tvb;
1105
1106   /* populate a tree in the second pane with the status of the link
1107      layer (ie none) */
1108   if(tree) {
1109     ti = proto_tree_add_item(tree, proto_ppp, NullTVB, 0+offset, 2, FALSE);
1110     fh_tree = proto_item_add_subtree(ti, ett_ppp);
1111   }
1112
1113   next_tvb = tvb_create_from_top(offset);
1114   dissect_ppp_stuff(next_tvb, &pi, tree, fh_tree);
1115 }
1116
1117 void
1118 dissect_ppp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
1119   e_ppphdr   ph;
1120   proto_item *ti;
1121   proto_tree *fh_tree = NULL;
1122   int        proto_offset;
1123   tvbuff_t   *next_tvb;
1124   guint8     byte0;
1125
1126   pinfo->current_proto = "PPP";
1127   byte0 = tvb_get_guint8(tvb, 0);
1128
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);
1133     proto_offset =  2;
1134   }
1135   else {
1136     /* address and control are compressed (NULL) */
1137     ph.ppp_prot = tvb_get_ntohs(tvb, 0);
1138     proto_offset = 0;
1139   }
1140
1141   /* load the top pane info. This should be overwritten by
1142      the next protocol in the stack */
1143
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" );
1150
1151   /* populate a tree in the second pane with the status of the link
1152      layer (ie none) */
1153   if(tree) {
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);
1159     }
1160   }
1161
1162   next_tvb = tvb_new_subset(tvb, proto_offset, -1, -1);
1163
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);
1167   }
1168 }
1169
1170 void
1171 proto_register_ppp(void)
1172 {
1173 /*        static hf_register_info hf[] = {
1174                 { &variable,
1175                 { "Name",           "ppp.abbreviation", TYPE, VALS_POINTER }},
1176         };*/
1177         static gint *ett[] = {
1178                 &ett_ppp,
1179                 &ett_ipcp,
1180                 &ett_ipcp_options,
1181                 &ett_ipcp_ipaddrs_opt,
1182                 &ett_ipcp_compressprot_opt,
1183                 &ett_lcp,
1184                 &ett_lcp_options,
1185                 &ett_lcp_mru_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,
1195         };
1196
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));
1200
1201 /* subdissector code */
1202         subdissector_table = register_dissector_table("ppp.protocol");
1203 }
1204
1205 void
1206 proto_register_mp(void)
1207 {
1208   static hf_register_info hf[] = {
1209     { &hf_mp_frag_first,
1210     { "First fragment",         "mp.first",     FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1211         "" }},
1212
1213     { &hf_mp_frag_last,
1214     { "Last fragment",          "mp.last",      FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1215         "" }},
1216
1217     { &hf_mp_sequence_num,
1218     { "Sequence number",        "mp.seq",       FT_UINT24, BASE_DEC, NULL, 0x0,
1219         "" }}
1220   };
1221   static gint *ett[] = {
1222     &ett_mp,
1223     &ett_mp_flags,
1224   };
1225
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));
1229 }