Add sample strace output to illustrate the timeout problem.
[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.23 1999/11/30 23:56:36 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-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, guint32 cap_len, packet_counts *ld ) {
524   switch (pntohs(&pd[2])) {
525     case PPP_IP:
526       capture_ip(pd, 4, cap_len, ld);
527       break;
528     case PPP_IPX:
529       capture_ipx(pd, 4, cap_len, ld);
530       break;
531     default:
532       ld->other++;
533       break;
534   }
535 }
536
537 static void
538 dissect_lcp_mru_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
539                         guint length, proto_tree *tree)
540 {
541   proto_tree_add_text(tree, offset, length, "MRU: %u", pntohs(opd));
542 }
543
544 static void
545 dissect_lcp_async_map_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, "Async characters to map: 0x%08x",
549                         pntohl(opd));
550 }
551
552 static void
553 dissect_lcp_protocol_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
554                         guint length, proto_tree *tree)
555 {
556   guint16 protocol;
557   proto_item *tf;
558   proto_tree *field_tree = NULL;
559   
560   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
561           optp->name, length, plurality(length, "", "s"));
562   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
563   offset += 2;
564   length -= 2;
565   protocol = pntohs(opd);
566   proto_tree_add_text(field_tree, offset, 2, "%s: %s (0x%02x)", optp->name,
567                 val_to_str(protocol, ppp_vals, "Unknown"), protocol);
568   offset += 2;
569   opd += 2;
570   length -= 2;
571   if (length > 0)
572     proto_tree_add_text(field_tree, offset, length, "Data (%d byte%s)", length,
573                         plurality(length, "", "s"));
574 }
575
576 static void
577 dissect_lcp_magicnumber_opt(const ip_tcp_opt *optp, const u_char *opd,
578                         int offset, guint length, proto_tree *tree)
579 {
580   proto_tree_add_text(tree, offset, length, "Magic number: 0x%08x",
581                         pntohl(opd));
582 }
583
584 static void
585 dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp, const u_char *opd,
586                         int offset, guint length, proto_tree *tree)
587 {
588   proto_item *tf;
589   proto_tree *field_tree = NULL;
590   guint8 alternatives;
591   
592   alternatives = *opd;
593   tf = proto_tree_add_text(tree, offset, length, "%s: 0x%02x",
594           optp->name, alternatives);
595   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
596   offset += 2;
597   if (alternatives & 0x1)
598     proto_tree_add_text(field_tree, offset + 2, 1, "%s",
599        decode_boolean_bitfield(alternatives, 0x1, 8, "Null FCS", NULL));
600   if (alternatives & 0x2)
601     proto_tree_add_text(field_tree, offset + 2, 1, "%s",
602        decode_boolean_bitfield(alternatives, 0x2, 8, "CCITT 16-bit FCS", NULL));
603   if (alternatives & 0x4)
604     proto_tree_add_text(field_tree, offset + 2, 1, "%s",
605        decode_boolean_bitfield(alternatives, 0x4, 8, "CCITT 32-bit FCS", NULL));
606 }
607
608 static void
609 dissect_lcp_self_describing_pad_opt(const ip_tcp_opt *optp, const u_char *opd,
610                         int offset, guint length, proto_tree *tree)
611 {
612   proto_tree_add_text(tree, offset, length,
613                         "Maximum octets of self-describing padding: %u",
614                         *opd);
615 }
616
617 static void
618 dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp, const u_char *opd,
619                         int offset, guint length, proto_tree *tree)
620 {
621   proto_item *tf;
622   proto_tree *field_tree = NULL;
623   
624   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
625           optp->name, length, plurality(length, "", "s"));
626   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
627   offset += 2;
628   length -= 2;
629   proto_tree_add_text(field_tree, offset, 1, "Window: %u", *opd);
630   offset += 1;
631   opd += 1;
632   length -= 1;
633   if (length > 0)
634     proto_tree_add_text(field_tree, offset, length, "Address (%d byte%s)",
635                         length, plurality(length, "", "s"));
636 }
637
638 static const value_string callback_op_vals[] = {
639         {0, "Location is determined by user authentication" },
640         {1, "Message is dialing string" },
641         {2, "Message is location identifier" },
642         {3, "Message is E.164" },
643         {4, "Message is distinguished name" },
644         {0, NULL }
645 };
646
647 static void
648 dissect_lcp_callback_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
649                         guint length, proto_tree *tree)
650 {
651   proto_item *tf;
652   proto_tree *field_tree = NULL;
653   
654   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
655           optp->name, length, plurality(length, "", "s"));
656   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
657   offset += 2;
658   length -= 2;
659   proto_tree_add_text(field_tree, offset, 1, "Operation: %s (0x%02x)",
660                 val_to_str(*opd, callback_op_vals, "Unknown"),
661                 *opd);
662   offset += 1;
663   opd += 1;
664   length -= 1;
665   if (length > 0)
666     proto_tree_add_text(field_tree, offset, length, "Message (%d byte%s)",
667                         length, plurality(length, "", "s"));
668 }
669
670 static void
671 dissect_lcp_multilink_mrru_opt(const ip_tcp_opt *optp, const u_char *opd,
672                         int offset, guint length, proto_tree *tree)
673 {
674   proto_tree_add_text(tree, offset, length, "Multilink MRRU: %u",
675                         pntohs(opd));
676 }
677
678 #define CLASS_NULL                      0
679 #define CLASS_LOCAL                     1
680 #define CLASS_IP                        2
681 #define CLASS_IEEE_802_1                3
682 #define CLASS_PPP_MAGIC_NUMBER          4
683 #define CLASS_PSDN_DIRECTORY_NUMBER     5
684
685 static const value_string multilink_ep_disc_class_vals[] = {
686         {CLASS_NULL,                  "Null" },
687         {CLASS_LOCAL,                 "Locally assigned address" },
688         {CLASS_IP,                    "IP address" },
689         {CLASS_IEEE_802_1,            "IEEE 802.1 globally assigned MAC address" },
690         {CLASS_PPP_MAGIC_NUMBER,      "PPP magic-number block" },
691         {CLASS_PSDN_DIRECTORY_NUMBER, "Public switched network directory number" },
692         {0,                           NULL }
693 };
694
695 static void
696 dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp, const u_char *opd,
697                         int offset, guint length, proto_tree *tree)
698 {
699   proto_item *tf;
700   proto_tree *field_tree = NULL;
701   guint8 ep_disc_class;
702
703   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
704           optp->name, length, plurality(length, "", "s"));
705   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
706   offset += 2;
707   length -= 2;
708   ep_disc_class = *opd;
709   proto_tree_add_text(field_tree, offset, 1, "Class: %s (%u)",
710                 val_to_str(ep_disc_class, multilink_ep_disc_class_vals, "Unknown"),
711                 ep_disc_class);
712   offset += 1;
713   opd += 1;
714   length -= 1;
715   if (length > 0) {
716     switch (ep_disc_class) {
717
718     case CLASS_NULL:
719       proto_tree_add_text(field_tree, offset, length,
720                         "Address (%d byte%s), should have been empty",
721                         length, plurality(length, "", "s"));
722       break;
723
724     case CLASS_LOCAL:
725       if (length > 20) {
726         proto_tree_add_text(field_tree, offset, length,
727                         "Address (%d byte%s), should have been <20",
728                         length, plurality(length, "", "s"));
729       } else {
730         proto_tree_add_text(field_tree, offset, length,
731                         "Address (%d byte%s)",
732                         length, plurality(length, "", "s"));
733       }
734       break;
735
736     case CLASS_IP:
737       if (length != 4) {
738         proto_tree_add_text(field_tree, offset, length,
739                         "Address (%d byte%s), should have been 4",
740                         length, plurality(length, "", "s"));
741       } else {
742         proto_tree_add_text(field_tree, offset, length,
743                         "Address: %s", ip_to_str(opd));
744       }
745       break;
746
747     case CLASS_IEEE_802_1:
748       if (length != 6) {
749         proto_tree_add_text(field_tree, offset, length,
750                         "Address (%d byte%s), should have been 6",
751                         length, plurality(length, "", "s"));
752       } else {
753         proto_tree_add_text(field_tree, offset, length,
754                         "Address: %s", ether_to_str(opd));
755       }
756       break;
757
758     case CLASS_PPP_MAGIC_NUMBER:
759       /* XXX - dissect as 32-bit magic numbers */
760       if (length > 20) {
761         proto_tree_add_text(field_tree, offset, length,
762                         "Address (%d byte%s), should have been <20",
763                         length, plurality(length, "", "s"));
764       } else {
765         proto_tree_add_text(field_tree, offset, length,
766                         "Address (%d byte%s)",
767                         length, plurality(length, "", "s"));
768       }
769       break;
770
771     case CLASS_PSDN_DIRECTORY_NUMBER:
772       if (length > 15) {
773         proto_tree_add_text(field_tree, offset, length,
774                         "Address (%d byte%s), should have been <20",
775                         length, plurality(length, "", "s"));
776       } else {
777         proto_tree_add_text(field_tree, offset, length,
778                         "Address (%d byte%s)",
779                         length, plurality(length, "", "s"));
780       }
781       break;
782
783     default:
784       proto_tree_add_text(field_tree, offset, length,
785                         "Address (%d byte%s)",
786                         length, plurality(length, "", "s"));
787       break;
788     }
789   }
790 }
791
792 static void
793 dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp, const u_char *opd,
794                         int offset, guint length, proto_tree *tree)
795 {
796   proto_tree_add_text(tree, offset, length,
797                         "Link discriminator for BAP: 0x%04x",
798                         pntohs(opd));
799 }
800
801 /* Character set numbers from the IANA charset registry. */
802 static const value_string charset_num_vals[] = {
803         {105, "UTF-8" },
804         {0,   NULL }
805 };
806
807 static void
808 dissect_lcp_internationalization_opt(const ip_tcp_opt *optp, const u_char *opd,
809                         int offset, guint length, proto_tree *tree)
810 {
811   proto_item *tf;
812   proto_tree *field_tree = NULL;
813   
814   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
815           optp->name, length, plurality(length, "", "s"));
816   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
817   offset += 2;
818   length -= 2;
819   proto_tree_add_text(field_tree, offset, 4, "Character set: %s (0x%04x)",
820                 val_to_str(pntohl(opd), charset_num_vals, "Unknown"),
821                 pntohl(opd));
822   offset += 4;
823   opd += 4;
824   length -= 4;
825   if (length > 0) {
826     /* XXX - should be displayed as an ASCII string */
827     proto_tree_add_text(field_tree, offset, length, "Language tag (%d byte%s)",
828                         length, plurality(length, "", "s"));
829   }
830 }
831
832 static void
833 dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, const u_char *opd,
834                         int offset, guint length, proto_tree *tree)
835 {
836   proto_item *tf;
837   proto_tree *field_tree = NULL;
838   
839   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
840           optp->name, length, plurality(length, "", "s"));
841   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
842   offset += 2;
843   length -= 2;
844   proto_tree_add_text(field_tree, offset, 4,
845                         "Source IP address: %s", ip_to_str(opd));
846   offset += 4;
847   opd += 4;
848   length -= 4;
849   proto_tree_add_text(field_tree, offset, 4,
850                         "Destination IP address: %s", ip_to_str(opd));
851 }
852
853 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, const u_char *opd,
854                         int offset, guint length, proto_tree *tree)
855 {
856   proto_tree_add_text(tree, offset, length, "%s: %s", optp->name,
857                         ip_to_str((guint8 *)opd));
858 }
859
860 static void
861 dissect_cp( const u_char *pd, int offset, const char *proto_short_name,
862         const char *proto_long_name, int proto_subtree_index,
863         const value_string *proto_vals, int options_subtree_index,
864         const ip_tcp_opt *opts, int nopts, frame_data *fd, proto_tree *tree ) {
865   proto_item *ti;
866   proto_tree *fh_tree = NULL;
867   proto_item *tf;
868   proto_tree *field_tree;
869
870   guint8 code;
871   guint8 id;
872   int length;
873   guint16 protocol;
874
875   code = pd[0+offset];
876   id = pd[1+offset];
877   length = pntohs(&pd[2+offset]);
878
879   if(check_col(fd, COL_INFO))
880         col_add_fstr(fd, COL_INFO, "%sCP %s", proto_short_name,
881                 val_to_str(code, proto_vals, "Unknown"));
882
883   if(tree) {
884     ti = proto_tree_add_text(tree, 0+offset, 4, "%s Control Protocol",
885                                 proto_long_name);
886     fh_tree = proto_item_add_subtree(ti, proto_subtree_index);
887     proto_tree_add_text(fh_tree, 0+offset, 1, "Code: %s (0x%02x)",
888       val_to_str(code, proto_vals, "Unknown"), code);
889     proto_tree_add_text(fh_tree, 1+offset, 1, "Identifier: 0x%02x",
890                         id);
891     proto_tree_add_text(fh_tree, 2+offset, 2, "Length: %u",
892                         length);
893   }
894   offset += 4;
895   length -= 4;
896
897   switch (code) {
898     case CONFREQ:
899     case CONFACK:
900     case CONFNAK:
901     case CONFREJ:
902       if(tree) {
903         if (length > 0) {
904           tf = proto_tree_add_text(fh_tree, offset, length,
905             "Options: (%d byte%s)", length, plurality(length, "", "s"));
906           field_tree = proto_item_add_subtree(tf, options_subtree_index);
907           dissect_ip_tcp_options(&pd[offset], offset, length, opts, nopts,
908                                 -1, field_tree);
909         }
910       }
911       break;
912
913     case ECHOREQ:
914     case ECHOREP:
915     case DISCREQ:
916     case IDENT:
917       if(tree) {
918         proto_tree_add_text(fh_tree, offset, 4, "Magic number: 0x%08x",
919                         pntohl(&pd[offset]));
920         offset += 4;
921         length -= 4;
922         if (length > 0)
923           proto_tree_add_text(fh_tree, offset, length, "Message (%d byte%s)",
924                                 length, plurality(length, "", "s"));
925       }
926       break;
927
928     case TIMEREMAIN:
929       if(tree) {
930         proto_tree_add_text(fh_tree, offset, 4, "Magic number: 0x%08x",
931                         pntohl(&pd[offset]));
932         offset += 4;
933         length -= 4;
934         proto_tree_add_text(fh_tree, offset, 4, "Seconds remaining: %u",
935                         pntohl(&pd[offset]));
936         offset += 4;
937         length -= 4;
938         if (length > 0)
939           proto_tree_add_text(fh_tree, offset, length, "Message (%d byte%s)",
940                                 length, plurality(length, "", "s"));
941       }
942       break;
943
944     case PROTREJ:
945       if(tree) {
946         protocol = pntohs(&pd[offset]);
947         proto_tree_add_text(fh_tree, offset, 2, "Rejected protocol: %s (0x%04x)",
948                 val_to_str(protocol, ppp_vals, "Unknown"), protocol);
949         offset += 2;
950         length -= 2;
951         if (length > 0)
952           proto_tree_add_text(fh_tree, offset, length, "Rejected packet (%d byte%s)",
953                                 length, plurality(length, "", "s"));
954                 /* XXX - should be dissected as a PPP packet */
955       }
956       break;
957
958     case CODEREJ:
959                 /* decode the rejected LCP packet here. */
960       if (length > 0)
961         proto_tree_add_text(fh_tree, offset, length, "Rejected packet (%d byte%s)",
962                                 length, plurality(length, "", "s"));
963       break;
964
965     case TERMREQ:
966     case TERMACK:
967       if (length > 0)
968         proto_tree_add_text(fh_tree, offset, length, "Data (%d byte%s)",
969                                 length, plurality(length, "", "s"));
970       break;
971
972     default:
973       if (length > 0)
974         proto_tree_add_text(fh_tree, offset, length, "Stuff (%d byte%s)",
975                                 length, plurality(length, "", "s"));
976       break;
977   }
978 }
979
980 /* Protocol field compression */
981 #define PFC_BIT 0x01
982
983 static gboolean
984 dissect_ppp_stuff( const u_char *pd, int offset, frame_data *fd,
985                 proto_tree *tree, proto_tree *fh_tree ) {
986   guint16 ppp_prot;
987   int     proto_len;
988
989   if (pd[offset] & PFC_BIT) {
990     ppp_prot = pd[offset];
991     proto_len = 1;
992   } else {
993     ppp_prot = pntohs(&pd[offset]);
994     proto_len = 2;
995   }
996
997   if (tree) {
998     proto_tree_add_text(fh_tree, offset, proto_len, "Protocol: %s (0x%04x)",
999       val_to_str(ppp_prot, ppp_vals, "Unknown"), ppp_prot);
1000   }
1001   offset += proto_len;
1002
1003   switch (ppp_prot) {
1004     case PPP_IP:
1005       dissect_ip(pd, offset, fd, tree);
1006       return TRUE;
1007     case PPP_AT:
1008       dissect_ddp(pd, offset, fd, tree);
1009       return TRUE;
1010     case PPP_IPX:
1011       dissect_ipx(pd, offset, fd, tree);
1012       return TRUE;
1013     case PPP_VINES:
1014       dissect_vines(pd, offset, fd, tree);
1015       return TRUE;
1016     case PPP_MP:
1017       dissect_mp(pd, offset, fd, tree, fh_tree);
1018       return TRUE;
1019     case PPP_IPV6:
1020       dissect_ipv6(pd, offset, fd, tree);
1021       return TRUE;
1022     case PPP_LCP:
1023       dissect_cp(pd, offset, "L", "Link", ett_lcp, lcp_vals, ett_lcp_options,
1024                 lcp_opts, N_LCP_OPTS, fd, tree);
1025       return TRUE;
1026     case PPP_IPCP:
1027       dissect_cp(pd, offset, "IP", "IP", ett_ipcp, cp_vals, ett_ipcp_options,
1028                 ipcp_opts, N_IPCP_OPTS, fd, tree);
1029       return TRUE;
1030     default:
1031       if (check_col(fd, COL_INFO))
1032         col_add_fstr(fd, COL_INFO, "PPP %s (0x%04x)",
1033                 val_to_str(ppp_prot, ppp_vals, "Unknown"), ppp_prot);
1034       dissect_data(pd, offset, fd, tree);
1035       return FALSE;
1036   }
1037 }
1038
1039 #define MP_FRAG_MASK     0xC0
1040 #define MP_FRAG(bits)    ((bits) & MP_FRAG_MASK)
1041 #define MP_FRAG_FIRST    0x80
1042 #define MP_FRAG_LAST     0x40
1043 #define MP_FRAG_RESERVED 0x3f
1044
1045 /* According to RFC 1717, the length the MP header isn't indicated anywhere
1046    in the header itself.  It starts out at four bytes and can be
1047    negotiated down to two using LCP.  We currently assume that all
1048    headers are four bytes.  - gcc
1049  */
1050 static void
1051 dissect_mp(const u_char *pd, int offset, frame_data *fd,
1052   proto_tree *tree, proto_tree *fh_tree)
1053 {
1054   proto_tree *ti, *mp_tree, *hdr_tree;
1055   guint8      flags;
1056   guint32     seq;
1057   gchar       flag_str[12];
1058   int         first, last;
1059
1060   flags = pd[offset];
1061   first = flags && MP_FRAG_FIRST;
1062   last  = flags && MP_FRAG_LAST;
1063   memcpy(&seq, &pd[offset + 1], 3);
1064
1065   if (check_col(fd, COL_INFO))
1066     col_add_fstr(fd, COL_INFO, "PPP Multilink");
1067
1068   if (tree) {
1069     switch (flags) {
1070       case MP_FRAG_FIRST:
1071         strcpy(flag_str, "First");
1072         break;
1073       case MP_FRAG_LAST:
1074         strcpy(flag_str, "Last");
1075         break;
1076       case MP_FRAG_FIRST|MP_FRAG_LAST:
1077         strcpy(flag_str, "First, Last");
1078         break;
1079       default:
1080         strcpy(flag_str, "Unknown");
1081         break;
1082     }
1083     ti = proto_tree_add_item(tree, proto_mp, offset, 4, NULL);
1084     mp_tree = proto_item_add_subtree(ti, ett_mp);
1085     ti = proto_tree_add_text(mp_tree, offset, 1, "Fragment: 0x%2X (%s)",
1086       flags, flag_str);
1087     hdr_tree = proto_item_add_subtree(ti, ett_mp_flags);
1088     proto_tree_add_item_format(hdr_tree, hf_mp_frag_first, offset, 1, first,
1089       "%s", decode_boolean_bitfield(flags, MP_FRAG_FIRST, sizeof(flags) * 8,
1090         "first", "not first"));
1091     proto_tree_add_item_format(hdr_tree, hf_mp_frag_last, offset, 1, last,
1092       "%s", decode_boolean_bitfield(flags, MP_FRAG_LAST, sizeof(flags) * 8,
1093         "last", "not last"));
1094     proto_tree_add_text(hdr_tree, offset, 1, "%s",
1095       decode_boolean_bitfield(flags, MP_FRAG_RESERVED, sizeof(flags) * 8,
1096         "reserved", "reserved"));
1097     proto_tree_add_item_format(mp_tree, hf_mp_sequence_num,
1098       offset + 1, 3, seq, "Sequence: %lu", seq);
1099  }
1100
1101   offset += 4;
1102
1103   if (fd->cap_len > offset) {
1104     if (tree) {
1105       ti = proto_tree_add_item(tree, proto_ppp, offset, 1, NULL);
1106       fh_tree = proto_item_add_subtree(ti, ett_ppp);
1107     }
1108     dissect_ppp_stuff(pd, offset, fd, tree, fh_tree);
1109   }
1110 }
1111
1112 void
1113 dissect_payload_ppp( const u_char *pd, int offset, frame_data *fd, proto_tree *tree ) {
1114   proto_item *ti;
1115   proto_tree *fh_tree = NULL;
1116
1117   /* populate a tree in the second pane with the status of the link
1118      layer (ie none) */
1119   if(tree) {
1120     ti = proto_tree_add_item(tree, proto_ppp, 0+offset, 2, NULL);
1121     fh_tree = proto_item_add_subtree(ti, ett_ppp);
1122   }
1123
1124   dissect_ppp_stuff(pd, offset, fd, tree, fh_tree);
1125 }
1126
1127 void
1128 dissect_ppp( const u_char *pd, frame_data *fd, proto_tree *tree ) {
1129   e_ppphdr   ph;
1130   proto_item *ti;
1131   proto_tree *fh_tree = NULL;
1132
1133   ph.ppp_addr = pd[0];
1134   ph.ppp_ctl  = pd[1];
1135   ph.ppp_prot = pntohs(&pd[2]);
1136
1137   /* load the top pane info. This should be overwritten by
1138      the next protocol in the stack */
1139
1140   if(check_col(fd, COL_RES_DL_SRC))
1141     col_add_str(fd, COL_RES_DL_SRC, "N/A" );
1142   if(check_col(fd, COL_RES_DL_DST))
1143     col_add_str(fd, COL_RES_DL_DST, "N/A" );
1144   if(check_col(fd, COL_PROTOCOL))
1145     col_add_str(fd, COL_PROTOCOL, "PPP" );
1146
1147   /* populate a tree in the second pane with the status of the link
1148      layer (ie none) */
1149   if(tree) {
1150     ti = proto_tree_add_item(tree, proto_ppp, 0, 4, NULL);
1151     fh_tree = proto_item_add_subtree(ti, ett_ppp);
1152     proto_tree_add_text(fh_tree, 0, 1, "Address: %02x", ph.ppp_addr);
1153     proto_tree_add_text(fh_tree, 1, 1, "Control: %02x", ph.ppp_ctl);
1154   }
1155
1156   if (!dissect_ppp_stuff(pd, 2, fd, tree, fh_tree)) {
1157     if (check_col(fd, COL_PROTOCOL))
1158       col_add_fstr(fd, COL_PROTOCOL, "0x%04x", ph.ppp_prot);
1159   }
1160 }
1161
1162 void
1163 proto_register_ppp(void)
1164 {
1165 /*        static hf_register_info hf[] = {
1166                 { &variable,
1167                 { "Name",           "ppp.abbreviation", TYPE, VALS_POINTER }},
1168         };*/
1169         static gint *ett[] = {
1170                 &ett_ppp,
1171                 &ett_ipcp,
1172                 &ett_ipcp_options,
1173                 &ett_ipcp_ipaddrs_opt,
1174                 &ett_ipcp_compressprot_opt,
1175                 &ett_lcp,
1176                 &ett_lcp_options,
1177                 &ett_lcp_mru_opt,
1178                 &ett_lcp_async_map_opt,
1179                 &ett_lcp_authprot_opt,
1180                 &ett_lcp_qualprot_opt,
1181                 &ett_lcp_magicnum_opt,
1182                 &ett_lcp_fcs_alternatives_opt,
1183                 &ett_lcp_numbered_mode_opt,
1184                 &ett_lcp_callback_opt,
1185                 &ett_lcp_multilink_ep_disc_opt,
1186                 &ett_lcp_internationalization_opt,
1187         };
1188
1189         proto_ppp = proto_register_protocol("Point-to-Point Protocol", "ppp");
1190  /*       proto_register_field_array(proto_ppp, hf, array_length(hf));*/
1191         proto_register_subtree_array(ett, array_length(ett));
1192 }
1193
1194 void
1195 proto_register_mp(void)
1196 {
1197   static hf_register_info hf[] = {
1198     { &hf_mp_frag_first,
1199     { "First fragment",         "mp.first",     FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1200         "" }},
1201
1202     { &hf_mp_frag_last,
1203     { "Last fragment",          "mp.last",      FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1204         "" }},
1205
1206     { &hf_mp_sequence_num,
1207     { "Sequence number",        "mp.seq",       FT_UINT32, BASE_DEC, NULL, 0x0,
1208         "" }}
1209   };
1210   static gint *ett[] = {
1211     &ett_mp,
1212     &ett_mp_flags,
1213   };
1214
1215   proto_mp = proto_register_protocol("PPP Multilink Protocol", "mp");
1216   proto_register_field_array(proto_mp, hf, array_length(hf));
1217   proto_register_subtree_array(ett, array_length(ett));
1218 }