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