PPP options in LCP, IPCP, etc. are like IP and TCP options - one octet
[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.18 1999/08/28 08:31:26 guy Exp $
5  *
6  * Ethereal - Network traffic analyzer
7  * By Gerald Combs <gerald@zing.org>
8  *
9  * This file created and by Mike Hall <mlh@io.com>
10  * Copyright 1998
11  * 
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  * 
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  * 
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #ifdef HAVE_SYS_TYPES_H
32 # include <sys/types.h>
33 #endif
34
35 #include <glib.h>
36 #include "packet.h"
37 #include "packet-ip.h"
38
39 static int proto_ppp = -1;
40
41 /* PPP structs and definitions */
42
43 typedef struct _e_ppphdr {
44   guint8  ppp_addr;
45   guint8  ppp_ctl;
46   guint16 ppp_prot;
47 } e_ppphdr;
48
49
50 /* Protocol types, from Linux "ppp_defs.h" and
51
52         http://www.isi.edu/in-notes/iana/assignments/ppp-numbers
53
54  */
55 #define PPP_IP          0x21    /* Internet Protocol */
56 #define PPP_AT          0x29    /* AppleTalk Protocol */
57 #define PPP_IPX         0x2b    /* IPX protocol */
58 #define PPP_VJC_COMP    0x2d    /* VJ compressed TCP */
59 #define PPP_VJC_UNCOMP  0x2f    /* VJ uncompressed TCP */
60 #define PPP_VINES       0x35    /* Banyan Vines */
61 #define PPP_IPV6        0x57    /* Internet Protocol Version 6 */
62 #define PPP_COMP        0xfd    /* compressed packet */
63 #define PPP_IPCP        0x8021  /* IP Control Protocol */
64 #define PPP_ATCP        0x8029  /* AppleTalk Control Protocol */
65 #define PPP_IPXCP       0x802b  /* IPX Control Protocol */
66 #define PPP_CCP         0x80fd  /* Compression Control Protocol */
67 #define PPP_LCP         0xc021  /* Link Control Protocol */
68 #define PPP_PAP         0xc023  /* Password Authentication Protocol */
69 #define PPP_LQR         0xc025  /* Link Quality Report protocol */
70 #define PPP_CHAP        0xc223  /* Cryptographic Handshake Auth. Protocol */
71 #define PPP_CBCP        0xc029  /* Callback Control Protocol */
72
73 static const value_string ppp_vals[] = {
74         {PPP_IP,        "IP"             },
75         {PPP_AT,        "Appletalk"      },
76         {PPP_IPX,       "Netware IPX/SPX"},
77         {PPP_VJC_COMP,  "VJ compressed TCP"},
78         {PPP_VJC_UNCOMP,"VJ uncompressed TCP"}, 
79         {PPP_VINES,     "Vines"          },
80         {PPP_IPV6,      "IPv6"           },
81         {PPP_COMP,      "compressed packet" },
82         {PPP_IPCP,      "IP Control Protocol" },
83         {PPP_ATCP,      "AppleTalk Control Protocol" },
84         {PPP_IPXCP,     "IPX Control Protocol" },
85         {PPP_CCP,       "Compression Control Protocol" },
86         {PPP_LCP,       "Link Control Protocol" },
87         {PPP_PAP,       "Password Authentication Protocol"  },
88         {PPP_LQR,       "Link Quality Report protocol" },
89         {PPP_CHAP,      "Cryptographic Handshake Auth. Protocol" },
90         {PPP_CBCP,      "Callback Control Protocol" },
91         {0,             NULL            }
92 };
93
94 /* CP (LCP, IPCP, etc.) codes.
95  * from pppd fsm.h 
96  */
97 #define CONFREQ    1  /* Configuration Request */
98 #define CONFACK    2  /* Configuration Ack */
99 #define CONFNAK    3  /* Configuration Nak */
100 #define CONFREJ    4  /* Configuration Reject */
101 #define TERMREQ    5  /* Termination Request */
102 #define TERMACK    6  /* Termination Ack */
103 #define CODEREJ    7  /* Code Reject */
104
105 static const value_string cp_vals[] = {
106         {CONFREQ,    "Configuration Request" },
107         {CONFACK,    "Configuration Ack" },
108         {CONFNAK,    "Configuration Nak" },
109         {CONFREJ,    "Configuration Reject" },
110         {TERMREQ,    "Termination Request" },
111         {TERMACK,    "Termination Ack" },
112         {CODEREJ,    "Code Reject" },
113         {0,          NULL            } };
114
115 /*
116  * LCP-specific packet types.
117  */
118 #define PROTREJ    8  /* Protocol Reject */
119 #define ECHOREQ    9  /* Echo Request */
120 #define ECHOREP    10 /* Echo Reply */
121 #define DISCREQ    11 /* Discard Request */
122 #define IDENT      12 /* Identification */
123 #define TIMEREMAIN 13 /* Time remaining */
124
125 #define CBCP_OPT  6 /* Use callback control protocol */
126
127 static const value_string lcp_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         {PROTREJ,    "Protocol Reject" },
136         {ECHOREQ,    "Echo Request" },
137         {ECHOREP,    "Echo Reply" },
138         {DISCREQ,    "Discard Request" },
139         {IDENT,      "Identification" },
140         {TIMEREMAIN, "Time Remaining" },
141         {0,          NULL }
142 };
143
144 /*
145  * Options.  (LCP)
146  */
147 #define CI_MRU                  1       /* Maximum Receive Unit */
148 #define CI_ASYNCMAP             2       /* Async Control Character Map */
149 #define CI_AUTHTYPE             3       /* Authentication Type */
150 #define CI_QUALITY              4       /* Quality Protocol */
151 #define CI_MAGICNUMBER          5       /* Magic Number */
152 #define CI_PCOMPRESSION         7       /* Protocol Field Compression */
153 #define CI_ACCOMPRESSION        8       /* Address/Control Field Compression */
154 #define CI_FCS_ALTERNATIVES     9       /* FCS Alternatives (RFC 1570) */
155 #define CI_SELF_DESCRIBING_PAD  10      /* Self-Describing Pad (RFC 1570) */
156 #define CI_NUMBERED_MODE        11      /* Numbered Mode (RFC 1663) */
157 #define CI_CALLBACK             13      /* Callback (RFC 1570) */
158 #define CI_COMPOUND_FRAMES      15      /* Compound frames (RFC 1570) */
159 #define CI_MULTILINK_MRRU       17      /* Multilink MRRU (RFC 1717) */
160 #define CI_MULTILINK_SSNH       18      /* Multilink Short Sequence Number
161                                            Header (RFC 1717) */
162 #define CI_MULTILINK_EP_DISC    19      /* Multilink Endpoint Discriminator
163                                            (RFC 1717) */
164 #define CI_DCE_IDENTIFIER       21      /* DCE Identifier */
165 #define CI_MULTILINK_PLUS_PROC  22      /* Multilink Plus Procedure */
166 #define CI_LINK_DISC_FOR_BACP   23      /* Link Discriminator for BACP
167                                            (RFC 2125) */
168 #define CI_LCP_AUTHENTICATION   24      /* LCP Authentication Option */
169 #define CI_COBS                 25      /* Consistent Overhead Byte
170                                            Stuffing */
171 #define CI_PREFIX_ELISION       26      /* Prefix elision */
172 #define CI_MULTILINK_HDR_FMT    27      /* Multilink header format */
173 #define CI_INTERNATIONALIZATION 28      /* Internationalization (RFC 2484) */
174 #define CI_SDL_ON_SONET_SDH     29      /* Simple Data Link on SONET/SDH */
175
176 static void dissect_lcp_mru_opt(const ip_tcp_opt *optp, const u_char *opd,
177                         int offset, guint length, proto_tree *tree);
178 static void dissect_lcp_async_map_opt(const ip_tcp_opt *optp, const u_char *opd,
179                         int offset, guint length, proto_tree *tree);
180 static void dissect_lcp_protocol_opt(const ip_tcp_opt *optp, const u_char *opd,
181                         int offset, guint length, proto_tree *tree);
182 static void dissect_lcp_magicnumber_opt(const ip_tcp_opt *optp,
183                         const u_char *opd, int offset, guint length,
184                         proto_tree *tree);
185 static void dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp,
186                         const u_char *opd, int offset, guint length,
187                         proto_tree *tree);
188 static void dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp,
189                         const u_char *opd, int offset, guint length,
190                         proto_tree *tree);
191 static void dissect_lcp_self_describing_pad_opt(const ip_tcp_opt *optp,
192                         const u_char *opd, int offset, guint length,
193                         proto_tree *tree);
194 static void dissect_lcp_callback_opt(const ip_tcp_opt *optp, const u_char *opd,
195                         int offset, guint length, proto_tree *tree);
196 static void dissect_lcp_multilink_mrru_opt(const ip_tcp_opt *optp,
197                         const u_char *opd, int offset, guint length,
198                         proto_tree *tree);
199 static void dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp,
200                         const u_char *opd, int offset, guint length,
201                         proto_tree *tree);
202 static void dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp,
203                         const u_char *opd, int offset, guint length,
204                         proto_tree *tree);
205 static void dissect_lcp_internationalization_opt(const ip_tcp_opt *optp,
206                         const u_char *opd, int offset, guint length,
207                         proto_tree *tree);
208
209 static const ip_tcp_opt lcp_opts[] = {
210         {
211                 CI_MRU,
212                 "Maximum Receive Unit",
213                 ETT_LCP_MRU_OPT,
214                 FIXED_LENGTH,
215                 4,
216                 dissect_lcp_mru_opt
217         },
218         {
219                 CI_ASYNCMAP,
220                 "Async Control Character Map",
221                 ETT_LCP_ASYNC_MAP_OPT,
222                 FIXED_LENGTH,
223                 6,
224                 dissect_lcp_async_map_opt
225         },
226         {
227                 CI_AUTHTYPE,
228                 "Authentication protocol",
229                 ETT_LCP_AUTHPROT_OPT,
230                 VARIABLE_LENGTH,
231                 4,
232                 dissect_lcp_protocol_opt
233         },
234         {
235                 CI_QUALITY,
236                 "Quality protocol",
237                 ETT_LCP_QUALPROT_OPT,
238                 VARIABLE_LENGTH,
239                 4,
240                 dissect_lcp_protocol_opt
241         },
242         {
243                 CI_MAGICNUMBER,
244                 NULL,
245                 ETT_LCP_MAGICNUM_OPT,
246                 FIXED_LENGTH,
247                 6,
248                 dissect_lcp_magicnumber_opt
249         },
250         {
251                 CI_PCOMPRESSION,
252                 "Protocol field compression",
253                 -1,
254                 FIXED_LENGTH,
255                 2,
256                 NULL
257         },
258         {
259                 CI_ACCOMPRESSION,
260                 "Address/control field compression",
261                 -1,
262                 FIXED_LENGTH,
263                 2,
264                 NULL
265         },
266         {
267                 CI_FCS_ALTERNATIVES,
268                 NULL,
269                 ETT_LCP_FCS_ALTERNATIVES_OPT,
270                 FIXED_LENGTH,
271                 3,
272                 dissect_lcp_fcs_alternatives_opt
273         },
274         {
275                 CI_SELF_DESCRIBING_PAD,
276                 NULL,
277                 -1,
278                 FIXED_LENGTH,
279                 3,
280                 dissect_lcp_self_describing_pad_opt
281         },
282         {
283                 CI_NUMBERED_MODE,
284                 "Numbered mode",
285                 ETT_LCP_NUMBERED_MODE_OPT,
286                 VARIABLE_LENGTH,
287                 4,
288                 dissect_lcp_numbered_mode_opt
289         },
290         {
291                 CI_CALLBACK,
292                 "Callback",
293                 ETT_LCP_CALLBACK_OPT,
294                 VARIABLE_LENGTH,
295                 3,
296                 dissect_lcp_callback_opt,
297         },
298         {
299                 CI_COMPOUND_FRAMES,
300                 "Compound frames",
301                 -1,
302                 FIXED_LENGTH,
303                 2,
304                 NULL
305         },
306         {
307                 CI_MULTILINK_MRRU,
308                 NULL,
309                 -1,
310                 FIXED_LENGTH,
311                 4,
312                 dissect_lcp_multilink_mrru_opt
313         },
314         {
315                 CI_MULTILINK_SSNH,
316                 "Use short sequence number headers",
317                 -1,
318                 FIXED_LENGTH,
319                 2,
320                 NULL
321         },
322         {
323                 CI_MULTILINK_EP_DISC,
324                 "Multilink endpoint discriminator",
325                 ETT_LCP_MULTILINK_EP_DISC_OPT,
326                 VARIABLE_LENGTH,
327                 3,
328                 dissect_lcp_multilink_ep_disc_opt,
329         },
330         {
331                 CI_DCE_IDENTIFIER,
332                 "DCE identifier",
333                 -1,
334                 VARIABLE_LENGTH,
335                 2,
336                 NULL
337         },
338         {
339                 CI_MULTILINK_PLUS_PROC,
340                 "Multilink Plus Procedure",
341                 -1,
342                 VARIABLE_LENGTH,
343                 2,
344                 NULL
345         },
346         {
347                 CI_LINK_DISC_FOR_BACP,
348                 NULL,
349                 -1,
350                 FIXED_LENGTH,
351                 4,
352                 dissect_lcp_bap_link_discriminator_opt
353         },
354         {
355                 CI_LCP_AUTHENTICATION,
356                 "LCP authentication",
357                 -1,
358                 VARIABLE_LENGTH,
359                 2,
360                 NULL
361         },
362         {
363                 CI_COBS,
364                 "Consistent Overhead Byte Stuffing",
365                 -1,
366                 VARIABLE_LENGTH,
367                 2,
368                 NULL
369         },
370         {
371                 CI_PREFIX_ELISION,
372                 "Prefix elision",
373                 -1,
374                 VARIABLE_LENGTH,
375                 2,
376                 NULL
377         },
378         {
379                 CI_MULTILINK_HDR_FMT,
380                 "Multilink header format",
381                 -1,
382                 VARIABLE_LENGTH,
383                 2,
384                 NULL
385         },
386         {
387                 CI_INTERNATIONALIZATION,
388                 "Internationalization",
389                 ETT_LCP_INTERNATIONALIZATION_OPT,
390                 VARIABLE_LENGTH,
391                 7,
392                 dissect_lcp_internationalization_opt
393         },
394         {
395                 CI_SDL_ON_SONET_SDH,
396                 "Simple data link on SONET/SDH",
397                 -1,
398                 VARIABLE_LENGTH,
399                 2,
400                 NULL
401         }
402 };
403
404 #define N_LCP_OPTS      (sizeof lcp_opts / sizeof lcp_opts[0])
405
406 /*
407  * Options.  (IPCP)
408  */
409 #define CI_ADDRS        1       /* IP Addresses (deprecated) (RFC 1172) */
410 #define CI_COMPRESSTYPE 2       /* Compression Type (RFC 1332) */
411 #define CI_ADDR         3       /* IP Address (RFC 1332) */
412 #define CI_MOBILE_IPv4  4       /* Mobile IPv4 (RFC 2290) */
413 #define CI_MS_DNS1      129     /* Primary DNS value (RFC 1877) */
414 #define CI_MS_WINS1     130     /* Primary WINS value (RFC 1877) */
415 #define CI_MS_DNS2      131     /* Secondary DNS value (RFC 1877) */
416 #define CI_MS_WINS2     132     /* Secondary WINS value (RFC 1877) */
417
418 static void dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, const u_char *opd,
419                         int offset, guint length, proto_tree *tree);
420 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, const u_char *opd,
421                         int offset, guint length, proto_tree *tree);
422
423 static const ip_tcp_opt ipcp_opts[] = {
424         {
425                 CI_ADDRS,
426                 "IP addresses (deprecated)",
427                 ETT_IPCP_IPADDRS_OPT,
428                 FIXED_LENGTH,
429                 10,
430                 dissect_ipcp_addrs_opt
431         },
432         {
433                 CI_COMPRESSTYPE,
434                 "IP compression protocol",
435                 ETT_IPCP_COMPRESSPROT_OPT,
436                 VARIABLE_LENGTH,
437                 4,
438                 dissect_lcp_protocol_opt
439         },
440         {
441                 CI_ADDR,
442                 "IP address",
443                 -1,
444                 FIXED_LENGTH,
445                 6,
446                 dissect_ipcp_addr_opt
447         },
448         {
449                 CI_MOBILE_IPv4,
450                 "Mobile node's home IP address",
451                 -1,
452                 FIXED_LENGTH,
453                 6,
454                 dissect_ipcp_addr_opt
455         },
456         {
457                 CI_MS_DNS1,
458                 "Primary DNS server IP address",
459                 -1,
460                 FIXED_LENGTH,
461                 6,
462                 dissect_ipcp_addr_opt
463         },
464         {
465                 CI_MS_WINS1,
466                 "Primary WINS server IP address",
467                 -1,
468                 FIXED_LENGTH,
469                 6,
470                 dissect_ipcp_addr_opt
471         },
472         {
473                 CI_MS_DNS2,
474                 "Secondary DNS server IP address",
475                 -1,
476                 FIXED_LENGTH,
477                 6,
478                 dissect_ipcp_addr_opt
479         },
480         {
481                 CI_MS_WINS2,
482                 "Secondary WINS server IP address",
483                 -1,
484                 FIXED_LENGTH,
485                 6,
486                 dissect_ipcp_addr_opt
487         }
488 };
489
490 #define N_IPCP_OPTS     (sizeof ipcp_opts / sizeof ipcp_opts[0])
491
492 void
493 capture_ppp( const u_char *pd, guint32 cap_len, packet_counts *ld ) {
494   switch (pntohs(&pd[2])) {
495     case PPP_IP:
496       capture_ip(pd, 4, cap_len, ld);
497       break;
498     default:
499       ld->other++;
500       break;
501   }
502 }
503
504 static void
505 dissect_lcp_mru_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
506                         guint length, proto_tree *tree)
507 {
508   proto_tree_add_text(tree, offset, length, "MRU: %u", pntohs(opd));
509 }
510
511 static void
512 dissect_lcp_async_map_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
513                         guint length, proto_tree *tree)
514 {
515   proto_tree_add_text(tree, offset, length, "Async characters to map: 0x%08x",
516                         pntohl(opd));
517 }
518
519 static void
520 dissect_lcp_protocol_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
521                         guint length, proto_tree *tree)
522 {
523   guint16 protocol;
524   proto_item *tf;
525   proto_tree *field_tree = NULL;
526   
527   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
528           optp->name, length, plurality(length, "", "s"));
529   field_tree = proto_item_add_subtree(tf, optp->subtree_index);
530   offset += 2;
531   length -= 2;
532   protocol = pntohs(opd);
533   proto_tree_add_text(field_tree, offset, 2, "%s: %s (0x%02x)", optp->name,
534                 val_to_str(protocol, ppp_vals, "Unknown"), protocol);
535   offset += 2;
536   opd += 2;
537   length -= 2;
538   if (length > 0)
539     proto_tree_add_text(field_tree, offset, length, "Data (%d byte%s)", length,
540                         plurality(length, "", "s"));
541 }
542
543 static void
544 dissect_lcp_magicnumber_opt(const ip_tcp_opt *optp, const u_char *opd,
545                         int offset, guint length, proto_tree *tree)
546 {
547   proto_tree_add_text(tree, offset, length, "Magic number: 0x%08x",
548                         pntohl(opd));
549 }
550
551 static void
552 dissect_lcp_fcs_alternatives_opt(const ip_tcp_opt *optp, const u_char *opd,
553                         int offset, guint length, proto_tree *tree)
554 {
555   proto_item *tf;
556   proto_tree *field_tree = NULL;
557   guint8 alternatives;
558   
559   alternatives = *opd;
560   tf = proto_tree_add_text(tree, offset, length, "%s: 0x%02x",
561           optp->name, alternatives);
562   field_tree = proto_item_add_subtree(tf, optp->subtree_index);
563   offset += 2;
564   if (alternatives & 0x1)
565     proto_tree_add_text(field_tree, offset + 2, 1, "%s",
566        decode_boolean_bitfield(alternatives, 0x1, 8, "Null FCS", NULL));
567   if (alternatives & 0x2)
568     proto_tree_add_text(field_tree, offset + 2, 1, "%s",
569        decode_boolean_bitfield(alternatives, 0x2, 8, "CCITT 16-bit FCS", NULL));
570   if (alternatives & 0x4)
571     proto_tree_add_text(field_tree, offset + 2, 1, "%s",
572        decode_boolean_bitfield(alternatives, 0x4, 8, "CCITT 32-bit FCS", NULL));
573 }
574
575 static void
576 dissect_lcp_self_describing_pad_opt(const ip_tcp_opt *optp, const u_char *opd,
577                         int offset, guint length, proto_tree *tree)
578 {
579   proto_tree_add_text(tree, offset, length,
580                         "Maximum octets of self-describing padding: %u",
581                         *opd);
582 }
583
584 static void
585 dissect_lcp_numbered_mode_opt(const ip_tcp_opt *optp, const u_char *opd,
586                         int offset, guint length, proto_tree *tree)
587 {
588   proto_item *tf;
589   proto_tree *field_tree = NULL;
590   
591   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
592           optp->name, length, plurality(length, "", "s"));
593   field_tree = proto_item_add_subtree(tf, optp->subtree_index);
594   offset += 2;
595   length -= 2;
596   proto_tree_add_text(field_tree, offset, 1, "Window: %u", *opd);
597   offset += 1;
598   opd += 1;
599   length -= 1;
600   if (length > 0)
601     proto_tree_add_text(field_tree, offset, length, "Address (%d byte%s)",
602                         length, plurality(length, "", "s"));
603 }
604
605 static const value_string callback_op_vals[] = {
606         {0, "Location is determined by user authentication" },
607         {1, "Message is dialing string" },
608         {2, "Message is location identifier" },
609         {3, "Message is E.164" },
610         {4, "Message is distinguished name" },
611         {0, NULL }
612 };
613
614 static void
615 dissect_lcp_callback_opt(const ip_tcp_opt *optp, const u_char *opd, int offset,
616                         guint length, proto_tree *tree)
617 {
618   proto_item *tf;
619   proto_tree *field_tree = NULL;
620   
621   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
622           optp->name, length, plurality(length, "", "s"));
623   field_tree = proto_item_add_subtree(tf, optp->subtree_index);
624   offset += 2;
625   length -= 2;
626   proto_tree_add_text(field_tree, offset, 1, "Operation: %s (0x%02x)",
627                 val_to_str(*opd, callback_op_vals, "Unknown"),
628                 *opd);
629   offset += 1;
630   opd += 1;
631   length -= 1;
632   if (length > 0)
633     proto_tree_add_text(field_tree, offset, length, "Message (%d byte%s)",
634                         length, plurality(length, "", "s"));
635 }
636
637 static void
638 dissect_lcp_multilink_mrru_opt(const ip_tcp_opt *optp, const u_char *opd,
639                         int offset, guint length, proto_tree *tree)
640 {
641   proto_tree_add_text(tree, offset, length, "Multilink MRRU: %u",
642                         pntohs(opd));
643 }
644
645 #define CLASS_NULL                      0
646 #define CLASS_LOCAL                     1
647 #define CLASS_IP                        2
648 #define CLASS_IEEE_802_1                3
649 #define CLASS_PPP_MAGIC_NUMBER          4
650 #define CLASS_PSDN_DIRECTORY_NUMBER     5
651
652 static const value_string multilink_ep_disc_class_vals[] = {
653         {CLASS_NULL,                  "Null" },
654         {CLASS_LOCAL,                 "Locally assigned address" },
655         {CLASS_IP,                    "IP address" },
656         {CLASS_IEEE_802_1,            "IEEE 802.1 globally assigned MAC address" },
657         {CLASS_PPP_MAGIC_NUMBER,      "PPP magic-number block" },
658         {CLASS_PSDN_DIRECTORY_NUMBER, "Public switched network directory number" },
659         {0,                           NULL }
660 };
661
662 static void
663 dissect_lcp_multilink_ep_disc_opt(const ip_tcp_opt *optp, const u_char *opd,
664                         int offset, guint length, proto_tree *tree)
665 {
666   proto_item *tf;
667   proto_tree *field_tree = NULL;
668   guint8 ep_disc_class;
669
670   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
671           optp->name, length, plurality(length, "", "s"));
672   field_tree = proto_item_add_subtree(tf, optp->subtree_index);
673   offset += 2;
674   length -= 2;
675   ep_disc_class = *opd;
676   proto_tree_add_text(field_tree, offset, 1, "Class: %s (%u)",
677                 val_to_str(ep_disc_class, multilink_ep_disc_class_vals, "Unknown"),
678                 ep_disc_class);
679   offset += 1;
680   opd += 1;
681   length -= 1;
682   if (length > 0) {
683     switch (ep_disc_class) {
684
685     case CLASS_NULL:
686       proto_tree_add_text(field_tree, offset, length,
687                         "Address (%d byte%s), should have been empty",
688                         length, plurality(length, "", "s"));
689       break;
690
691     case CLASS_LOCAL:
692       if (length > 20) {
693         proto_tree_add_text(field_tree, offset, length,
694                         "Address (%d byte%s), should have been <20",
695                         length, plurality(length, "", "s"));
696       } else {
697         proto_tree_add_text(field_tree, offset, length,
698                         "Address (%d byte%s)",
699                         length, plurality(length, "", "s"));
700       }
701       break;
702
703     case CLASS_IP:
704       if (length != 4) {
705         proto_tree_add_text(field_tree, offset, length,
706                         "Address (%d byte%s), should have been 4",
707                         length, plurality(length, "", "s"));
708       } else {
709         proto_tree_add_text(field_tree, offset, length,
710                         "Address: %s", ip_to_str(opd));
711       }
712       break;
713
714     case CLASS_IEEE_802_1:
715       if (length != 6) {
716         proto_tree_add_text(field_tree, offset, length,
717                         "Address (%d byte%s), should have been 6",
718                         length, plurality(length, "", "s"));
719       } else {
720         proto_tree_add_text(field_tree, offset, length,
721                         "Address: %s", ether_to_str(opd));
722       }
723       break;
724
725     case CLASS_PPP_MAGIC_NUMBER:
726       /* XXX - dissect as 32-bit magic numbers */
727       if (length > 20) {
728         proto_tree_add_text(field_tree, offset, length,
729                         "Address (%d byte%s), should have been <20",
730                         length, plurality(length, "", "s"));
731       } else {
732         proto_tree_add_text(field_tree, offset, length,
733                         "Address (%d byte%s)",
734                         length, plurality(length, "", "s"));
735       }
736       break;
737
738     case CLASS_PSDN_DIRECTORY_NUMBER:
739       if (length > 15) {
740         proto_tree_add_text(field_tree, offset, length,
741                         "Address (%d byte%s), should have been <20",
742                         length, plurality(length, "", "s"));
743       } else {
744         proto_tree_add_text(field_tree, offset, length,
745                         "Address (%d byte%s)",
746                         length, plurality(length, "", "s"));
747       }
748       break;
749
750     default:
751       proto_tree_add_text(field_tree, offset, length,
752                         "Address (%d byte%s)",
753                         length, plurality(length, "", "s"));
754       break;
755     }
756   }
757 }
758
759 static void
760 dissect_lcp_bap_link_discriminator_opt(const ip_tcp_opt *optp, const u_char *opd,
761                         int offset, guint length, proto_tree *tree)
762 {
763   proto_tree_add_text(tree, offset, length,
764                         "Link discriminator for BAP: 0x%04x",
765                         pntohs(opd));
766 }
767
768 /* Character set numbers from the IANA charset registry. */
769 static const value_string charset_num_vals[] = {
770         {105, "UTF-8" },
771         {0,   NULL }
772 };
773
774 static void
775 dissect_lcp_internationalization_opt(const ip_tcp_opt *optp, const u_char *opd,
776                         int offset, guint length, proto_tree *tree)
777 {
778   proto_item *tf;
779   proto_tree *field_tree = NULL;
780   
781   tf = proto_tree_add_text(tree, 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, offset, 4, "Character set: %s (0x%04x)",
787                 val_to_str(pntohl(opd), charset_num_vals, "Unknown"),
788                 pntohl(opd));
789   offset += 4;
790   opd += 4;
791   length -= 4;
792   if (length > 0) {
793     /* XXX - should be displayed as an ASCII string */
794     proto_tree_add_text(field_tree, offset, length, "Language tag (%d byte%s)",
795                         length, plurality(length, "", "s"));
796   }
797 }
798
799 static void
800 dissect_ipcp_addrs_opt(const ip_tcp_opt *optp, const u_char *opd,
801                         int offset, guint length, proto_tree *tree)
802 {
803   proto_item *tf;
804   proto_tree *field_tree = NULL;
805   
806   tf = proto_tree_add_text(tree, offset, length, "%s: %u byte%s",
807           optp->name, length, plurality(length, "", "s"));
808   field_tree = proto_item_add_subtree(tf, optp->subtree_index);
809   offset += 2;
810   length -= 2;
811   proto_tree_add_text(field_tree, offset, 4,
812                         "Source IP address: %s", ip_to_str(opd));
813   offset += 4;
814   opd += 4;
815   length -= 4;
816   proto_tree_add_text(field_tree, offset, 4,
817                         "Destination IP address: %s", ip_to_str(opd));
818 }
819
820 static void dissect_ipcp_addr_opt(const ip_tcp_opt *optp, const u_char *opd,
821                         int offset, guint length, proto_tree *tree)
822 {
823   proto_tree_add_text(tree, offset, length, "%s: %s", optp->name,
824                         ip_to_str((guint8 *)opd));
825 }
826
827 static void
828 dissect_cp( const u_char *pd, int offset, const char *proto_short_name,
829         const char *proto_long_name, int proto_subtree_index,
830         const value_string *proto_vals, int options_subtree_index,
831         const ip_tcp_opt *opts, int nopts, frame_data *fd, proto_tree *tree ) {
832   proto_item *ti;
833   proto_tree *fh_tree = NULL;
834   proto_item *tf;
835   proto_tree *field_tree;
836
837   guint8 code;
838   guint8 id;
839   int length;
840   guint16 protocol;
841
842   code = pd[0+offset];
843   id = pd[1+offset];
844   length = pntohs(&pd[2+offset]);
845
846   if(check_col(fd, COL_INFO))
847         col_add_fstr(fd, COL_INFO, "%sCP %s", proto_short_name,
848                 val_to_str(code, proto_vals, "Unknown"));
849
850   if(tree) {
851     ti = proto_tree_add_text(tree, 0+offset, 4, "%s Control Protocol",
852                                 proto_long_name);
853     fh_tree = proto_item_add_subtree(ti, proto_subtree_index);
854     proto_tree_add_text(fh_tree, 0+offset, 1, "Code: %s (0x%02x)",
855       val_to_str(code, proto_vals, "Unknown"), code);
856     proto_tree_add_text(fh_tree, 1+offset, 1, "Identifier: 0x%02x",
857                         id);
858     proto_tree_add_text(fh_tree, 2+offset, 2, "Length: %u",
859                         length);
860   }
861   offset += 4;
862   length -= 4;
863
864   switch (code) {
865     case CONFREQ:
866     case CONFACK:
867     case CONFNAK:
868     case CONFREJ:
869       if(tree) {
870         if (length > 0) {
871           tf = proto_tree_add_text(fh_tree, offset, length,
872             "Options: (%d byte%s)", length, plurality(length, "", "s"));
873           field_tree = proto_item_add_subtree(tf, options_subtree_index);
874           dissect_ip_tcp_options(&pd[offset], offset, length, opts, nopts,
875                                 -1, field_tree);
876         }
877       }
878       break;
879
880     case ECHOREQ:
881     case ECHOREP:
882     case DISCREQ:
883     case IDENT:
884       if(tree) {
885         proto_tree_add_text(fh_tree, offset, 4, "Magic number: 0x%08x",
886                         pntohl(&pd[offset]));
887         offset += 4;
888         length -= 4;
889         if (length > 0)
890           proto_tree_add_text(fh_tree, offset, length, "Message (%d byte%s)",
891                                 length, plurality(length, "", "s"));
892       }
893       break;
894
895     case TIMEREMAIN:
896       if(tree) {
897         proto_tree_add_text(fh_tree, offset, 4, "Magic number: 0x%08x",
898                         pntohl(&pd[offset]));
899         offset += 4;
900         length -= 4;
901         proto_tree_add_text(fh_tree, offset, 4, "Seconds remaining: %u",
902                         pntohl(&pd[offset]));
903         offset += 4;
904         length -= 4;
905         if (length > 0)
906           proto_tree_add_text(fh_tree, offset, length, "Message (%d byte%s)",
907                                 length, plurality(length, "", "s"));
908       }
909       break;
910
911     case PROTREJ:
912       if(tree) {
913         protocol = pntohs(&pd[offset]);
914         proto_tree_add_text(fh_tree, offset, 2, "Rejected protocol: %s (0x%04x)",
915                 val_to_str(protocol, ppp_vals, "Unknown"), protocol);
916         offset += 2;
917         length -= 2;
918         if (length > 0)
919           proto_tree_add_text(fh_tree, offset, length, "Rejected packet (%d byte%s)",
920                                 length, plurality(length, "", "s"));
921                 /* XXX - should be dissected as a PPP packet */
922       }
923       break;
924
925     case CODEREJ:
926                 /* decode the rejected LCP packet here. */
927       if (length > 0)
928         proto_tree_add_text(fh_tree, offset, length, "Rejected packet (%d byte%s)",
929                                 length, plurality(length, "", "s"));
930       break;
931
932     case TERMREQ:
933     case TERMACK:
934       if (length > 0)
935         proto_tree_add_text(fh_tree, offset, length, "Data (%d byte%s)",
936                                 length, plurality(length, "", "s"));
937       break;
938
939     default:
940       if (length > 0)
941         proto_tree_add_text(fh_tree, offset, length, "Stuff (%d byte%s)",
942                                 length, plurality(length, "", "s"));
943       break;
944   }
945 }
946
947 static gboolean
948 dissect_ppp_stuff( const u_char *pd, int offset, frame_data *fd,
949                 proto_tree *tree, proto_tree *fh_tree ) {
950   guint16 ppp_prot;
951
952   ppp_prot = pntohs(&pd[offset]);
953
954   if (tree) {
955     proto_tree_add_text(fh_tree, offset, 2, "Protocol: %s (0x%04x)",
956       val_to_str(ppp_prot, ppp_vals, "Unknown"), ppp_prot);
957   }
958   offset += 2;
959
960   switch (ppp_prot) {
961     case PPP_IP:
962       dissect_ip(pd, offset, fd, tree);
963       return TRUE;
964     case PPP_AT:
965       dissect_ddp(pd, offset, fd, tree);
966       return TRUE;
967     case PPP_IPX:
968       dissect_ipx(pd, offset, fd, tree);
969       return TRUE;
970     case PPP_VINES:
971       dissect_vines(pd, offset, fd, tree);
972       return TRUE;
973     case PPP_IPV6:
974       dissect_ipv6(pd, offset, fd, tree);
975       return TRUE;
976     case PPP_LCP:
977       dissect_cp(pd, offset, "L", "Link", ETT_LCP, lcp_vals, ETT_LCP_OPTIONS,
978                 lcp_opts, N_LCP_OPTS, fd, tree);
979       return TRUE;
980     case PPP_IPCP:
981       dissect_cp(pd, offset, "IP", "IP", ETT_IPCP, cp_vals, ETT_IPCP_OPTIONS,
982                 ipcp_opts, N_IPCP_OPTS, fd, tree);
983       return TRUE;
984     default:
985       if (check_col(fd, COL_INFO))
986         col_add_fstr(fd, COL_INFO, "PPP %s (0x%04x)",
987                 val_to_str(ppp_prot, ppp_vals, "Unknown"), ppp_prot);
988       dissect_data(pd, offset, fd, tree);
989       return FALSE;
990   }
991 }
992
993 void
994 dissect_payload_ppp( const u_char *pd, int offset, frame_data *fd, proto_tree *tree ) {
995   proto_item *ti;
996   proto_tree *fh_tree = NULL;
997
998   /* populate a tree in the second pane with the status of the link
999      layer (ie none) */
1000   if(tree) {
1001     ti = proto_tree_add_item(tree, proto_ppp, 0+offset, 2, NULL);
1002     fh_tree = proto_item_add_subtree(ti, ETT_PPP);
1003   }
1004
1005   dissect_ppp_stuff(pd, offset, fd, tree, fh_tree);
1006 }
1007
1008 void
1009 dissect_ppp( const u_char *pd, frame_data *fd, proto_tree *tree ) {
1010   e_ppphdr   ph;
1011   proto_item *ti;
1012   proto_tree *fh_tree = NULL;
1013
1014   ph.ppp_addr = pd[0];
1015   ph.ppp_ctl  = pd[1];
1016   ph.ppp_prot = pntohs(&pd[2]);
1017
1018   /* load the top pane info. This should be overwritten by
1019      the next protocol in the stack */
1020
1021   if(check_col(fd, COL_RES_DL_SRC))
1022     col_add_str(fd, COL_RES_DL_SRC, "N/A" );
1023   if(check_col(fd, COL_RES_DL_DST))
1024     col_add_str(fd, COL_RES_DL_DST, "N/A" );
1025   if(check_col(fd, COL_PROTOCOL))
1026     col_add_str(fd, COL_PROTOCOL, "PPP" );
1027
1028   /* populate a tree in the second pane with the status of the link
1029      layer (ie none) */
1030   if(tree) {
1031     ti = proto_tree_add_item(tree, proto_ppp, 0, 4, NULL);
1032     fh_tree = proto_item_add_subtree(ti, ETT_PPP);
1033     proto_tree_add_text(fh_tree, 0, 1, "Address: %02x", ph.ppp_addr);
1034     proto_tree_add_text(fh_tree, 1, 1, "Control: %02x", ph.ppp_ctl);
1035   }
1036
1037   if (!dissect_ppp_stuff(pd, 2, fd, tree, fh_tree)) {
1038     if (check_col(fd, COL_PROTOCOL))
1039       col_add_fstr(fd, COL_PROTOCOL, "0x%04x", ph.ppp_prot);
1040   }
1041 }
1042
1043 void
1044 proto_register_ppp(void)
1045 {
1046 /*        static hf_register_info hf[] = {
1047                 { &variable,
1048                 { "Name",           "ppp.abbreviation", TYPE, VALS_POINTER }},
1049         };*/
1050
1051         proto_ppp = proto_register_protocol("Point-to-Point Protocol", "ppp");
1052  /*       proto_register_field_array(proto_ppp, hf, array_length(hf));*/
1053 }