Add comments about nettl support.
[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.28 2000/02/15 21:02:51 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-atalk.h"
38 #include "packet-ip.h"
39 #include "packet-ipv6.h"
40 #include "packet-ipx.h"
41 #include "packet-vines.h"
42
43 static int proto_ppp = -1;
44
45 static gint ett_ppp = -1;
46 static gint ett_ipcp = -1;
47 static gint ett_ipcp_options = -1;
48 static gint ett_ipcp_ipaddrs_opt = -1;
49 static gint ett_ipcp_compressprot_opt = -1;
50 static gint ett_lcp = -1;
51 static gint ett_lcp_options = -1;
52 static gint ett_lcp_mru_opt = -1;
53 static gint ett_lcp_async_map_opt = -1;
54 static gint ett_lcp_authprot_opt = -1;
55 static gint ett_lcp_qualprot_opt = -1;
56 static gint ett_lcp_magicnum_opt = -1;
57 static gint ett_lcp_fcs_alternatives_opt = -1;
58 static gint ett_lcp_numbered_mode_opt = -1;
59 static gint ett_lcp_callback_opt = -1;
60 static gint ett_lcp_multilink_ep_disc_opt = -1;
61 static gint ett_lcp_internationalization_opt = -1;
62
63 static int proto_mp = -1;
64 static int hf_mp_frag_first = -1;
65 static int hf_mp_frag_last = -1;
66 static int hf_mp_sequence_num = -1;
67
68 static int ett_mp = -1;
69 static int ett_mp_flags = -1;
70
71 /* PPP structs and definitions */
72
73 typedef struct _e_ppphdr {
74   guint8  ppp_addr;
75   guint8  ppp_ctl;
76   guint16 ppp_prot;
77 } e_ppphdr;
78
79
80 /* Protocol types, from Linux "ppp_defs.h" and
81
82         http://www.isi.edu/in-notes/iana/assignments/ppp-numbers
83
84  */
85 #define PPP_IP          0x21    /* Internet Protocol */
86 #define PPP_AT          0x29    /* AppleTalk Protocol */
87 #define PPP_IPX         0x2b    /* IPX protocol */
88 #define PPP_VJC_COMP    0x2d    /* VJ compressed TCP */
89 #define PPP_VJC_UNCOMP  0x2f    /* VJ uncompressed TCP */
90 #define PPP_VINES       0x35    /* Banyan Vines */
91 #define PPP_MP          0x3d    /* Multilink PPP */
92 #define PPP_IPV6        0x57    /* Internet Protocol Version 6 */
93 #define PPP_COMP        0xfd    /* compressed packet */
94 #define PPP_IPCP        0x8021  /* IP Control Protocol */
95 #define PPP_ATCP        0x8029  /* AppleTalk Control Protocol */
96 #define PPP_IPXCP       0x802b  /* IPX Control Protocol */
97 #define PPP_CCP         0x80fd  /* Compression Control Protocol */
98 #define PPP_LCP         0xc021  /* Link Control Protocol */
99 #define PPP_PAP         0xc023  /* Password Authentication Protocol */
100 #define PPP_LQR         0xc025  /* Link Quality Report protocol */
101 #define PPP_CHAP        0xc223  /* Cryptographic Handshake Auth. Protocol */
102 #define PPP_CBCP        0xc029  /* Callback Control Protocol */
103
104 static const value_string ppp_vals[] = {
105         {PPP_IP,        "IP"             },
106         {PPP_AT,        "Appletalk"      },
107         {PPP_IPX,       "Netware IPX/SPX"},
108         {PPP_VJC_COMP,  "VJ compressed TCP"},
109         {PPP_VJC_UNCOMP,"VJ uncompressed TCP"}, 
110         {PPP_VINES,     "Vines"          },
111         {PPP_MP,        "Multilink"},
112         {PPP_IPV6,      "IPv6"           },
113         {PPP_COMP,      "compressed packet" },
114         {PPP_IPCP,      "IP Control Protocol" },
115         {PPP_ATCP,      "AppleTalk Control Protocol" },
116         {PPP_IPXCP,     "IPX Control Protocol" },
117         {PPP_CCP,       "Compression Control Protocol" },
118         {PPP_LCP,       "Link Control Protocol" },
119         {PPP_PAP,       "Password Authentication Protocol"  },
120         {PPP_LQR,       "Link Quality Report protocol" },
121         {PPP_CHAP,      "Cryptographic Handshake Auth. Protocol" },
122         {PPP_CBCP,      "Callback Control Protocol" },
123         {0,             NULL            }
124 };
125
126 /* CP (LCP, IPCP, etc.) codes.
127  * from pppd fsm.h 
128  */
129 #define CONFREQ    1  /* Configuration Request */
130 #define CONFACK    2  /* Configuration Ack */
131 #define CONFNAK    3  /* Configuration Nak */
132 #define CONFREJ    4  /* Configuration Reject */
133 #define TERMREQ    5  /* Termination Request */
134 #define TERMACK    6  /* Termination Ack */
135 #define CODEREJ    7  /* Code Reject */
136
137 static const value_string cp_vals[] = {
138         {CONFREQ,    "Configuration Request" },
139         {CONFACK,    "Configuration Ack" },
140         {CONFNAK,    "Configuration Nak" },
141         {CONFREJ,    "Configuration Reject" },
142         {TERMREQ,    "Termination Request" },
143         {TERMACK,    "Termination Ack" },
144         {CODEREJ,    "Code Reject" },
145         {0,          NULL            } };
146
147 /*
148  * LCP-specific packet types.
149  */
150 #define PROTREJ    8  /* Protocol Reject */
151 #define ECHOREQ    9  /* Echo Request */
152 #define ECHOREP    10 /* Echo Reply */
153 #define DISCREQ    11 /* Discard Request */
154 #define IDENT      12 /* Identification */
155 #define TIMEREMAIN 13 /* Time remaining */
156
157 #define CBCP_OPT  6 /* Use callback control protocol */
158
159 static const value_string lcp_vals[] = {
160         {CONFREQ,    "Configuration Request" },
161         {CONFACK,    "Configuration Ack" },
162         {CONFNAK,    "Configuration Nak" },
163         {CONFREJ,    "Configuration Reject" },
164         {TERMREQ,    "Termination Request" },
165         {TERMACK,    "Termination Ack" },
166         {CODEREJ,    "Code Reject" },
167         {PROTREJ,    "Protocol Reject" },
168         {ECHOREQ,    "Echo Request" },
169         {ECHOREP,    "Echo Reply" },
170         {DISCREQ,    "Discard Request" },
171         {IDENT,      "Identification" },
172         {TIMEREMAIN, "Time Remaining" },
173         {0,          NULL }
174 };
175
176 /*
177  * Options.  (LCP)
178  */
179 #define CI_MRU                  1       /* Maximum Receive Unit */
180 #define CI_ASYNCMAP             2       /* Async Control Character Map */
181 #define CI_AUTHTYPE             3       /* Authentication Type */
182 #define CI_QUALITY              4       /* Quality Protocol */
183 #define CI_MAGICNUMBER          5       /* Magic Number */
184 #define CI_PCOMPRESSION         7       /* Protocol Field Compression */
185 #define CI_ACCOMPRESSION        8       /* Address/Control Field Compression */
186 #define CI_FCS_ALTERNATIVES     9       /* FCS Alternatives (RFC 1570) */
187 #define CI_SELF_DESCRIBING_PAD  10      /* Self-Describing Pad (RFC 1570) */
188 #define CI_NUMBERED_MODE        11      /* Numbered Mode (RFC 1663) */
189 #define CI_CALLBACK             13      /* Callback (RFC 1570) */
190 #define CI_COMPOUND_FRAMES      15      /* Compound frames (RFC 1570) */
191 #define CI_MULTILINK_MRRU       17      /* Multilink MRRU (RFC 1717) */
192 #define CI_MULTILINK_SSNH       18      /* Multilink Short Sequence Number
193                                            Header (RFC 1717) */
194 #define CI_MULTILINK_EP_DISC    19      /* Multilink Endpoint Discriminator
195                                            (RFC 1717) */
196 #define CI_DCE_IDENTIFIER       21      /* DCE Identifier */
197 #define CI_MULTILINK_PLUS_PROC  22      /* Multilink Plus Procedure */
198 #define CI_LINK_DISC_FOR_BACP   23      /* Link Discriminator for BACP
199                                            (RFC 2125) */
200 #define CI_LCP_AUTHENTICATION   24      /* LCP Authentication Option */
201 #define CI_COBS                 25      /* Consistent Overhead Byte
202                                            Stuffing */
203 #define CI_PREFIX_ELISION       26      /* Prefix elision */
204 #define CI_MULTILINK_HDR_FMT    27      /* Multilink header format */
205 #define CI_INTERNATIONALIZATION 28      /* Internationalization (RFC 2484) */
206 #define CI_SDL_ON_SONET_SDH     29      /* Simple Data Link on SONET/SDH */
207
208 static void dissect_lcp_mru_opt(const ip_tcp_opt *optp, const u_char *opd,
209                         int offset, guint length, proto_tree *tree);
210 static void dissect_lcp_async_map_opt(const ip_tcp_opt *optp, const u_char *opd,
211                         int offset, guint length, proto_tree *tree);
212 static void dissect_lcp_protocol_opt(const ip_tcp_opt *optp, const u_char *opd,
213                         int offset, guint length, proto_tree *tree);
214 static void dissect_lcp_magicnumber_opt(const ip_tcp_opt *optp,
215                         const u_char *opd, int offset, guint length,
216                         proto_tree *tree);
217 static void dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp,
218                         const u_char *opd, int offset, guint length,
219                         proto_tree *tree);
220 static void dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp,
221                         const u_char *opd, int offset, guint length,
222                         proto_tree *tree);
223 static void dissect_lcp_self_describing_pad_opt(const ip_tcp_opt *optp,
224                         const u_char *opd, int offset, guint length,
225                         proto_tree *tree);
226 static void dissect_lcp_callback_opt(const ip_tcp_opt *optp, const u_char *opd,
227                         int offset, guint length, proto_tree *tree);
228 static void dissect_lcp_multilink_mrru_opt(const ip_tcp_opt *optp,
229                         const u_char *opd, int offset, guint length,
230                         proto_tree *tree);
231 static void dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp,
232                         const u_char *opd, int offset, guint length,
233                         proto_tree *tree);
234 static void dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp,
235                         const u_char *opd, int offset, guint length,
236                         proto_tree *tree);
237 static void dissect_lcp_internationalization_opt(const ip_tcp_opt *optp,
238                         const u_char *opd, int offset, guint length,
239                         proto_tree *tree);
240 static void dissect_mp(const u_char *pd, int offset, frame_data *fd,
241   proto_tree *tree, proto_tree *fh_tree);
242
243 static const ip_tcp_opt lcp_opts[] = {
244         {
245                 CI_MRU,
246                 "Maximum Receive Unit",
247                 &ett_lcp_mru_opt,
248                 FIXED_LENGTH,
249                 4,
250                 dissect_lcp_mru_opt
251         },
252         {
253                 CI_ASYNCMAP,
254                 "Async Control Character Map",
255                 &ett_lcp_async_map_opt,
256                 FIXED_LENGTH,
257                 6,
258                 dissect_lcp_async_map_opt
259         },
260         {
261                 CI_AUTHTYPE,
262                 "Authentication protocol",
263                 &ett_lcp_authprot_opt,
264                 VARIABLE_LENGTH,
265                 4,
266                 dissect_lcp_protocol_opt
267         },
268         {
269                 CI_QUALITY,
270                 "Quality protocol",
271                 &ett_lcp_qualprot_opt,
272                 VARIABLE_LENGTH,
273                 4,
274                 dissect_lcp_protocol_opt
275         },
276         {
277                 CI_MAGICNUMBER,
278                 NULL,
279                 &ett_lcp_magicnum_opt,
280                 FIXED_LENGTH,
281                 6,
282                 dissect_lcp_magicnumber_opt
283         },
284         {
285                 CI_PCOMPRESSION,
286                 "Protocol field compression",
287                 NULL,
288                 FIXED_LENGTH,
289                 2,
290                 NULL
291         },
292         {
293                 CI_ACCOMPRESSION,
294                 "Address/control field compression",
295                 NULL,
296                 FIXED_LENGTH,
297                 2,
298                 NULL
299         },
300         {
301                 CI_FCS_ALTERNATIVES,
302                 NULL,
303                 &ett_lcp_fcs_alternatives_opt,
304                 FIXED_LENGTH,
305                 3,
306                 dissect_lcp_fcs_alternatives_opt
307         },
308         {
309                 CI_SELF_DESCRIBING_PAD,
310                 NULL,
311                 NULL,
312                 FIXED_LENGTH,
313                 3,
314                 dissect_lcp_self_describing_pad_opt
315         },
316         {
317                 CI_NUMBERED_MODE,
318                 "Numbered mode",
319                 &ett_lcp_numbered_mode_opt,
320                 VARIABLE_LENGTH,
321                 4,
322                 dissect_lcp_numbered_mode_opt
323         },
324         {
325                 CI_CALLBACK,
326                 "Callback",
327                 &ett_lcp_callback_opt,
328                 VARIABLE_LENGTH,
329                 3,
330                 dissect_lcp_callback_opt,
331         },
332         {
333                 CI_COMPOUND_FRAMES,
334                 "Compound frames",
335                 NULL,
336                 FIXED_LENGTH,
337                 2,
338                 NULL
339         },
340         {
341                 CI_MULTILINK_MRRU,
342                 NULL,
343                 NULL,
344                 FIXED_LENGTH,
345                 4,
346                 dissect_lcp_multilink_mrru_opt
347         },
348         {
349                 CI_MULTILINK_SSNH,
350                 "Use short sequence number headers",
351                 NULL,
352                 FIXED_LENGTH,
353                 2,
354                 NULL
355         },
356         {
357                 CI_MULTILINK_EP_DISC,
358                 "Multilink endpoint discriminator",
359                 &ett_lcp_multilink_ep_disc_opt,
360                 VARIABLE_LENGTH,
361                 3,
362                 dissect_lcp_multilink_ep_disc_opt,
363         },
364         {
365                 CI_DCE_IDENTIFIER,
366                 "DCE identifier",
367                 NULL,
368                 VARIABLE_LENGTH,
369                 2,
370                 NULL
371         },
372         {
373                 CI_MULTILINK_PLUS_PROC,
374                 "Multilink Plus Procedure",
375                 NULL,
376                 VARIABLE_LENGTH,
377                 2,
378                 NULL
379         },
380         {
381                 CI_LINK_DISC_FOR_BACP,
382                 NULL,
383                 NULL,
384                 FIXED_LENGTH,
385                 4,
386                 dissect_lcp_bap_link_discriminator_opt
387         },
388         {
389                 CI_LCP_AUTHENTICATION,
390                 "LCP authentication",
391                 NULL,
392                 VARIABLE_LENGTH,
393                 2,
394                 NULL
395         },
396         {
397                 CI_COBS,
398                 "Consistent Overhead Byte Stuffing",
399                 NULL,
400                 VARIABLE_LENGTH,
401                 2,
402                 NULL
403         },
404         {
405                 CI_PREFIX_ELISION,
406                 "Prefix elision",
407                 NULL,
408                 VARIABLE_LENGTH,
409                 2,
410                 NULL
411         },
412         {
413                 CI_MULTILINK_HDR_FMT,
414                 "Multilink header format",
415                 NULL,
416                 VARIABLE_LENGTH,
417                 2,
418                 NULL
419         },
420         {
421                 CI_INTERNATIONALIZATION,
422                 "Internationalization",
423                 &ett_lcp_internationalization_opt,
424                 VARIABLE_LENGTH,
425                 7,
426                 dissect_lcp_internationalization_opt
427         },
428         {
429                 CI_SDL_ON_SONET_SDH,
430                 "Simple data link on SONET/SDH",
431                 NULL,
432                 VARIABLE_LENGTH,
433                 2,
434                 NULL
435         }
436 };
437
438 #define N_LCP_OPTS      (sizeof lcp_opts / sizeof lcp_opts[0])
439
440 /*
441  * Options.  (IPCP)
442  */
443 #define CI_ADDRS        1       /* IP Addresses (deprecated) (RFC 1172) */
444 #define CI_COMPRESSTYPE 2       /* Compression Type (RFC 1332) */
445 #define CI_ADDR         3       /* IP Address (RFC 1332) */
446 #define CI_MOBILE_IPv4  4       /* Mobile IPv4 (RFC 2290) */
447 #define CI_MS_DNS1      129     /* Primary DNS value (RFC 1877) */
448 #define CI_MS_WINS1     130     /* Primary WINS value (RFC 1877) */
449 #define CI_MS_DNS2      131     /* Secondary DNS value (RFC 1877) */
450 #define CI_MS_WINS2     132     /* Secondary WINS value (RFC 1877) */
451
452 static void dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, const u_char *opd,
453                         int offset, guint length, proto_tree *tree);
454 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, const u_char *opd,
455                         int offset, guint length, proto_tree *tree);
456
457 static const ip_tcp_opt ipcp_opts[] = {
458         {
459                 CI_ADDRS,
460                 "IP addresses (deprecated)",
461                 &ett_ipcp_ipaddrs_opt,
462                 FIXED_LENGTH,
463                 10,
464                 dissect_ipcp_addrs_opt
465         },
466         {
467                 CI_COMPRESSTYPE,
468                 "IP compression protocol",
469                 &ett_ipcp_compressprot_opt,
470                 VARIABLE_LENGTH,
471                 4,
472                 dissect_lcp_protocol_opt
473         },
474         {
475                 CI_ADDR,
476                 "IP address",
477                 NULL,
478                 FIXED_LENGTH,
479                 6,
480                 dissect_ipcp_addr_opt
481         },
482         {
483                 CI_MOBILE_IPv4,
484                 "Mobile node's home IP address",
485                 NULL,
486                 FIXED_LENGTH,
487                 6,
488                 dissect_ipcp_addr_opt
489         },
490         {
491                 CI_MS_DNS1,
492                 "Primary DNS server IP address",
493                 NULL,
494                 FIXED_LENGTH,
495                 6,
496                 dissect_ipcp_addr_opt
497         },
498         {
499                 CI_MS_WINS1,
500                 "Primary WINS server IP address",
501                 NULL,
502                 FIXED_LENGTH,
503                 6,
504                 dissect_ipcp_addr_opt
505         },
506         {
507                 CI_MS_DNS2,
508                 "Secondary DNS server IP address",
509                 NULL,
510                 FIXED_LENGTH,
511                 6,
512                 dissect_ipcp_addr_opt
513         },
514         {
515                 CI_MS_WINS2,
516                 "Secondary WINS server IP address",
517                 NULL,
518                 FIXED_LENGTH,
519                 6,
520                 dissect_ipcp_addr_opt
521         }
522 };
523
524 #define N_IPCP_OPTS     (sizeof ipcp_opts / sizeof ipcp_opts[0])
525
526 void
527 capture_ppp( const u_char *pd, packet_counts *ld ) {
528   switch (pntohs(&pd[2])) {
529     case PPP_IP:
530       capture_ip(pd, 4, ld);
531       break;
532     case PPP_IPX:
533       capture_ipx(pd, 4, ld);
534       break;
535     case PPP_VINES:
536       capture_ipx(pd, 4, ld);
537       break;
538     default:
539       ld->other++;
540       break;
541   }
542 }
543
544 static void
545 dissect_lcp_mru_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
546                         guint length, proto_tree *tree)
547 {
548   proto_tree_add_text(tree, offset, length, "MRU: %u", pntohs(opd));
549 }
550
551 static void
552 dissect_lcp_async_map_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
553                         guint length, proto_tree *tree)
554 {
555   proto_tree_add_text(tree, offset, length, "Async characters to map: 0x%08x",
556                         pntohl(opd));
557 }
558
559 static void
560 dissect_lcp_protocol_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
561                         guint length, proto_tree *tree)
562 {
563   guint16 protocol;
564   proto_item *tf;
565   proto_tree *field_tree = NULL;
566   
567   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
568           optp->name, length, plurality(length, "", "s"));
569   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
570   offset += 2;
571   length -= 2;
572   protocol = pntohs(opd);
573   proto_tree_add_text(field_tree, offset, 2, "%s: %s (0x%02x)", optp->name,
574                 val_to_str(protocol, ppp_vals, "Unknown"), protocol);
575   offset += 2;
576   opd += 2;
577   length -= 2;
578   if (length > 0)
579     proto_tree_add_text(field_tree, offset, length, "Data (%d byte%s)", length,
580                         plurality(length, "", "s"));
581 }
582
583 static void
584 dissect_lcp_magicnumber_opt(const ip_tcp_opt *optp, const u_char *opd,
585                         int offset, guint length, proto_tree *tree)
586 {
587   proto_tree_add_text(tree, offset, length, "Magic number: 0x%08x",
588                         pntohl(opd));
589 }
590
591 static void
592 dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp, const u_char *opd,
593                         int offset, guint length, proto_tree *tree)
594 {
595   proto_item *tf;
596   proto_tree *field_tree = NULL;
597   guint8 alternatives;
598   
599   alternatives = *opd;
600   tf = proto_tree_add_text(tree, offset, length, "%s: 0x%02x",
601           optp->name, alternatives);
602   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
603   offset += 2;
604   if (alternatives & 0x1)
605     proto_tree_add_text(field_tree, offset + 2, 1, "%s",
606        decode_boolean_bitfield(alternatives, 0x1, 8, "Null FCS", NULL));
607   if (alternatives & 0x2)
608     proto_tree_add_text(field_tree, offset + 2, 1, "%s",
609        decode_boolean_bitfield(alternatives, 0x2, 8, "CCITT 16-bit FCS", NULL));
610   if (alternatives & 0x4)
611     proto_tree_add_text(field_tree, offset + 2, 1, "%s",
612        decode_boolean_bitfield(alternatives, 0x4, 8, "CCITT 32-bit FCS", NULL));
613 }
614
615 static void
616 dissect_lcp_self_describing_pad_opt(const ip_tcp_opt *optp, const u_char *opd,
617                         int offset, guint length, proto_tree *tree)
618 {
619   proto_tree_add_text(tree, offset, length,
620                         "Maximum octets of self-describing padding: %u",
621                         *opd);
622 }
623
624 static void
625 dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp, const u_char *opd,
626                         int offset, guint length, proto_tree *tree)
627 {
628   proto_item *tf;
629   proto_tree *field_tree = NULL;
630   
631   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
632           optp->name, length, plurality(length, "", "s"));
633   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
634   offset += 2;
635   length -= 2;
636   proto_tree_add_text(field_tree, offset, 1, "Window: %u", *opd);
637   offset += 1;
638   opd += 1;
639   length -= 1;
640   if (length > 0)
641     proto_tree_add_text(field_tree, offset, length, "Address (%d byte%s)",
642                         length, plurality(length, "", "s"));
643 }
644
645 static const value_string callback_op_vals[] = {
646         {0, "Location is determined by user authentication" },
647         {1, "Message is dialing string" },
648         {2, "Message is location identifier" },
649         {3, "Message is E.164" },
650         {4, "Message is distinguished name" },
651         {0, NULL }
652 };
653
654 static void
655 dissect_lcp_callback_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
656                         guint length, proto_tree *tree)
657 {
658   proto_item *tf;
659   proto_tree *field_tree = NULL;
660   
661   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
662           optp->name, length, plurality(length, "", "s"));
663   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
664   offset += 2;
665   length -= 2;
666   proto_tree_add_text(field_tree, offset, 1, "Operation: %s (0x%02x)",
667                 val_to_str(*opd, callback_op_vals, "Unknown"),
668                 *opd);
669   offset += 1;
670   opd += 1;
671   length -= 1;
672   if (length > 0)
673     proto_tree_add_text(field_tree, offset, length, "Message (%d byte%s)",
674                         length, plurality(length, "", "s"));
675 }
676
677 static void
678 dissect_lcp_multilink_mrru_opt(const ip_tcp_opt *optp, const u_char *opd,
679                         int offset, guint length, proto_tree *tree)
680 {
681   proto_tree_add_text(tree, offset, length, "Multilink MRRU: %u",
682                         pntohs(opd));
683 }
684
685 #define CLASS_NULL                      0
686 #define CLASS_LOCAL                     1
687 #define CLASS_IP                        2
688 #define CLASS_IEEE_802_1                3
689 #define CLASS_PPP_MAGIC_NUMBER          4
690 #define CLASS_PSDN_DIRECTORY_NUMBER     5
691
692 static const value_string multilink_ep_disc_class_vals[] = {
693         {CLASS_NULL,                  "Null" },
694         {CLASS_LOCAL,                 "Locally assigned address" },
695         {CLASS_IP,                    "IP address" },
696         {CLASS_IEEE_802_1,            "IEEE 802.1 globally assigned MAC address" },
697         {CLASS_PPP_MAGIC_NUMBER,      "PPP magic-number block" },
698         {CLASS_PSDN_DIRECTORY_NUMBER, "Public switched network directory number" },
699         {0,                           NULL }
700 };
701
702 static void
703 dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp, const u_char *opd,
704                         int offset, guint length, proto_tree *tree)
705 {
706   proto_item *tf;
707   proto_tree *field_tree = NULL;
708   guint8 ep_disc_class;
709
710   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
711           optp->name, length, plurality(length, "", "s"));
712   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
713   offset += 2;
714   length -= 2;
715   ep_disc_class = *opd;
716   proto_tree_add_text(field_tree, offset, 1, "Class: %s (%u)",
717                 val_to_str(ep_disc_class, multilink_ep_disc_class_vals, "Unknown"),
718                 ep_disc_class);
719   offset += 1;
720   opd += 1;
721   length -= 1;
722   if (length > 0) {
723     switch (ep_disc_class) {
724
725     case CLASS_NULL:
726       proto_tree_add_text(field_tree, offset, length,
727                         "Address (%d byte%s), should have been empty",
728                         length, plurality(length, "", "s"));
729       break;
730
731     case CLASS_LOCAL:
732       if (length > 20) {
733         proto_tree_add_text(field_tree, offset, length,
734                         "Address (%d byte%s), should have been <20",
735                         length, plurality(length, "", "s"));
736       } else {
737         proto_tree_add_text(field_tree, offset, length,
738                         "Address (%d byte%s)",
739                         length, plurality(length, "", "s"));
740       }
741       break;
742
743     case CLASS_IP:
744       if (length != 4) {
745         proto_tree_add_text(field_tree, offset, length,
746                         "Address (%d byte%s), should have been 4",
747                         length, plurality(length, "", "s"));
748       } else {
749         proto_tree_add_text(field_tree, offset, length,
750                         "Address: %s", ip_to_str(opd));
751       }
752       break;
753
754     case CLASS_IEEE_802_1:
755       if (length != 6) {
756         proto_tree_add_text(field_tree, offset, length,
757                         "Address (%d byte%s), should have been 6",
758                         length, plurality(length, "", "s"));
759       } else {
760         proto_tree_add_text(field_tree, offset, length,
761                         "Address: %s", ether_to_str(opd));
762       }
763       break;
764
765     case CLASS_PPP_MAGIC_NUMBER:
766       /* XXX - dissect as 32-bit magic numbers */
767       if (length > 20) {
768         proto_tree_add_text(field_tree, offset, length,
769                         "Address (%d byte%s), should have been <20",
770                         length, plurality(length, "", "s"));
771       } else {
772         proto_tree_add_text(field_tree, offset, length,
773                         "Address (%d byte%s)",
774                         length, plurality(length, "", "s"));
775       }
776       break;
777
778     case CLASS_PSDN_DIRECTORY_NUMBER:
779       if (length > 15) {
780         proto_tree_add_text(field_tree, offset, length,
781                         "Address (%d byte%s), should have been <20",
782                         length, plurality(length, "", "s"));
783       } else {
784         proto_tree_add_text(field_tree, offset, length,
785                         "Address (%d byte%s)",
786                         length, plurality(length, "", "s"));
787       }
788       break;
789
790     default:
791       proto_tree_add_text(field_tree, offset, length,
792                         "Address (%d byte%s)",
793                         length, plurality(length, "", "s"));
794       break;
795     }
796   }
797 }
798
799 static void
800 dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp, const u_char *opd,
801                         int offset, guint length, proto_tree *tree)
802 {
803   proto_tree_add_text(tree, offset, length,
804                         "Link discriminator for BAP: 0x%04x",
805                         pntohs(opd));
806 }
807
808 /* Character set numbers from the IANA charset registry. */
809 static const value_string charset_num_vals[] = {
810         {105, "UTF-8" },
811         {0,   NULL }
812 };
813
814 static void
815 dissect_lcp_internationalization_opt(const ip_tcp_opt *optp, const u_char *opd,
816                         int offset, guint length, proto_tree *tree)
817 {
818   proto_item *tf;
819   proto_tree *field_tree = NULL;
820   
821   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
822           optp->name, length, plurality(length, "", "s"));
823   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
824   offset += 2;
825   length -= 2;
826   proto_tree_add_text(field_tree, offset, 4, "Character set: %s (0x%04x)",
827                 val_to_str(pntohl(opd), charset_num_vals, "Unknown"),
828                 pntohl(opd));
829   offset += 4;
830   opd += 4;
831   length -= 4;
832   if (length > 0) {
833     /* XXX - should be displayed as an ASCII string */
834     proto_tree_add_text(field_tree, offset, length, "Language tag (%d byte%s)",
835                         length, plurality(length, "", "s"));
836   }
837 }
838
839 static void
840 dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, const u_char *opd,
841                         int offset, guint length, proto_tree *tree)
842 {
843   proto_item *tf;
844   proto_tree *field_tree = NULL;
845   
846   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
847           optp->name, length, plurality(length, "", "s"));
848   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
849   offset += 2;
850   length -= 2;
851   proto_tree_add_text(field_tree, offset, 4,
852                         "Source IP address: %s", ip_to_str(opd));
853   offset += 4;
854   opd += 4;
855   length -= 4;
856   proto_tree_add_text(field_tree, offset, 4,
857                         "Destination IP address: %s", ip_to_str(opd));
858 }
859
860 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, const u_char *opd,
861                         int offset, guint length, proto_tree *tree)
862 {
863   proto_tree_add_text(tree, offset, length, "%s: %s", optp->name,
864                         ip_to_str((guint8 *)opd));
865 }
866
867 static void
868 dissect_cp( const u_char *pd, int offset, const char *proto_short_name,
869         const char *proto_long_name, int proto_subtree_index,
870         const value_string *proto_vals, int options_subtree_index,
871         const ip_tcp_opt *opts, int nopts, frame_data *fd, proto_tree *tree ) {
872   proto_item *ti;
873   proto_tree *fh_tree = NULL;
874   proto_item *tf;
875   proto_tree *field_tree;
876
877   guint8 code;
878   guint8 id;
879   int length;
880   guint16 protocol;
881
882   code = pd[0+offset];
883   id = pd[1+offset];
884   length = pntohs(&pd[2+offset]);
885
886   if(check_col(fd, COL_INFO))
887         col_add_fstr(fd, COL_INFO, "%sCP %s", proto_short_name,
888                 val_to_str(code, proto_vals, "Unknown"));
889
890   if(tree) {
891     ti = proto_tree_add_text(tree, 0+offset, 4, "%s Control Protocol",
892                                 proto_long_name);
893     fh_tree = proto_item_add_subtree(ti, proto_subtree_index);
894     proto_tree_add_text(fh_tree, 0+offset, 1, "Code: %s (0x%02x)",
895       val_to_str(code, proto_vals, "Unknown"), code);
896     proto_tree_add_text(fh_tree, 1+offset, 1, "Identifier: 0x%02x",
897                         id);
898     proto_tree_add_text(fh_tree, 2+offset, 2, "Length: %u",
899                         length);
900   }
901   offset += 4;
902   length -= 4;
903
904   switch (code) {
905     case CONFREQ:
906     case CONFACK:
907     case CONFNAK:
908     case CONFREJ:
909       if(tree) {
910         if (length > 0) {
911           tf = proto_tree_add_text(fh_tree, offset, length,
912             "Options: (%d byte%s)", length, plurality(length, "", "s"));
913           field_tree = proto_item_add_subtree(tf, options_subtree_index);
914           dissect_ip_tcp_options(&pd[offset], offset, length, opts, nopts,
915                                 -1, field_tree);
916         }
917       }
918       break;
919
920     case ECHOREQ:
921     case ECHOREP:
922     case DISCREQ:
923     case IDENT:
924       if(tree) {
925         proto_tree_add_text(fh_tree, offset, 4, "Magic number: 0x%08x",
926                         pntohl(&pd[offset]));
927         offset += 4;
928         length -= 4;
929         if (length > 0)
930           proto_tree_add_text(fh_tree, offset, length, "Message (%d byte%s)",
931                                 length, plurality(length, "", "s"));
932       }
933       break;
934
935     case TIMEREMAIN:
936       if(tree) {
937         proto_tree_add_text(fh_tree, offset, 4, "Magic number: 0x%08x",
938                         pntohl(&pd[offset]));
939         offset += 4;
940         length -= 4;
941         proto_tree_add_text(fh_tree, offset, 4, "Seconds remaining: %u",
942                         pntohl(&pd[offset]));
943         offset += 4;
944         length -= 4;
945         if (length > 0)
946           proto_tree_add_text(fh_tree, offset, length, "Message (%d byte%s)",
947                                 length, plurality(length, "", "s"));
948       }
949       break;
950
951     case PROTREJ:
952       if(tree) {
953         protocol = pntohs(&pd[offset]);
954         proto_tree_add_text(fh_tree, offset, 2, "Rejected protocol: %s (0x%04x)",
955                 val_to_str(protocol, ppp_vals, "Unknown"), protocol);
956         offset += 2;
957         length -= 2;
958         if (length > 0)
959           proto_tree_add_text(fh_tree, offset, length, "Rejected packet (%d byte%s)",
960                                 length, plurality(length, "", "s"));
961                 /* XXX - should be dissected as a PPP packet */
962       }
963       break;
964
965     case CODEREJ:
966                 /* decode the rejected LCP packet here. */
967       if (length > 0)
968         proto_tree_add_text(fh_tree, offset, length, "Rejected packet (%d byte%s)",
969                                 length, plurality(length, "", "s"));
970       break;
971
972     case TERMREQ:
973     case TERMACK:
974       if (length > 0)
975         proto_tree_add_text(fh_tree, offset, length, "Data (%d byte%s)",
976                                 length, plurality(length, "", "s"));
977       break;
978
979     default:
980       if (length > 0)
981         proto_tree_add_text(fh_tree, offset, length, "Stuff (%d byte%s)",
982                                 length, plurality(length, "", "s"));
983       break;
984   }
985 }
986
987 /* Protocol field compression */
988 #define PFC_BIT 0x01
989
990 static gboolean
991 dissect_ppp_stuff( const u_char *pd, int offset, frame_data *fd,
992                 proto_tree *tree, proto_tree *fh_tree ) {
993   guint16 ppp_prot;
994   int     proto_len;
995
996   if (pd[offset] & PFC_BIT) {
997     ppp_prot = pd[offset];
998     proto_len = 1;
999   } else {
1000     ppp_prot = pntohs(&pd[offset]);
1001     proto_len = 2;
1002   }
1003
1004   if (tree) {
1005     proto_tree_add_text(fh_tree, offset, proto_len, "Protocol: %s (0x%04x)",
1006       val_to_str(ppp_prot, ppp_vals, "Unknown"), ppp_prot);
1007   }
1008   offset += proto_len;
1009
1010   switch (ppp_prot) {
1011     case PPP_IP:
1012       dissect_ip(pd, offset, fd, tree);
1013       return TRUE;
1014     case PPP_AT:
1015       dissect_ddp(pd, offset, fd, tree);
1016       return TRUE;
1017     case PPP_IPX:
1018       dissect_ipx(pd, offset, fd, tree);
1019       return TRUE;
1020     case PPP_VINES:
1021       dissect_vines(pd, offset, fd, tree);
1022       return TRUE;
1023     case PPP_MP:
1024       dissect_mp(pd, offset, fd, tree, fh_tree);
1025       return TRUE;
1026     case PPP_IPV6:
1027       dissect_ipv6(pd, offset, fd, tree);
1028       return TRUE;
1029     case PPP_LCP:
1030       dissect_cp(pd, offset, "L", "Link", ett_lcp, lcp_vals, ett_lcp_options,
1031                 lcp_opts, N_LCP_OPTS, fd, tree);
1032       return TRUE;
1033     case PPP_IPCP:
1034       dissect_cp(pd, offset, "IP", "IP", ett_ipcp, cp_vals, ett_ipcp_options,
1035                 ipcp_opts, N_IPCP_OPTS, fd, tree);
1036       return TRUE;
1037     default:
1038       if (check_col(fd, COL_INFO))
1039         col_add_fstr(fd, COL_INFO, "PPP %s (0x%04x)",
1040                 val_to_str(ppp_prot, ppp_vals, "Unknown"), ppp_prot);
1041       dissect_data(pd, offset, fd, tree);
1042       return FALSE;
1043   }
1044 }
1045
1046 #define MP_FRAG_MASK     0xC0
1047 #define MP_FRAG(bits)    ((bits) & MP_FRAG_MASK)
1048 #define MP_FRAG_FIRST    0x80
1049 #define MP_FRAG_LAST     0x40
1050 #define MP_FRAG_RESERVED 0x3f
1051
1052 /* According to RFC 1717, the length the MP header isn't indicated anywhere
1053    in the header itself.  It starts out at four bytes and can be
1054    negotiated down to two using LCP.  We currently assume that all
1055    headers are four bytes.  - gcc
1056  */
1057 static void
1058 dissect_mp(const u_char *pd, int offset, frame_data *fd,
1059   proto_tree *tree, proto_tree *fh_tree)
1060 {
1061   proto_tree *ti, *mp_tree, *hdr_tree;
1062   guint8      flags;
1063   guint32     seq;
1064   gchar       flag_str[12];
1065   int         first, last;
1066
1067   flags = pd[offset];
1068   first = flags && MP_FRAG_FIRST;
1069   last  = flags && MP_FRAG_LAST;
1070   seq = pd[offset+1] << 16 | pd[offset+2] << 8 | pd[offset+3];
1071
1072   if (check_col(fd, COL_INFO))
1073     col_add_fstr(fd, COL_INFO, "PPP Multilink");
1074
1075   if (tree) {
1076     switch (flags) {
1077       case MP_FRAG_FIRST:
1078         strcpy(flag_str, "First");
1079         break;
1080       case MP_FRAG_LAST:
1081         strcpy(flag_str, "Last");
1082         break;
1083       case MP_FRAG_FIRST|MP_FRAG_LAST:
1084         strcpy(flag_str, "First, Last");
1085         break;
1086       default:
1087         strcpy(flag_str, "Unknown");
1088         break;
1089     }
1090     ti = proto_tree_add_item(tree, proto_mp, offset, 4, NULL);
1091     mp_tree = proto_item_add_subtree(ti, ett_mp);
1092     ti = proto_tree_add_text(mp_tree, offset, 1, "Fragment: 0x%2X (%s)",
1093       flags, flag_str);
1094     hdr_tree = proto_item_add_subtree(ti, ett_mp_flags);
1095     proto_tree_add_item_format(hdr_tree, hf_mp_frag_first, offset, 1, first,
1096       "%s", decode_boolean_bitfield(flags, MP_FRAG_FIRST, sizeof(flags) * 8,
1097         "first", "not first"));
1098     proto_tree_add_item_format(hdr_tree, hf_mp_frag_last, offset, 1, last,
1099       "%s", decode_boolean_bitfield(flags, MP_FRAG_LAST, sizeof(flags) * 8,
1100         "last", "not last"));
1101     proto_tree_add_text(hdr_tree, offset, 1, "%s",
1102       decode_boolean_bitfield(flags, MP_FRAG_RESERVED, sizeof(flags) * 8,
1103         "reserved", "reserved"));
1104     proto_tree_add_item(mp_tree, hf_mp_sequence_num, offset + 1, 3, seq);
1105  }
1106
1107   offset += 4;
1108
1109   if (IS_DATA_IN_FRAME(offset)) {
1110     if (tree) {
1111       ti = proto_tree_add_item(tree, proto_ppp, offset, 1, NULL);
1112       fh_tree = proto_item_add_subtree(ti, ett_ppp);
1113     }
1114     dissect_ppp_stuff(pd, offset, fd, tree, fh_tree);
1115   }
1116 }
1117
1118 void
1119 dissect_payload_ppp( const u_char *pd, int offset, frame_data *fd, proto_tree *tree ) {
1120   proto_item *ti;
1121   proto_tree *fh_tree = NULL;
1122
1123   /* populate a tree in the second pane with the status of the link
1124      layer (ie none) */
1125   if(tree) {
1126     ti = proto_tree_add_item(tree, proto_ppp, 0+offset, 2, NULL);
1127     fh_tree = proto_item_add_subtree(ti, ett_ppp);
1128   }
1129
1130   dissect_ppp_stuff(pd, offset, fd, tree, fh_tree);
1131 }
1132
1133 void
1134 dissect_ppp( const u_char *pd, frame_data *fd, proto_tree *tree ) {
1135   e_ppphdr   ph;
1136   proto_item *ti;
1137   proto_tree *fh_tree = NULL;
1138
1139   ph.ppp_addr = pd[0];
1140   ph.ppp_ctl  = pd[1];
1141   ph.ppp_prot = pntohs(&pd[2]);
1142
1143   /* load the top pane info. This should be overwritten by
1144      the next protocol in the stack */
1145
1146   if(check_col(fd, COL_RES_DL_SRC))
1147     col_add_str(fd, COL_RES_DL_SRC, "N/A" );
1148   if(check_col(fd, COL_RES_DL_DST))
1149     col_add_str(fd, COL_RES_DL_DST, "N/A" );
1150   if(check_col(fd, COL_PROTOCOL))
1151     col_add_str(fd, COL_PROTOCOL, "PPP" );
1152
1153   /* populate a tree in the second pane with the status of the link
1154      layer (ie none) */
1155   if(tree) {
1156     ti = proto_tree_add_item(tree, proto_ppp, 0, 4, NULL);
1157     fh_tree = proto_item_add_subtree(ti, ett_ppp);
1158     proto_tree_add_text(fh_tree, 0, 1, "Address: %02x", ph.ppp_addr);
1159     proto_tree_add_text(fh_tree, 1, 1, "Control: %02x", ph.ppp_ctl);
1160   }
1161
1162   if (!dissect_ppp_stuff(pd, 2, fd, tree, fh_tree)) {
1163     if (check_col(fd, COL_PROTOCOL))
1164       col_add_fstr(fd, COL_PROTOCOL, "0x%04x", ph.ppp_prot);
1165   }
1166 }
1167
1168 void
1169 proto_register_ppp(void)
1170 {
1171 /*        static hf_register_info hf[] = {
1172                 { &variable,
1173                 { "Name",           "ppp.abbreviation", TYPE, VALS_POINTER }},
1174         };*/
1175         static gint *ett[] = {
1176                 &ett_ppp,
1177                 &ett_ipcp,
1178                 &ett_ipcp_options,
1179                 &ett_ipcp_ipaddrs_opt,
1180                 &ett_ipcp_compressprot_opt,
1181                 &ett_lcp,
1182                 &ett_lcp_options,
1183                 &ett_lcp_mru_opt,
1184                 &ett_lcp_async_map_opt,
1185                 &ett_lcp_authprot_opt,
1186                 &ett_lcp_qualprot_opt,
1187                 &ett_lcp_magicnum_opt,
1188                 &ett_lcp_fcs_alternatives_opt,
1189                 &ett_lcp_numbered_mode_opt,
1190                 &ett_lcp_callback_opt,
1191                 &ett_lcp_multilink_ep_disc_opt,
1192                 &ett_lcp_internationalization_opt,
1193         };
1194
1195         proto_ppp = proto_register_protocol("Point-to-Point Protocol", "ppp");
1196  /*       proto_register_field_array(proto_ppp, hf, array_length(hf));*/
1197         proto_register_subtree_array(ett, array_length(ett));
1198 }
1199
1200 void
1201 proto_register_mp(void)
1202 {
1203   static hf_register_info hf[] = {
1204     { &hf_mp_frag_first,
1205     { "First fragment",         "mp.first",     FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1206         "" }},
1207
1208     { &hf_mp_frag_last,
1209     { "Last fragment",          "mp.last",      FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1210         "" }},
1211
1212     { &hf_mp_sequence_num,
1213     { "Sequence number",        "mp.seq",       FT_UINT24, BASE_DEC, NULL, 0x0,
1214         "" }}
1215   };
1216   static gint *ett[] = {
1217     &ett_mp,
1218     &ett_mp_flags,
1219   };
1220
1221   proto_mp = proto_register_protocol("PPP Multilink Protocol", "mp");
1222   proto_register_field_array(proto_mp, hf, array_length(hf));
1223   proto_register_subtree_array(ett, array_length(ett));
1224 }