Updates from Ed Warnicke.
[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.48 2000/12/14 08:20:29 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 "prefs.h"
37 #include "packet.h"
38 #include "packet-ppp.h"
39 #include "ppptypes.h"
40 #include "packet-atalk.h"
41 #include "packet-ip.h"
42 #include "packet-ipv6.h"
43 #include "packet-ipx.h"
44 #include "packet-vines.h"
45
46 static int proto_ppp = -1;
47
48 static gint ett_ppp = -1;
49 static gint ett_ipcp = -1;
50 static gint ett_ipcp_options = -1;
51 static gint ett_ipcp_ipaddrs_opt = -1;
52 static gint ett_ipcp_compressprot_opt = -1;
53 static gint ett_lcp = -1;
54 static gint ett_lcp_options = -1;
55 static gint ett_lcp_mru_opt = -1;
56 static gint ett_lcp_async_map_opt = -1;
57 static gint ett_lcp_authprot_opt = -1;
58 static gint ett_lcp_qualprot_opt = -1;
59 static gint ett_lcp_magicnum_opt = -1;
60 static gint ett_lcp_fcs_alternatives_opt = -1;
61 static gint ett_lcp_numbered_mode_opt = -1;
62 static gint ett_lcp_callback_opt = -1;
63 static gint ett_lcp_multilink_ep_disc_opt = -1;
64 static gint ett_lcp_internationalization_opt = -1;
65
66 static dissector_table_t subdissector_table;
67
68 static int proto_mp = -1;
69 static int hf_mp_frag_first = -1;
70 static int hf_mp_frag_last = -1;
71 static int hf_mp_sequence_num = -1;
72
73 static int ett_mp = -1;
74 static int ett_mp_flags = -1;
75
76 /* options */
77 static gint ppp_fcs_decode = 0; /* 0 = No FCS, 1 = 16 bit FCS, 2 = 32 bit FCS */
78 #define NO_FCS 0
79 #define FCS_16 1
80 #define FCS_32 2
81
82 /* PPP structs and definitions */
83
84 typedef struct _e_ppphdr {
85   guint8  ppp_addr;
86   guint8  ppp_ctl;
87   guint16 ppp_prot;
88 } e_ppphdr;
89
90 static const value_string ppp_vals[] = {
91         {PPP_IP,        "IP"             },
92         {PPP_AT,        "Appletalk"      },
93         {PPP_IPX,       "Netware IPX/SPX"},
94         {PPP_VJC_COMP,  "VJ compressed TCP"},
95         {PPP_VJC_UNCOMP,"VJ uncompressed TCP"}, 
96         {PPP_VINES,     "Vines"          },
97         {PPP_MP,        "Multilink"},
98         {PPP_IPV6,      "IPv6"           },
99         {PPP_COMP,      "compressed packet" },
100         {PPP_IPCP,      "IP Control Protocol" },
101         {PPP_ATCP,      "AppleTalk Control Protocol" },
102         {PPP_IPXCP,     "IPX Control Protocol" },
103         {PPP_CCP,       "Compression Control Protocol" },
104         {PPP_LCP,       "Link Control Protocol" },
105         {PPP_PAP,       "Password Authentication Protocol"  },
106         {PPP_LQR,       "Link Quality Report protocol" },
107         {PPP_CHAP,      "Cryptographic Handshake Auth. Protocol" },
108         {PPP_CBCP,      "Callback Control Protocol" },
109         {PPP_MPLS_UNI,  "MPLS Uni-cast"},
110         {PPP_MPLS_MULTI, "MPLS Multi-cast"},
111         {CISCO_IP,      "CISCO HDLC IP"},
112         {CISCO_SLARP,   "CISCO HDLC SLARP"},
113         {0,             NULL            }
114 };
115
116 /* CP (LCP, IPCP, etc.) codes.
117  * from pppd fsm.h 
118  */
119 #define CONFREQ    1  /* Configuration Request */
120 #define CONFACK    2  /* Configuration Ack */
121 #define CONFNAK    3  /* Configuration Nak */
122 #define CONFREJ    4  /* Configuration Reject */
123 #define TERMREQ    5  /* Termination Request */
124 #define TERMACK    6  /* Termination Ack */
125 #define CODEREJ    7  /* Code Reject */
126
127 static const value_string cp_vals[] = {
128         {CONFREQ,    "Configuration Request" },
129         {CONFACK,    "Configuration Ack" },
130         {CONFNAK,    "Configuration Nak" },
131         {CONFREJ,    "Configuration Reject" },
132         {TERMREQ,    "Termination Request" },
133         {TERMACK,    "Termination Ack" },
134         {CODEREJ,    "Code Reject" },
135         {0,          NULL            } };
136
137 /*
138  * LCP-specific packet types.
139  */
140 #define PROTREJ    8  /* Protocol Reject */
141 #define ECHOREQ    9  /* Echo Request */
142 #define ECHOREP    10 /* Echo Reply */
143 #define DISCREQ    11 /* Discard Request */
144 #define IDENT      12 /* Identification */
145 #define TIMEREMAIN 13 /* Time remaining */
146
147 #define CBCP_OPT  6 /* Use callback control protocol */
148
149 static const value_string lcp_vals[] = {
150         {CONFREQ,    "Configuration Request" },
151         {CONFACK,    "Configuration Ack" },
152         {CONFNAK,    "Configuration Nak" },
153         {CONFREJ,    "Configuration Reject" },
154         {TERMREQ,    "Termination Request" },
155         {TERMACK,    "Termination Ack" },
156         {CODEREJ,    "Code Reject" },
157         {PROTREJ,    "Protocol Reject" },
158         {ECHOREQ,    "Echo Request" },
159         {ECHOREP,    "Echo Reply" },
160         {DISCREQ,    "Discard Request" },
161         {IDENT,      "Identification" },
162         {TIMEREMAIN, "Time Remaining" },
163         {0,          NULL }
164 };
165
166 /*
167  * Options.  (LCP)
168  */
169 #define CI_MRU                  1       /* Maximum Receive Unit */
170 #define CI_ASYNCMAP             2       /* Async Control Character Map */
171 #define CI_AUTHTYPE             3       /* Authentication Type */
172 #define CI_QUALITY              4       /* Quality Protocol */
173 #define CI_MAGICNUMBER          5       /* Magic Number */
174 #define CI_PCOMPRESSION         7       /* Protocol Field Compression */
175 #define CI_ACCOMPRESSION        8       /* Address/Control Field Compression */
176 #define CI_FCS_ALTERNATIVES     9       /* FCS Alternatives (RFC 1570) */
177 #define CI_SELF_DESCRIBING_PAD  10      /* Self-Describing Pad (RFC 1570) */
178 #define CI_NUMBERED_MODE        11      /* Numbered Mode (RFC 1663) */
179 #define CI_CALLBACK             13      /* Callback (RFC 1570) */
180 #define CI_COMPOUND_FRAMES      15      /* Compound frames (RFC 1570) */
181 #define CI_MULTILINK_MRRU       17      /* Multilink MRRU (RFC 1717) */
182 #define CI_MULTILINK_SSNH       18      /* Multilink Short Sequence Number
183                                            Header (RFC 1717) */
184 #define CI_MULTILINK_EP_DISC    19      /* Multilink Endpoint Discriminator
185                                            (RFC 1717) */
186 #define CI_DCE_IDENTIFIER       21      /* DCE Identifier */
187 #define CI_MULTILINK_PLUS_PROC  22      /* Multilink Plus Procedure */
188 #define CI_LINK_DISC_FOR_BACP   23      /* Link Discriminator for BACP
189                                            (RFC 2125) */
190 #define CI_LCP_AUTHENTICATION   24      /* LCP Authentication Option */
191 #define CI_COBS                 25      /* Consistent Overhead Byte
192                                            Stuffing */
193 #define CI_PREFIX_ELISION       26      /* Prefix elision */
194 #define CI_MULTILINK_HDR_FMT    27      /* Multilink header format */
195 #define CI_INTERNATIONALIZATION 28      /* Internationalization (RFC 2484) */
196 #define CI_SDL_ON_SONET_SDH     29      /* Simple Data Link on SONET/SDH */
197
198 static void dissect_lcp_mru_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
199                         int offset, guint length, frame_data *fd,
200                         proto_tree *tree);
201 static void dissect_lcp_async_map_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
202                         int offset, guint length, frame_data *fd,
203                         proto_tree *tree);
204 static void dissect_lcp_protocol_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
205                         int offset, guint length, frame_data *fd,
206                         proto_tree *tree);
207 static void dissect_lcp_magicnumber_opt(const ip_tcp_opt *optp,
208                         tvbuff_t *tvb, int offset, guint length,
209                         frame_data *fd, proto_tree *tree);
210 static void dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp,
211                         tvbuff_t *tvb, int offset, guint length,
212                         frame_data *fd, proto_tree *tree);
213 static void dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp,
214                         tvbuff_t *tvb, int offset, guint length,
215                         frame_data *fd, proto_tree *tree);
216 static void dissect_lcp_self_describing_pad_opt(const ip_tcp_opt *optp,
217                         tvbuff_t *tvb, int offset, guint length,
218                         frame_data *fd, proto_tree *tree);
219 static void dissect_lcp_callback_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
220                         int offset, guint length, frame_data *fd,
221                         proto_tree *tree);
222 static void dissect_lcp_multilink_mrru_opt(const ip_tcp_opt *optp,
223                         tvbuff_t *tvb, int offset, guint length,
224                         frame_data *fd, proto_tree *tree);
225 static void dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp,
226                         tvbuff_t *tvb, int offset, guint length,
227                         frame_data *fd, proto_tree *tree);
228 static void dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp,
229                         tvbuff_t *tvb, int offset, guint length,
230                         frame_data *fd, proto_tree *tree);
231 static void dissect_lcp_internationalization_opt(const ip_tcp_opt *optp,
232                         tvbuff_t *tvb, int offset, guint length,
233                         frame_data *fd, proto_tree *tree);
234 static void dissect_mp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree);
235
236 static const ip_tcp_opt lcp_opts[] = {
237         {
238                 CI_MRU,
239                 "Maximum Receive Unit",
240                 &ett_lcp_mru_opt,
241                 FIXED_LENGTH,
242                 4,
243                 dissect_lcp_mru_opt
244         },
245         {
246                 CI_ASYNCMAP,
247                 "Async Control Character Map",
248                 &ett_lcp_async_map_opt,
249                 FIXED_LENGTH,
250                 6,
251                 dissect_lcp_async_map_opt
252         },
253         {
254                 CI_AUTHTYPE,
255                 "Authentication protocol",
256                 &ett_lcp_authprot_opt,
257                 VARIABLE_LENGTH,
258                 4,
259                 dissect_lcp_protocol_opt
260         },
261         {
262                 CI_QUALITY,
263                 "Quality protocol",
264                 &ett_lcp_qualprot_opt,
265                 VARIABLE_LENGTH,
266                 4,
267                 dissect_lcp_protocol_opt
268         },
269         {
270                 CI_MAGICNUMBER,
271                 NULL,
272                 &ett_lcp_magicnum_opt,
273                 FIXED_LENGTH,
274                 6,
275                 dissect_lcp_magicnumber_opt
276         },
277         {
278                 CI_PCOMPRESSION,
279                 "Protocol field compression",
280                 NULL,
281                 FIXED_LENGTH,
282                 2,
283                 NULL
284         },
285         {
286                 CI_ACCOMPRESSION,
287                 "Address/control field compression",
288                 NULL,
289                 FIXED_LENGTH,
290                 2,
291                 NULL
292         },
293         {
294                 CI_FCS_ALTERNATIVES,
295                 NULL,
296                 &ett_lcp_fcs_alternatives_opt,
297                 FIXED_LENGTH,
298                 3,
299                 dissect_lcp_fcs_alternatives_opt
300         },
301         {
302                 CI_SELF_DESCRIBING_PAD,
303                 NULL,
304                 NULL,
305                 FIXED_LENGTH,
306                 3,
307                 dissect_lcp_self_describing_pad_opt
308         },
309         {
310                 CI_NUMBERED_MODE,
311                 "Numbered mode",
312                 &ett_lcp_numbered_mode_opt,
313                 VARIABLE_LENGTH,
314                 4,
315                 dissect_lcp_numbered_mode_opt
316         },
317         {
318                 CI_CALLBACK,
319                 "Callback",
320                 &ett_lcp_callback_opt,
321                 VARIABLE_LENGTH,
322                 3,
323                 dissect_lcp_callback_opt,
324         },
325         {
326                 CI_COMPOUND_FRAMES,
327                 "Compound frames",
328                 NULL,
329                 FIXED_LENGTH,
330                 2,
331                 NULL
332         },
333         {
334                 CI_MULTILINK_MRRU,
335                 NULL,
336                 NULL,
337                 FIXED_LENGTH,
338                 4,
339                 dissect_lcp_multilink_mrru_opt
340         },
341         {
342                 CI_MULTILINK_SSNH,
343                 "Use short sequence number headers",
344                 NULL,
345                 FIXED_LENGTH,
346                 2,
347                 NULL
348         },
349         {
350                 CI_MULTILINK_EP_DISC,
351                 "Multilink endpoint discriminator",
352                 &ett_lcp_multilink_ep_disc_opt,
353                 VARIABLE_LENGTH,
354                 3,
355                 dissect_lcp_multilink_ep_disc_opt,
356         },
357         {
358                 CI_DCE_IDENTIFIER,
359                 "DCE identifier",
360                 NULL,
361                 VARIABLE_LENGTH,
362                 2,
363                 NULL
364         },
365         {
366                 CI_MULTILINK_PLUS_PROC,
367                 "Multilink Plus Procedure",
368                 NULL,
369                 VARIABLE_LENGTH,
370                 2,
371                 NULL
372         },
373         {
374                 CI_LINK_DISC_FOR_BACP,
375                 NULL,
376                 NULL,
377                 FIXED_LENGTH,
378                 4,
379                 dissect_lcp_bap_link_discriminator_opt
380         },
381         {
382                 CI_LCP_AUTHENTICATION,
383                 "LCP authentication",
384                 NULL,
385                 VARIABLE_LENGTH,
386                 2,
387                 NULL
388         },
389         {
390                 CI_COBS,
391                 "Consistent Overhead Byte Stuffing",
392                 NULL,
393                 VARIABLE_LENGTH,
394                 2,
395                 NULL
396         },
397         {
398                 CI_PREFIX_ELISION,
399                 "Prefix elision",
400                 NULL,
401                 VARIABLE_LENGTH,
402                 2,
403                 NULL
404         },
405         {
406                 CI_MULTILINK_HDR_FMT,
407                 "Multilink header format",
408                 NULL,
409                 VARIABLE_LENGTH,
410                 2,
411                 NULL
412         },
413         {
414                 CI_INTERNATIONALIZATION,
415                 "Internationalization",
416                 &ett_lcp_internationalization_opt,
417                 VARIABLE_LENGTH,
418                 7,
419                 dissect_lcp_internationalization_opt
420         },
421         {
422                 CI_SDL_ON_SONET_SDH,
423                 "Simple data link on SONET/SDH",
424                 NULL,
425                 VARIABLE_LENGTH,
426                 2,
427                 NULL
428         }
429 };
430
431 #define N_LCP_OPTS      (sizeof lcp_opts / sizeof lcp_opts[0])
432
433 /*
434  * Options.  (IPCP)
435  */
436 #define CI_ADDRS        1       /* IP Addresses (deprecated) (RFC 1172) */
437 #define CI_COMPRESSTYPE 2       /* Compression Type (RFC 1332) */
438 #define CI_ADDR         3       /* IP Address (RFC 1332) */
439 #define CI_MOBILE_IPv4  4       /* Mobile IPv4 (RFC 2290) */
440 #define CI_MS_DNS1      129     /* Primary DNS value (RFC 1877) */
441 #define CI_MS_WINS1     130     /* Primary WINS value (RFC 1877) */
442 #define CI_MS_DNS2      131     /* Secondary DNS value (RFC 1877) */
443 #define CI_MS_WINS2     132     /* Secondary WINS value (RFC 1877) */
444
445 static void dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
446                         int offset, guint length, frame_data *fd,
447                         proto_tree *tree);
448 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
449                         int offset, guint length, frame_data *fd,
450                         proto_tree *tree);
451
452 static const ip_tcp_opt ipcp_opts[] = {
453         {
454                 CI_ADDRS,
455                 "IP addresses (deprecated)",
456                 &ett_ipcp_ipaddrs_opt,
457                 FIXED_LENGTH,
458                 10,
459                 dissect_ipcp_addrs_opt
460         },
461         {
462                 CI_COMPRESSTYPE,
463                 "IP compression protocol",
464                 &ett_ipcp_compressprot_opt,
465                 VARIABLE_LENGTH,
466                 4,
467                 dissect_lcp_protocol_opt
468         },
469         {
470                 CI_ADDR,
471                 "IP address",
472                 NULL,
473                 FIXED_LENGTH,
474                 6,
475                 dissect_ipcp_addr_opt
476         },
477         {
478                 CI_MOBILE_IPv4,
479                 "Mobile node's home IP address",
480                 NULL,
481                 FIXED_LENGTH,
482                 6,
483                 dissect_ipcp_addr_opt
484         },
485         {
486                 CI_MS_DNS1,
487                 "Primary DNS server IP address",
488                 NULL,
489                 FIXED_LENGTH,
490                 6,
491                 dissect_ipcp_addr_opt
492         },
493         {
494                 CI_MS_WINS1,
495                 "Primary WINS server IP address",
496                 NULL,
497                 FIXED_LENGTH,
498                 6,
499                 dissect_ipcp_addr_opt
500         },
501         {
502                 CI_MS_DNS2,
503                 "Secondary DNS server IP address",
504                 NULL,
505                 FIXED_LENGTH,
506                 6,
507                 dissect_ipcp_addr_opt
508         },
509         {
510                 CI_MS_WINS2,
511                 "Secondary WINS server IP address",
512                 NULL,
513                 FIXED_LENGTH,
514                 6,
515                 dissect_ipcp_addr_opt
516         }
517 };
518
519 #define N_IPCP_OPTS     (sizeof ipcp_opts / sizeof ipcp_opts[0])
520
521 const unsigned int fcstab_32[256] =
522       {
523       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
524       0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
525       0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
526       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
527       0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
528       0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
529       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
530       0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
531       0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
532       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
533       0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
534       0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
535       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
536       0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
537       0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
538       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
539       0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
540       0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
541       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
542       0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
543       0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
544       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
545       0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
546       0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
547       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
548       0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
549       0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
550       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
551       0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
552       0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
553       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
554       0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
555       0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
556       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
557       0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
558       0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
559       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
560       0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
561       0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
562       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
563       0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
564       0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
565       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
566       0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
567       0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
568       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
569       0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
570       0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
571       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
572       0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
573       0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
574       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
575       0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
576       0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
577       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
578       0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
579       0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
580       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
581       0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
582       0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
583       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
584       0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
585       0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
586       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
587       };
588
589 const unsigned short fcstab_16[256] = {
590         0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,
591         0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,
592         0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,
593         0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,
594         0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,
595         0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,
596         0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,
597         0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,
598         0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,
599         0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,
600         0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,
601         0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,
602         0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,
603         0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,
604         0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,
605         0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,
606         0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,
607         0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,
608         0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,
609         0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,
610         0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,
611         0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,
612         0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,
613         0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,
614         0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,
615         0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,
616         0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,
617         0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,
618         0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,
619         0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,
620         0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,
621         0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78
622     };
623   
624 /*
625 *******************************************************************************
626 * DETAILS : Calculate a new FCS-16 given the current FCS-16 and the new data.
627 *******************************************************************************
628 */
629 guint16
630 fcs16(register guint16 fcs,
631          tvbuff_t * tvbuff,
632          guint32 offset,
633          guint32 len)
634 {
635     guint8 val;
636     /* Check for Invalid Length */
637     if(len == 0)
638         return(0x0000);
639     while (len--) {
640                 val = tvb_get_guint8(tvbuff, offset++);
641                 fcs = (guint16)((fcs >> 8) & 0x00ff) ^
642             fcstab_16[((guint16)(fcs ^ (guint16)((val) & 0x00ff)) & 0x00ff)];
643         }
644
645     return (fcs ^ 0xffff);
646 }
647   
648 /*
649 *******************************************************************************
650 * DETAILS : Calculate a new FCS-32 given the current FCS-32 and the new data.
651 *******************************************************************************
652 */
653 guint32
654 fcs32(guint32 fcs,
655          tvbuff_t * tvbuff,
656          guint32 offset,
657          guint32 len)
658 {
659     guint8 val;
660     /* Check for invalid Length */
661     if(len <= 0)
662         return(0x00000000);
663
664     while (len--) {
665                 val = tvb_get_guint8(tvbuff, offset++);
666                 fcs = (((fcs) >> 8) ^ fcstab_32[((fcs) ^ (val)) & 0xff]);
667         }
668     return (fcs ^ 0xffffffff);
669 }
670
671 void
672 capture_ppp( const u_char *pd, int offset, packet_counts *ld ) {
673   switch (pntohs(&pd[offset + 2])) {
674     case PPP_IP:
675     case CISCO_IP:
676       capture_ip(pd, offset + 4, ld);
677       break;
678     case PPP_IPX:
679       capture_ipx(pd, offset + 4, ld);
680       break;
681     case PPP_VINES:
682       capture_vines(pd, offset + 4, ld);
683       break;
684     default:
685       ld->other++;
686       break;
687   }
688 }
689
690 static void
691 dissect_lcp_mru_opt(const ip_tcp_opt *optp, tvbuff_t *tvb, int offset,
692                         guint length, frame_data *fd, proto_tree *tree)
693 {
694   proto_tree_add_text(tree, tvb, offset, length, "MRU: %u",
695                         tvb_get_ntohs(tvb, offset + 2));
696 }
697
698 static void
699 dissect_lcp_async_map_opt(const ip_tcp_opt *optp, tvbuff_t *tvb, int offset,
700                         guint length, frame_data *fd, proto_tree *tree)
701 {
702   proto_tree_add_text(tree, tvb, offset, length, "Async characters to map: 0x%08x",
703                         tvb_get_ntohl(tvb, offset + 2));
704 }
705
706 static void
707 dissect_lcp_protocol_opt(const ip_tcp_opt *optp, tvbuff_t *tvb, int offset,
708                         guint length, frame_data *fd, proto_tree *tree)
709 {
710   guint16 protocol;
711   proto_item *tf;
712   proto_tree *field_tree = NULL;
713   
714   tf = proto_tree_add_text(tree, tvb, offset, length, "%s: %u byte%s",
715           optp->name, length, plurality(length, "", "s"));
716   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
717   offset += 2;
718   length -= 2;
719   protocol = tvb_get_ntohs(tvb, offset);
720   proto_tree_add_text(field_tree, tvb, offset, 2, "%s: %s (0x%02x)", optp->name,
721                 val_to_str(protocol, ppp_vals, "Unknown"), protocol);
722   offset += 2;
723   length -= 2;
724   if (length > 0)
725     proto_tree_add_text(field_tree, tvb, offset, length, "Data (%d byte%s)", length,
726                         plurality(length, "", "s"));
727 }
728
729 static void
730 dissect_lcp_magicnumber_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
731                         int offset, guint length, frame_data *fd,
732                         proto_tree *tree)
733 {
734   proto_tree_add_text(tree, tvb, offset, length, "Magic number: 0x%08x",
735                         tvb_get_ntohl(tvb, offset + 2));
736 }
737
738 static void
739 dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
740                         int offset, guint length, frame_data *fd,
741                         proto_tree *tree)
742 {
743   proto_item *tf;
744   proto_tree *field_tree = NULL;
745   guint8 alternatives;
746   
747   alternatives = tvb_get_guint8(tvb, offset + 2);
748   tf = proto_tree_add_text(tree, tvb, offset, length, "%s: 0x%02x",
749           optp->name, alternatives);
750   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
751   offset += 2;
752   if (alternatives & 0x1)
753     proto_tree_add_text(field_tree, tvb, offset + 2, 1, "%s",
754        decode_boolean_bitfield(alternatives, 0x1, 8, "Null FCS", NULL));
755   if (alternatives & 0x2)
756     proto_tree_add_text(field_tree, tvb, offset + 2, 1, "%s",
757        decode_boolean_bitfield(alternatives, 0x2, 8, "CCITT 16-bit FCS", NULL));
758   if (alternatives & 0x4)
759     proto_tree_add_text(field_tree, tvb, offset + 2, 1, "%s",
760        decode_boolean_bitfield(alternatives, 0x4, 8, "CCITT 32-bit FCS", NULL));
761 }
762
763 static void
764 dissect_lcp_self_describing_pad_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
765                         int offset, guint length, frame_data *fd,
766                         proto_tree *tree)
767 {
768   proto_tree_add_text(tree, tvb, offset, length,
769                         "Maximum octets of self-describing padding: %u",
770                         tvb_get_guint8(tvb, offset + 2));
771 }
772
773 static void
774 dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
775                         int offset, guint length, frame_data *fd,
776                         proto_tree *tree)
777 {
778   proto_item *tf;
779   proto_tree *field_tree = NULL;
780   
781   tf = proto_tree_add_text(tree, tvb, offset, length, "%s: %u byte%s",
782           optp->name, length, plurality(length, "", "s"));
783   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
784   offset += 2;
785   length -= 2;
786   proto_tree_add_text(field_tree, tvb, offset, 1, "Window: %u",
787                         tvb_get_guint8(tvb, offset));
788   offset += 1;
789   length -= 1;
790   if (length > 0)
791     proto_tree_add_text(field_tree, tvb, offset, length, "Address (%d byte%s)",
792                         length, plurality(length, "", "s"));
793 }
794
795 static const value_string callback_op_vals[] = {
796         {0, "Location is determined by user authentication" },
797         {1, "Message is dialing string" },
798         {2, "Message is location identifier" },
799         {3, "Message is E.164" },
800         {4, "Message is distinguished name" },
801         {0, NULL }
802 };
803
804 static void
805 dissect_lcp_callback_opt(const ip_tcp_opt *optp, tvbuff_t *tvb, int offset,
806                         guint length, frame_data *fd, proto_tree *tree)
807 {
808   proto_item *tf;
809   proto_tree *field_tree = NULL;
810   guint8 operation;
811   
812   tf = proto_tree_add_text(tree, tvb, offset, length, "%s: %u byte%s",
813           optp->name, length, plurality(length, "", "s"));
814   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
815   offset += 2;
816   length -= 2;
817   operation = tvb_get_guint8(tvb, offset);
818   proto_tree_add_text(field_tree, tvb, offset, 1, "Operation: %s (0x%02x)",
819                 val_to_str(operation, callback_op_vals, "Unknown"),
820                 operation);
821   offset += 1;
822   length -= 1;
823   if (length > 0)
824     proto_tree_add_text(field_tree, tvb, offset, length, "Message (%d byte%s)",
825                         length, plurality(length, "", "s"));
826 }
827
828 static void
829 dissect_lcp_multilink_mrru_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
830                         int offset, guint length, frame_data *fd,
831                         proto_tree *tree)
832 {
833   proto_tree_add_text(tree, tvb, offset, length, "Multilink MRRU: %u",
834                         tvb_get_ntohs(tvb, offset + 2));
835 }
836
837 #define CLASS_NULL                      0
838 #define CLASS_LOCAL                     1
839 #define CLASS_IP                        2
840 #define CLASS_IEEE_802_1                3
841 #define CLASS_PPP_MAGIC_NUMBER          4
842 #define CLASS_PSDN_DIRECTORY_NUMBER     5
843
844 static const value_string multilink_ep_disc_class_vals[] = {
845         {CLASS_NULL,                  "Null" },
846         {CLASS_LOCAL,                 "Locally assigned address" },
847         {CLASS_IP,                    "IP address" },
848         {CLASS_IEEE_802_1,            "IEEE 802.1 globally assigned MAC address" },
849         {CLASS_PPP_MAGIC_NUMBER,      "PPP magic-number block" },
850         {CLASS_PSDN_DIRECTORY_NUMBER, "Public switched network directory number" },
851         {0,                           NULL }
852 };
853
854 static void
855 dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
856                         int offset, guint length, frame_data *fd,
857                         proto_tree *tree)
858 {
859   proto_item *tf;
860   proto_tree *field_tree = NULL;
861   guint8 ep_disc_class;
862
863   tf = proto_tree_add_text(tree, tvb, offset, length, "%s: %u byte%s",
864           optp->name, length, plurality(length, "", "s"));
865   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
866   offset += 2;
867   length -= 2;
868   ep_disc_class = tvb_get_guint8(tvb, offset);
869   proto_tree_add_text(field_tree, tvb, offset, 1, "Class: %s (%u)",
870                 val_to_str(ep_disc_class, multilink_ep_disc_class_vals, "Unknown"),
871                 ep_disc_class);
872   offset += 1;
873   length -= 1;
874   if (length > 0) {
875     switch (ep_disc_class) {
876
877     case CLASS_NULL:
878       proto_tree_add_text(field_tree, tvb, offset, length,
879                         "Address (%d byte%s), should have been empty",
880                         length, plurality(length, "", "s"));
881       break;
882
883     case CLASS_LOCAL:
884       if (length > 20) {
885         proto_tree_add_text(field_tree, tvb, offset, length,
886                         "Address (%d byte%s), should have been <20",
887                         length, plurality(length, "", "s"));
888       } else {
889         proto_tree_add_text(field_tree, tvb, offset, length,
890                         "Address (%d byte%s)",
891                         length, plurality(length, "", "s"));
892       }
893       break;
894
895     case CLASS_IP:
896       if (length != 4) {
897         proto_tree_add_text(field_tree, tvb, offset, length,
898                         "Address (%d byte%s), should have been 4",
899                         length, plurality(length, "", "s"));
900       } else {
901         proto_tree_add_text(field_tree, tvb, offset, length,
902                         "Address: %s", ip_to_str(tvb_get_ptr(tvb, offset, 4)));
903       }
904       break;
905
906     case CLASS_IEEE_802_1:
907       if (length != 6) {
908         proto_tree_add_text(field_tree, tvb, offset, length,
909                         "Address (%d byte%s), should have been 6",
910                         length, plurality(length, "", "s"));
911       } else {
912         proto_tree_add_text(field_tree, tvb, offset, length,
913                         "Address: %s", ether_to_str(tvb_get_ptr(tvb, offset, 6)));
914       }
915       break;
916
917     case CLASS_PPP_MAGIC_NUMBER:
918       /* XXX - dissect as 32-bit magic numbers */
919       if (length > 20) {
920         proto_tree_add_text(field_tree, tvb, offset, length,
921                         "Address (%d byte%s), should have been <20",
922                         length, plurality(length, "", "s"));
923       } else {
924         proto_tree_add_text(field_tree, tvb, offset, length,
925                         "Address (%d byte%s)",
926                         length, plurality(length, "", "s"));
927       }
928       break;
929
930     case CLASS_PSDN_DIRECTORY_NUMBER:
931       if (length > 15) {
932         proto_tree_add_text(field_tree, tvb, offset, length,
933                         "Address (%d byte%s), should have been <20",
934                         length, plurality(length, "", "s"));
935       } else {
936         proto_tree_add_text(field_tree, tvb, offset, length,
937                         "Address (%d byte%s)",
938                         length, plurality(length, "", "s"));
939       }
940       break;
941
942     default:
943       proto_tree_add_text(field_tree, tvb, offset, length,
944                         "Address (%d byte%s)",
945                         length, plurality(length, "", "s"));
946       break;
947     }
948   }
949 }
950
951 static void
952 dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
953                         int offset, guint length, frame_data *fd,
954                         proto_tree *tree)
955 {
956   proto_tree_add_text(tree, tvb, offset, length,
957                         "Link discriminator for BAP: 0x%04x",
958                         tvb_get_ntohs(tvb, offset + 2));
959 }
960
961 /* Character set numbers from the IANA charset registry. */
962 static const value_string charset_num_vals[] = {
963         {105, "UTF-8" },
964         {0,   NULL }
965 };
966
967 static void
968 dissect_lcp_internationalization_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
969                         int offset, guint length, frame_data *fd,
970                         proto_tree *tree)
971 {
972   proto_item *tf;
973   proto_tree *field_tree = NULL;
974   guint32 charset;
975   
976   tf = proto_tree_add_text(tree, tvb, offset, length, "%s: %u byte%s",
977           optp->name, length, plurality(length, "", "s"));
978   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
979   offset += 2;
980   length -= 2;
981   charset = tvb_get_ntohl(tvb, offset);
982   proto_tree_add_text(field_tree, tvb, offset, 4, "Character set: %s (0x%04x)",
983                 val_to_str(charset, charset_num_vals, "Unknown"),
984                 charset);
985   offset += 4;
986   length -= 4;
987   if (length > 0) {
988     /* XXX - should be displayed as an ASCII string */
989     proto_tree_add_text(field_tree, tvb, offset, length, "Language tag (%d byte%s)",
990                         length, plurality(length, "", "s"));
991   }
992 }
993
994 static void
995 dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
996                         int offset, guint length, frame_data *fd,
997                         proto_tree *tree)
998 {
999   proto_item *tf;
1000   proto_tree *field_tree = NULL;
1001   
1002   tf = proto_tree_add_text(tree, tvb, offset, length, "%s: %u byte%s",
1003           optp->name, length, plurality(length, "", "s"));
1004   field_tree = proto_item_add_subtree(tf, *optp->subtree_index);
1005   offset += 2;
1006   length -= 2;
1007   proto_tree_add_text(field_tree, tvb, offset, 4,
1008                         "Source IP address: %s",
1009                         ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1010   offset += 4;
1011   length -= 4;
1012   proto_tree_add_text(field_tree, tvb, offset, 4,
1013                         "Destination IP address: %s",
1014                         ip_to_str(tvb_get_ptr(tvb, offset, 4)));
1015 }
1016
1017 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, tvbuff_t *tvb,
1018                         int offset, guint length, frame_data *fd,
1019                         proto_tree *tree)
1020 {
1021   proto_tree_add_text(tree, tvb, offset, length, "%s: %s", optp->name,
1022                         ip_to_str(tvb_get_ptr(tvb, offset + 2, 4)));
1023 }
1024
1025 static void
1026 dissect_cp( tvbuff_t *tvb, const char *proto_short_name,
1027         const char *proto_long_name, int proto_subtree_index,
1028         const value_string *proto_vals, int options_subtree_index,
1029         const ip_tcp_opt *opts, int nopts, packet_info *pinfo, proto_tree *tree ) {
1030   proto_item *ti;
1031   proto_tree *fh_tree = NULL;
1032   proto_item *tf;
1033   proto_tree *field_tree;
1034
1035   guint8 code;
1036   guint8 id;
1037   int length, offset;
1038   guint16 protocol;
1039
1040   code = tvb_get_guint8(tvb, 0);
1041   id = tvb_get_guint8(tvb, 1);
1042   length = tvb_get_ntohs(tvb, 2);
1043
1044   if(check_col(pinfo->fd, COL_INFO))
1045         col_add_fstr(pinfo->fd, COL_INFO, "%sCP %s", proto_short_name,
1046                 val_to_str(code, proto_vals, "Unknown"));
1047
1048   if(tree) {
1049     ti = proto_tree_add_text(tree, tvb, 0, 4, "%s Control Protocol",
1050                                 proto_long_name);
1051     fh_tree = proto_item_add_subtree(ti, proto_subtree_index);
1052     proto_tree_add_text(fh_tree, tvb, 0, 1, "Code: %s (0x%02x)",
1053       val_to_str(code, proto_vals, "Unknown"), code);
1054     proto_tree_add_text(fh_tree, tvb, 1, 1, "Identifier: 0x%02x",
1055                         id);
1056     proto_tree_add_text(fh_tree, tvb, 2, 2, "Length: %u",
1057                         length);
1058   }
1059   offset = 4;
1060   length -= 4;
1061
1062   switch (code) {
1063     case CONFREQ:
1064     case CONFACK:
1065     case CONFNAK:
1066     case CONFREJ:
1067       if(tree) {
1068         if (length > 0) {
1069           tf = proto_tree_add_text(fh_tree, tvb, offset, length,
1070             "Options: (%d byte%s)", length, plurality(length, "", "s"));
1071           field_tree = proto_item_add_subtree(tf, options_subtree_index);
1072           dissect_ip_tcp_options(tvb, offset, length, opts, nopts, -1,
1073                                  pinfo->fd, field_tree);
1074         }
1075       }
1076       break;
1077
1078     case ECHOREQ:
1079     case ECHOREP:
1080     case DISCREQ:
1081     case IDENT:
1082       if(tree) {
1083         proto_tree_add_text(fh_tree, tvb, offset, 4, "Magic number: 0x%08x",
1084                         tvb_get_ntohl(tvb, offset));
1085         offset += 4;
1086         length -= 4;
1087         if (length > 0)
1088           proto_tree_add_text(fh_tree, tvb, offset, length, "Message (%d byte%s)",
1089                                 length, plurality(length, "", "s"));
1090       }
1091       break;
1092
1093     case TIMEREMAIN:
1094       if(tree) {
1095         proto_tree_add_text(fh_tree, tvb, offset, 4, "Magic number: 0x%08x",
1096                         tvb_get_ntohl(tvb, offset));
1097         offset += 4;
1098         length -= 4;
1099         proto_tree_add_text(fh_tree, tvb, offset, 4, "Seconds remaining: %u",
1100                         tvb_get_ntohl(tvb, offset));
1101         offset += 4;
1102         length -= 4;
1103         if (length > 0)
1104           proto_tree_add_text(fh_tree, tvb, offset, length, "Message (%d byte%s)",
1105                                 length, plurality(length, "", "s"));
1106       }
1107       break;
1108
1109     case PROTREJ:
1110       if(tree) {
1111         protocol = tvb_get_ntohs(tvb, offset);
1112         proto_tree_add_text(fh_tree, tvb, offset, 2, "Rejected protocol: %s (0x%04x)",
1113                 val_to_str(protocol, ppp_vals, "Unknown"), protocol);
1114         offset += 2;
1115         length -= 2;
1116         if (length > 0)
1117           proto_tree_add_text(fh_tree, tvb, offset, length, "Rejected packet (%d byte%s)",
1118                                 length, plurality(length, "", "s"));
1119                 /* XXX - should be dissected as a PPP packet */
1120       }
1121       break;
1122
1123     case CODEREJ:
1124                 /* decode the rejected LCP packet here. */
1125       if (length > 0)
1126         proto_tree_add_text(fh_tree, tvb, offset, length, "Rejected packet (%d byte%s)",
1127                                 length, plurality(length, "", "s"));
1128       break;
1129
1130     case TERMREQ:
1131     case TERMACK:
1132       if (length > 0)
1133         proto_tree_add_text(fh_tree, tvb, offset, length, "Data (%d byte%s)",
1134                                 length, plurality(length, "", "s"));
1135       break;
1136
1137     default:
1138       if (length > 0)
1139         proto_tree_add_text(fh_tree, tvb, offset, length, "Stuff (%d byte%s)",
1140                                 length, plurality(length, "", "s"));
1141       break;
1142   }
1143 }
1144
1145 /* Protocol field compression */
1146 #define PFC_BIT 0x01
1147
1148 static gboolean
1149 dissect_ppp_stuff( tvbuff_t *tvb, packet_info *pinfo,
1150                 proto_tree *tree, proto_tree *fh_tree ) {
1151   guint16 ppp_prot;
1152   int     proto_len;
1153   tvbuff_t      *next_tvb;
1154
1155   if (tvb_get_guint8(tvb, 0) & PFC_BIT) {
1156     ppp_prot = tvb_get_guint8(tvb, 0);
1157     proto_len = 1;
1158   } else {
1159     ppp_prot = tvb_get_ntohs(tvb, 0);
1160     proto_len = 2;
1161   }
1162
1163   if (tree) {
1164     proto_tree_add_text(fh_tree, tvb, 0, proto_len, "Protocol: %s (0x%04x)",
1165       val_to_str(ppp_prot, ppp_vals, "Unknown"), ppp_prot);
1166   }
1167
1168   next_tvb = tvb_new_subset(tvb, proto_len, -1, -1);
1169
1170   /* do lookup with the subdissector table */
1171   if (dissector_try_port(subdissector_table, ppp_prot, next_tvb, pinfo, tree))
1172       return TRUE;
1173
1174   /* XXX - make "dissect_lcp()" and "dissect_ipcp()", have them just
1175      call "dissect_cp()", and register them as well?
1176
1177      We can do that for "dissect_mp()", too. */
1178   switch (ppp_prot) {
1179     case PPP_MP:
1180       dissect_mp(next_tvb, pinfo, tree);
1181       return TRUE;
1182     case PPP_LCP:
1183       dissect_cp(next_tvb, "L", "Link", ett_lcp, lcp_vals, ett_lcp_options,
1184                 lcp_opts, N_LCP_OPTS, pinfo, tree);
1185       return TRUE;
1186     case PPP_IPCP:
1187       dissect_cp(next_tvb, "IP", "IP", ett_ipcp, cp_vals, ett_ipcp_options,
1188                 ipcp_opts, N_IPCP_OPTS, pinfo, tree);
1189       return TRUE;
1190     default:
1191       if (check_col(pinfo->fd, COL_INFO))
1192         col_add_fstr(pinfo->fd, COL_INFO, "PPP %s (0x%04x)",
1193                 val_to_str(ppp_prot, ppp_vals, "Unknown"), ppp_prot);
1194       dissect_data(next_tvb, 0, pinfo, tree);
1195       return FALSE;
1196   }
1197 }
1198
1199 #define MP_FRAG_MASK     0xC0
1200 #define MP_FRAG(bits)    ((bits) & MP_FRAG_MASK)
1201 #define MP_FRAG_FIRST    0x80
1202 #define MP_FRAG_LAST     0x40
1203 #define MP_FRAG_RESERVED 0x3f
1204
1205 /* According to RFC 1717, the length the MP header isn't indicated anywhere
1206    in the header itself.  It starts out at four bytes and can be
1207    negotiated down to two using LCP.  We currently assume that all
1208    headers are four bytes.  - gcc
1209  */
1210 static void
1211 dissect_mp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
1212 {
1213   proto_tree *mp_tree, *hdr_tree, *fh_tree = NULL;
1214   proto_item *ti;
1215   guint8      flags;
1216   guint32     seq;
1217   gchar       *flag_str;
1218   int         first, last;
1219   tvbuff_t      *next_tvb;
1220
1221   CHECK_DISPLAY_AS_DATA(proto_mp, tvb, pinfo, tree);
1222
1223   flags = tvb_get_guint8(tvb, 0);
1224   first = flags && MP_FRAG_FIRST;
1225   last  = flags && MP_FRAG_LAST;
1226   seq   = tvb_get_ntoh24(tvb, 1);
1227
1228   if (check_col(pinfo->fd, COL_INFO))
1229     col_add_fstr(pinfo->fd, COL_INFO, "PPP Multilink");
1230
1231   if (tree) {
1232     switch (flags) {
1233       case MP_FRAG_FIRST:
1234         flag_str = "First";
1235         break;
1236       case MP_FRAG_LAST:
1237         flag_str = "Last";
1238         break;
1239       case MP_FRAG_FIRST|MP_FRAG_LAST:
1240         flag_str = "First, Last";
1241         break;
1242       default:
1243         flag_str = "Unknown";
1244         break;
1245     }
1246     ti = proto_tree_add_item(tree, proto_mp, tvb, 0, 4, FALSE);
1247     mp_tree = proto_item_add_subtree(ti, ett_mp);
1248     ti = proto_tree_add_text(mp_tree, tvb, 0, 1, "Fragment: 0x%2X (%s)",
1249       flags, flag_str);
1250     hdr_tree = proto_item_add_subtree(ti, ett_mp_flags);
1251     proto_tree_add_boolean_format(hdr_tree, hf_mp_frag_first, tvb, 0, 1, first,
1252       "%s", decode_boolean_bitfield(flags, MP_FRAG_FIRST, sizeof(flags) * 8,
1253         "first", "not first"));
1254     proto_tree_add_boolean_format(hdr_tree, hf_mp_frag_last, tvb, 0, 1, last,
1255       "%s", decode_boolean_bitfield(flags, MP_FRAG_LAST, sizeof(flags) * 8,
1256         "last", "not last"));
1257     proto_tree_add_text(hdr_tree, tvb, 0, 1, "%s",
1258       decode_boolean_bitfield(flags, MP_FRAG_RESERVED, sizeof(flags) * 8,
1259         "reserved", "reserved"));
1260     proto_tree_add_uint(mp_tree, hf_mp_sequence_num, tvb,  1, 3, seq);
1261  }
1262
1263   next_tvb = tvb_new_subset(tvb, 4, -1, -1);
1264
1265   if (tvb_length(next_tvb) > 0) {
1266           if (tree) {
1267             ti = proto_tree_add_item(tree, proto_ppp, next_tvb, 0, 1, FALSE);
1268             fh_tree = proto_item_add_subtree(ti, ett_ppp);
1269           }
1270           dissect_ppp_stuff(next_tvb, pinfo, tree, fh_tree);
1271   }
1272 }
1273
1274 static void
1275 dissect_payload_ppp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
1276   proto_item *ti;
1277   proto_tree *fh_tree = NULL;
1278
1279   /* XXX - the length shouldn't be 2, it should be based on the length
1280      of the protocol field. */
1281   if(tree) {
1282     ti = proto_tree_add_item(tree, proto_ppp, tvb, 0, 2, FALSE);
1283     fh_tree = proto_item_add_subtree(ti, ett_ppp);
1284   }
1285
1286   dissect_ppp_stuff(tvb, pinfo, tree, fh_tree);
1287 }
1288
1289 static void
1290 dissect_ppp( tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree ) {
1291   e_ppphdr   ph;
1292   proto_item *ti;
1293   proto_tree *fh_tree = NULL;
1294   int        proto_offset;
1295   tvbuff_t   *next_tvb;
1296   guint8     byte0;
1297   guint32    rx_fcs_exp;
1298   guint32    rx_fcs_got;
1299
1300   CHECK_DISPLAY_AS_DATA(proto_ppp, tvb, pinfo, tree);
1301
1302   pinfo->current_proto = "PPP";
1303   byte0 = tvb_get_guint8(tvb, 0);
1304
1305   if (byte0 == 0xff) {
1306     ph.ppp_addr = tvb_get_guint8(tvb, 0);
1307     ph.ppp_ctl  = tvb_get_guint8(tvb, 1);
1308     ph.ppp_prot = tvb_get_ntohs(tvb, 2);
1309     proto_offset =  2;
1310   }
1311   /* Cisco HDLC format */
1312   else if (byte0 == 0x0f) {
1313     ph.ppp_addr = tvb_get_guint8(tvb, 0);
1314     ph.ppp_ctl  = tvb_get_guint8(tvb, 1);
1315     ph.ppp_prot = tvb_get_ntohs(tvb, 2);
1316     proto_offset =  2;
1317   }
1318   else {
1319     /* address and control are compressed (NULL) */
1320     ph.ppp_prot = tvb_get_ntohs(tvb, 0);
1321     proto_offset = 0;
1322   }
1323
1324   /* load the top pane info. This should be overwritten by
1325      the next protocol in the stack */
1326
1327   if(check_col(pinfo->fd, COL_RES_DL_SRC))
1328     col_set_str(pinfo->fd, COL_RES_DL_SRC, "N/A" );
1329   if(check_col(pinfo->fd, COL_RES_DL_DST))
1330     col_set_str(pinfo->fd, COL_RES_DL_DST, "N/A" );
1331   if(check_col(pinfo->fd, COL_PROTOCOL))
1332     col_set_str(pinfo->fd, COL_PROTOCOL, "PPP" );
1333
1334   if(tree) {
1335     ti = proto_tree_add_item(tree, proto_ppp, tvb, 0, 4, FALSE);
1336     fh_tree = proto_item_add_subtree(ti, ett_ppp);
1337     if (byte0 == 0xff) {
1338       proto_tree_add_text(fh_tree, tvb, 0, 1, "Address: %02x", ph.ppp_addr);
1339       proto_tree_add_text(fh_tree, tvb, 1, 1, "Control: %02x", ph.ppp_ctl);
1340     }
1341     else if (byte0 == 0x0f) {
1342       proto_tree_add_text(fh_tree, tvb, 0, 1, "Address: %02x", ph.ppp_addr);
1343       proto_tree_add_text(fh_tree, tvb, 1, 1, "Control: %02x", ph.ppp_ctl);
1344     }
1345   }
1346
1347   next_tvb = tvb_new_subset(tvb, proto_offset, -1, -1);
1348
1349   if (!dissect_ppp_stuff(next_tvb, pinfo, tree, fh_tree)) {
1350     if (check_col(pinfo->fd, COL_PROTOCOL))
1351       col_add_fstr(pinfo->fd, COL_PROTOCOL, "0x%04x", ph.ppp_prot);
1352   }
1353
1354   /* Calculate the FCS check */
1355   if (ppp_fcs_decode == FCS_16) {
1356     rx_fcs_got = 0;
1357     rx_fcs_exp = fcs16(0xFFFF, tvb, 0, tvb_length(tvb) - 2);
1358     rx_fcs_got = tvb_get_guint8(tvb, tvb_length(tvb) - 2) |
1359         (tvb_get_guint8(tvb, tvb_length(tvb) - 1) << 8);
1360         if (rx_fcs_got != rx_fcs_exp) {
1361       proto_tree_add_text(fh_tree, tvb, tvb_length(tvb) - 2, 2, "FCS 16: %04x (incorrect, should be %04x)", rx_fcs_got, rx_fcs_exp);
1362         }
1363         else {
1364       proto_tree_add_text(fh_tree, tvb, tvb_length(tvb) - 2, 2, "FCS 16: %04x (correct)", rx_fcs_got);
1365         }
1366   }
1367   else if(ppp_fcs_decode == FCS_32) {
1368     rx_fcs_got = 0;
1369     rx_fcs_exp = fcs32(0xFFFFFFFF, tvb, 0, tvb_length(tvb) - 4);
1370     rx_fcs_got = tvb_get_guint8(tvb, tvb_length(tvb) - 4) |
1371         (tvb_get_guint8(tvb, tvb_length(tvb) - 3) << 8) |
1372         (tvb_get_guint8(tvb, tvb_length(tvb) - 2) << 16) | 
1373         (tvb_get_guint8(tvb, tvb_length(tvb) - 1) << 24);
1374         if (rx_fcs_got != rx_fcs_exp) {
1375       proto_tree_add_text(fh_tree, tvb, tvb_length(tvb) - 4, 4, "FCS 32: %08x (incorrect, should be %08x) ", rx_fcs_got, rx_fcs_exp);
1376         }
1377         else {
1378       proto_tree_add_text(fh_tree, tvb, tvb_length(tvb) - 4, 4, "FCS 32: %08x (correct)", rx_fcs_got);
1379         }
1380   }
1381
1382 }
1383
1384 void
1385 proto_register_ppp(void)
1386 {
1387 /*        static hf_register_info hf[] = {
1388                 { &variable,
1389                 { "Name",           "ppp.abbreviation", TYPE, VALS_POINTER }},
1390         };*/
1391         static gint *ett[] = {
1392                 &ett_ppp,
1393                 &ett_ipcp,
1394                 &ett_ipcp_options,
1395                 &ett_ipcp_ipaddrs_opt,
1396                 &ett_ipcp_compressprot_opt,
1397                 &ett_lcp,
1398                 &ett_lcp_options,
1399                 &ett_lcp_mru_opt,
1400                 &ett_lcp_async_map_opt,
1401                 &ett_lcp_authprot_opt,
1402                 &ett_lcp_qualprot_opt,
1403                 &ett_lcp_magicnum_opt,
1404                 &ett_lcp_fcs_alternatives_opt,
1405                 &ett_lcp_numbered_mode_opt,
1406                 &ett_lcp_callback_opt,
1407                 &ett_lcp_multilink_ep_disc_opt,
1408                 &ett_lcp_internationalization_opt,
1409         };
1410
1411     static enum_val_t ppp_options[] = {
1412         {"None", 0}, 
1413         {"16-Bit", 1}, 
1414         {"32-Bit", 2},
1415         {NULL, -1}
1416     };
1417     
1418     module_t *ppp_module;
1419
1420         proto_ppp = proto_register_protocol("Point-to-Point Protocol", "ppp");
1421  /*       proto_register_field_array(proto_ppp, hf, array_length(hf));*/
1422         proto_register_subtree_array(ett, array_length(ett));
1423
1424 /* subdissector code */
1425         subdissector_table = register_dissector_table("ppp.protocol");
1426
1427         register_dissector("ppp", dissect_ppp);
1428         register_dissector("payload_ppp", dissect_payload_ppp);
1429
1430         /* Register the preferences for the ppp protocol */
1431         ppp_module = prefs_register_module("ppp", "PPP", NULL);
1432
1433         prefs_register_enum_preference(ppp_module, 
1434         "ppp_fcs",
1435         "PPP Frame Checksum",
1436     "PPP Frame Checksum", 
1437     &ppp_fcs_decode,
1438     ppp_options, FALSE);
1439 }
1440
1441 void
1442 proto_register_mp(void)
1443 {
1444   static hf_register_info hf[] = {
1445     { &hf_mp_frag_first,
1446     { "First fragment",         "mp.first",     FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1447         "" }},
1448
1449     { &hf_mp_frag_last,
1450     { "Last fragment",          "mp.last",      FT_BOOLEAN, BASE_NONE, NULL, 0x0,
1451         "" }},
1452
1453     { &hf_mp_sequence_num,
1454     { "Sequence number",        "mp.seq",       FT_UINT24, BASE_DEC, NULL, 0x0,
1455         "" }}
1456   };
1457   static gint *ett[] = {
1458     &ett_mp,
1459     &ett_mp_flags,
1460   };
1461
1462   proto_mp = proto_register_protocol("PPP Multilink Protocol", "mp");
1463   proto_register_field_array(proto_mp, hf, array_length(hf));
1464   proto_register_subtree_array(ett, array_length(ett));
1465 }
1466
1467 void
1468 proto_reg_handoff_ppp(void)
1469 {
1470         dissector_add("wtap_encap", WTAP_ENCAP_PPP, dissect_ppp);
1471         dissector_add("wtap_encap", WTAP_ENCAP_PPP_WITH_PHDR, dissect_ppp);
1472 }