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