From Chris Wilson:
[obnox/wireshark/wip.git] / packet-pptp.c
1 /* packet-pptp.c
2  * Routines for the Point-to-Point Tunnelling Protocol (PPTP) (RFC 2637)
3  * Brad Robel-Forrest <brad.robel-forrest@watchguard.com>
4  *
5  * $Id: packet-pptp.c,v 1.29 2003/08/12 02:05:41 gerald Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31
32 #include <glib.h>
33 #include <epan/packet.h>
34
35 static int proto_pptp = -1;
36 static int hf_pptp_message_type = -1;
37
38 static gint ett_pptp = -1;
39
40 static dissector_handle_t data_handle;
41
42 #define TCP_PORT_PPTP                   1723
43
44 #define MAGIC_COOKIE            0x1A2B3C4D
45
46 static const value_string msgtype_vals[] = {
47   { 1, "Control Message" },
48   { 2, "Management Message" },
49   { 0, NULL }
50 };
51
52 #define NUM_FRAME_TYPES         4
53 #define frametype2str(t)        \
54   ((t < NUM_FRAME_TYPES) ? frametypestr[t] : "Unknown framing type")
55
56 static const char *frametypestr[NUM_FRAME_TYPES] = {
57   "Unknown framing type",
58   "Asynchronous Framing supported",
59   "Synchronous Framing supported",
60   "Either Framing supported"
61 };
62
63 #define NUM_BEARER_TYPES        4
64 #define bearertype2str(t)       \
65   ((t < NUM_BEARER_TYPES) ? bearertypestr[t] : "Unknown bearer type")
66
67 static const char *bearertypestr[NUM_BEARER_TYPES] = {
68   "Unknown bearer type",
69   "Analog access supported",
70   "Digital access supported",
71   "Either access supported"
72 };
73
74 #define NUM_CNTRLRESULT_TYPES   6
75 #define cntrlresulttype2str(t)  \
76   ((t < NUM_CNTRLRESULT_TYPES) ? cntrlresulttypestr[t] : "Unknown Start-Control-connection-Reply result code")
77
78 static const char *cntrlresulttypestr[NUM_CNTRLRESULT_TYPES] = {
79   "Unknown Start-Control-connection-Reply result code",
80   "Successful channel establishment",
81   "General error",
82   "Command channel already exists",
83   "Requester not authorized",
84   "Protocol version not supported"
85 };
86
87 #define NUM_ERROR_TYPES         7
88 #define errortype2str(t)        \
89   ((t < NUM_ERROR_TYPES) ? errortypestr[t] : "Unknown general error code")
90
91 static const char *errortypestr[NUM_ERROR_TYPES] = {
92   "None",
93   "Not-Connected",
94   "Bad-Format",
95   "Bad-Value",
96   "No-Resource",
97   "Bad-Call ID",
98   "PAC-Error"
99 };
100
101 #define NUM_REASON_TYPES        4
102 #define reasontype2str(t)       \
103   ((t < NUM_REASON_TYPES) ? reasontypestr[t] : "Unknown Stop-Control-Connection-Request reason code")
104
105 static const char *reasontypestr[NUM_REASON_TYPES] = {
106   "Unknown Stop-Control-Connection-Request reason code",
107   "None",
108   "Stop-Protocol",
109   "Stop-Local-Shutdown"
110 };
111
112 #define NUM_STOPRESULT_TYPES    3
113 #define stopresulttype2str(t)   \
114   ((t < NUM_STOPRESULT_TYPES) ? stopresulttypestr[t] : "Unknown Stop-Control-Connection-Reply result code")
115
116 static const char *stopresulttypestr[NUM_STOPRESULT_TYPES] = {
117   "Unknown Stop-Control-Connection-Reply result code",
118   "OK",
119   "General error"
120 };
121
122 #define NUM_ECHORESULT_TYPES    3
123 #define echoresulttype2str(t)   \
124   ((t < NUM_ECHORESULT_TYPES) ? echoresulttypestr[t] : "Unknown Echo-Reply result code")
125
126 static const char *echoresulttypestr[NUM_ECHORESULT_TYPES] = {
127   "Unknown Echo-Reply result code",
128   "OK",
129   "General error"
130 };
131
132 #define NUM_OUTRESULT_TYPES     8
133 #define outresulttype2str(t)    \
134   ((t < NUM_OUTRESULT_TYPES) ? outresulttypestr[t] : "Unknown Outgoing-Call-Reply result code")
135
136 static const char *outresulttypestr[NUM_OUTRESULT_TYPES] = {
137   "Unknown Outgoing-Call-Reply result code",
138   "Connected",
139   "General Error",
140   "No Carrier",
141   "Busy",
142   "No Dial Tone",
143   "Time-out",
144   "Do Not Accept"
145 };
146
147 #define NUM_INRESULT_TYPES      4
148 #define inresulttype2str(t)     \
149   ((t < NUM_INRESULT_TYPES) ? inresulttypestr[t] : "Unknown Incoming-Call-Reply result code")
150
151 static const char *inresulttypestr[NUM_INRESULT_TYPES] = {
152   "Unknown Incoming-Call-Reply result code",
153   "Connect",
154   "General Error",
155   "Do Not Accept"
156 };
157
158 #define NUM_DISCRESULT_TYPES    5
159 #define discresulttype2str(t)   \
160   ((t < NUM_DISCRESULT_TYPES) ? discresulttypestr[t] : "Unknown Call-Disconnect-Notify result code")
161
162 static const char *discresulttypestr[NUM_DISCRESULT_TYPES] = {
163   "Unknown Call-Disconnect-Notify result code",
164   "Lost Carrier",
165   "General Error",
166   "Admin Shutdown",
167   "Request"
168 };
169
170 static void dissect_unknown(tvbuff_t *, int, packet_info *, proto_tree *);
171 static void dissect_cntrl_req(tvbuff_t *, int, packet_info *, proto_tree *);
172 static void dissect_cntrl_reply(tvbuff_t *, int, packet_info *, proto_tree *);
173 static void dissect_stop_req(tvbuff_t *, int, packet_info *, proto_tree *);
174 static void dissect_stop_reply(tvbuff_t *, int, packet_info *, proto_tree *);
175 static void dissect_echo_req(tvbuff_t *, int, packet_info *, proto_tree *);
176 static void dissect_echo_reply(tvbuff_t *, int, packet_info *, proto_tree *);
177 static void dissect_out_req(tvbuff_t *, int, packet_info *, proto_tree *);
178 static void dissect_out_reply(tvbuff_t *, int, packet_info *, proto_tree *);
179 static void dissect_in_req(tvbuff_t *, int, packet_info *, proto_tree *);
180 static void dissect_in_reply(tvbuff_t *, int, packet_info *, proto_tree *);
181 static void dissect_in_connected(tvbuff_t *, int, packet_info *, proto_tree *);
182 static void dissect_clear_req(tvbuff_t *, int, packet_info *, proto_tree *);
183 static void dissect_disc_notify(tvbuff_t *, int, packet_info *, proto_tree *);
184 static void dissect_error_notify(tvbuff_t *, int, packet_info *, proto_tree *);
185 static void dissect_set_link(tvbuff_t *, int, packet_info *, proto_tree *);
186
187 #define NUM_CNTRL_TYPES         16
188 #define cntrltype2str(t)        \
189   ((t < NUM_CNTRL_TYPES) ? strfuncs[t].str : "UNKNOWN-CONTROL-TYPE")
190
191 static struct strfunc {
192   const char *  str;
193   void          (*func)(tvbuff_t *, int, packet_info *, proto_tree *);
194 } strfuncs[NUM_CNTRL_TYPES] = {
195   {"Unknown control type",    dissect_unknown      },
196   {"Start-Control-Connection-Request",   dissect_cntrl_req    },
197   {"Start-Control-Connection-Reply",     dissect_cntrl_reply  },
198   {"Stop-Control-Connection-Request",    dissect_stop_req     },
199   {"Stop-Control-Connection-Reply",      dissect_stop_reply   },
200   {"Echo-Request",                       dissect_echo_req     },
201   {"Echo-Reply",                         dissect_echo_reply   },
202   {"Outgoing-Call-Request",              dissect_out_req      },
203   {"Outgoing-Call-Reply",                dissect_out_reply    },
204   {"Incoming-Call-Request",              dissect_in_req       },
205   {"Incoming-Call-Reply",                dissect_in_reply     },
206   {"Incoming-Call-Connected",            dissect_in_connected },
207   {"Call-Clear-Request",                 dissect_clear_req    },
208   {"Call-Disconnect-Notify",             dissect_disc_notify  },
209   {"WAN-Error-Notify",                   dissect_error_notify },
210   {"Set-Link-Info",                      dissect_set_link     }
211 };
212
213 /*
214  * Length of host name and vendor name strings in control requests and
215  * replies.
216  */
217 #define HOSTLEN         64
218 #define VENDORLEN       64
219
220 /*
221  * Length of phone number(s) and subaddress in call requests.
222  */
223 #define PHONELEN        64
224 #define SUBADDRLEN      64
225
226 /*
227  * Length of statistics in a Call-Disconnect-Notify message.
228  */
229 #define STATSLEN        128
230
231 static void
232 dissect_pptp(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
233 {
234   int                   offset = 0;
235   guint16               len;
236   guint16               cntrl_type;
237
238   if (check_col(pinfo->cinfo, COL_PROTOCOL))
239     col_set_str(pinfo->cinfo, COL_PROTOCOL, "PPTP");
240   if (check_col(pinfo->cinfo, COL_INFO))
241     col_clear(pinfo->cinfo, COL_INFO);
242
243   len        = tvb_get_ntohs(tvb, offset);
244   cntrl_type = tvb_get_ntohs(tvb, offset + 8);
245
246   if (check_col(pinfo->cinfo, COL_INFO))
247     col_add_fstr(pinfo->cinfo, COL_INFO, "%s", cntrltype2str(cntrl_type));
248
249   if (tree) {
250     guint32             cookie;
251     proto_item *        ti;
252     proto_tree *        pptp_tree;
253
254     ti = proto_tree_add_item(tree, proto_pptp, tvb, offset, len, FALSE);
255     pptp_tree = proto_item_add_subtree(ti, ett_pptp);
256
257     proto_tree_add_text(pptp_tree, tvb, offset, 2, "Length: %u", len);
258     offset += 2;
259
260     proto_tree_add_item(pptp_tree, hf_pptp_message_type, tvb,
261                                offset, 2, FALSE);
262     offset += 2;
263
264     cookie = tvb_get_ntohl(tvb, offset);
265
266     if (cookie == MAGIC_COOKIE)
267       proto_tree_add_text(pptp_tree, tvb, offset, 4,
268                           "Cookie: %#08x (correct)", cookie);
269     else
270       proto_tree_add_text(pptp_tree, tvb, offset, 4,
271                           "Cookie: %#08x (incorrect)", cookie);
272     offset += 4;
273
274     proto_tree_add_text(pptp_tree, tvb, offset, 2,
275                         "Control type: %s (%u)", cntrltype2str(cntrl_type), cntrl_type);
276     offset += 2;
277
278     proto_tree_add_text(pptp_tree, tvb, offset, 2,
279                         "Reserved: %u", tvb_get_ntohs(tvb, offset));
280     offset += 2;
281
282     if (cntrl_type < NUM_CNTRL_TYPES)
283       ( *(strfuncs[cntrl_type].func))(tvb, offset, pinfo, pptp_tree);
284     else
285       call_dissector(data_handle,tvb_new_subset(tvb, offset, -1, -1), pinfo, pptp_tree);
286   }
287 }
288
289 static void
290 dissect_unknown(tvbuff_t *tvb, int offset, packet_info *pinfo,
291                 proto_tree *tree)
292 {
293   call_dissector(data_handle,tvb_new_subset(tvb, offset, -1, -1), pinfo, tree);
294 }
295
296 static void
297 dissect_cntrl_req(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
298                   proto_tree *tree)
299 {
300   guint8                major_ver;
301   guint8                minor_ver;
302   guint32               frame;
303   guint32               bearer;
304   guint8                host[HOSTLEN+1];
305   guint8                vendor[VENDORLEN+1];
306
307   major_ver = tvb_get_guint8(tvb, offset);
308   minor_ver = tvb_get_guint8(tvb, offset + 1);
309   proto_tree_add_text(tree, tvb, offset, 2,
310                       "Protocol version: %u.%u", major_ver, minor_ver);
311   offset += 2;
312
313   proto_tree_add_text(tree, tvb, offset, 2,
314                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
315   offset += 2;
316
317   frame = tvb_get_ntohl(tvb, offset);
318   proto_tree_add_text(tree, tvb, offset, 4,
319                       "Framing capabilities: %s (%u)", frametype2str(frame), frame);
320   offset += 4;
321
322   bearer = tvb_get_ntohl(tvb, offset);
323   proto_tree_add_text(tree, tvb, offset, 4,
324                       "Bearer capabilities: %s (%u)", bearertype2str(bearer), bearer);
325   offset += 4;
326
327   proto_tree_add_text(tree, tvb, offset, 2,
328                       "Maximum channels: %u", tvb_get_ntohs(tvb, offset));
329   offset += 2;
330
331   proto_tree_add_text(tree, tvb, offset, 2,
332                       "Firmware revision: %u", tvb_get_ntohs(tvb, offset));
333   offset += 2;
334
335   tvb_memcpy(tvb, host, offset, HOSTLEN);
336   host[HOSTLEN] = '\0';
337   proto_tree_add_text(tree, tvb, offset, HOSTLEN,
338                       "Hostname: %s", host);
339   offset += HOSTLEN;
340
341   tvb_memcpy(tvb, vendor, offset, VENDORLEN);
342   vendor[VENDORLEN] = '\0';
343   proto_tree_add_text(tree, tvb, offset, VENDORLEN,
344                       "Vendor: %s", vendor);
345 }
346
347 static void
348 dissect_cntrl_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
349                     proto_tree *tree)
350 {
351   guint8                major_ver;
352   guint8                minor_ver;
353   guint8                result;
354   guint8                error;
355   guint32               frame;
356   guint32               bearer;
357   guint8                host[HOSTLEN+1];
358   guint8                vendor[VENDORLEN+1];
359
360   major_ver = tvb_get_guint8(tvb, offset);
361   minor_ver = tvb_get_guint8(tvb, offset + 1);
362   proto_tree_add_text(tree, tvb, offset, 2,
363                       "Protocol version: %u.%u", major_ver, minor_ver);
364   offset += 2;
365
366   result = tvb_get_guint8(tvb, offset);
367   proto_tree_add_text(tree, tvb, offset, 1,
368                       "Result: %s (%u)", cntrlresulttype2str(result), result);
369   offset += 1;
370
371   error = tvb_get_guint8(tvb, offset);
372   proto_tree_add_text(tree, tvb, offset, 1,
373                       "Error: %s (%u)", errortype2str(error), error);
374   offset += 1;
375
376   frame = tvb_get_ntohl(tvb, offset);
377   proto_tree_add_text(tree, tvb, offset, 4,
378                       "Framing capabilities: %s (%u)", frametype2str(frame), frame);
379   offset += 4;
380
381   bearer = tvb_get_ntohl(tvb, offset);
382   proto_tree_add_text(tree, tvb, offset, 4,
383                       "Bearer capabilities: %s (%u)", bearertype2str(bearer), bearer);
384   offset += 4;
385
386   proto_tree_add_text(tree, tvb, offset, 2,
387                       "Maximum channels: %u", tvb_get_ntohs(tvb, offset));
388   offset += 2;
389
390   proto_tree_add_text(tree, tvb, offset, 2,
391                       "Firmware revision: %u", tvb_get_ntohs(tvb, offset));
392   offset += 2;
393
394   tvb_memcpy(tvb, host, offset, HOSTLEN);
395   host[HOSTLEN] = '\0';
396   proto_tree_add_text(tree, tvb, offset, HOSTLEN,
397                       "Hostname: %s", host);
398   offset += HOSTLEN;
399
400   tvb_memcpy(tvb, vendor, offset, VENDORLEN);
401   vendor[VENDORLEN] = '\0';
402   proto_tree_add_text(tree, tvb, offset, VENDORLEN,
403                       "Vendor: %s", vendor);
404 }
405
406 static void
407 dissect_stop_req(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
408                  proto_tree *tree)
409 {
410   guint8                reason;
411
412   reason = tvb_get_guint8(tvb, offset);
413   proto_tree_add_text(tree, tvb, offset, 1,
414                       "Reason: %s (%u)", reasontype2str(reason), reason);
415   offset += 1;
416
417   proto_tree_add_text(tree, tvb, offset, 1,
418                       "Reserved: %u", tvb_get_guint8(tvb, offset));
419   offset += 1;
420
421   proto_tree_add_text(tree, tvb, offset, 2,
422                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
423 }
424
425 static void
426 dissect_stop_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
427                    proto_tree *tree)
428 {
429   guint8                result;
430   guint8                error;
431
432   result = tvb_get_guint8(tvb, offset);
433   proto_tree_add_text(tree, tvb, offset, 1,
434                       "Result: %s (%u)", stopresulttype2str(result), result);
435   offset += 1;
436
437   error = tvb_get_guint8(tvb, offset);
438   proto_tree_add_text(tree, tvb, offset, 1,
439                       "Error: %s (%u)", errortype2str(error), error);
440   offset += 1;
441
442   proto_tree_add_text(tree, tvb, offset, 2,
443                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
444 }
445
446 static void
447 dissect_echo_req(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
448                  proto_tree *tree)
449 {
450   proto_tree_add_text(tree, tvb, offset, 4,
451                       "Identifier: %u", tvb_get_ntohl(tvb, offset));
452 }
453
454 static void
455 dissect_echo_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
456                    proto_tree *tree)
457 {
458   guint8                result;
459   guint8                error;
460
461   proto_tree_add_text(tree, tvb, offset, 4,
462                       "Identifier: %u", tvb_get_ntohl(tvb, offset));
463   offset += 4;
464
465   result = tvb_get_guint8(tvb, offset);
466   proto_tree_add_text(tree, tvb, offset, 1,
467                       "Result: %s (%u)", echoresulttype2str(result), result);
468   offset += 1;
469
470   error = tvb_get_guint8(tvb, offset);
471   proto_tree_add_text(tree, tvb, offset, sizeof(error),
472                       "Error: %s (%u)", errortype2str(error), error);
473   offset += 1;
474
475   proto_tree_add_text(tree, tvb, offset, 2,
476                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
477 }
478
479 static void
480 dissect_out_req(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
481                 proto_tree *tree)
482 {
483   guint32               bearer;
484   guint32               frame;
485   guint8                phone[PHONELEN+1];
486   guint8                subaddr[SUBADDRLEN+1];
487
488   proto_tree_add_text(tree, tvb, offset, 2,
489                       "Call ID: %u", tvb_get_ntohs(tvb, offset));
490   offset += 2;
491
492   proto_tree_add_text(tree, tvb, offset, 2,
493                       "Call Serial Number: %u", tvb_get_ntohs(tvb, offset));
494   offset += 2;
495
496   proto_tree_add_text(tree, tvb, offset, 4,
497                       "Minimum BPS: %u", tvb_get_ntohl(tvb, offset));
498   offset += 4;
499
500   proto_tree_add_text(tree, tvb, offset, 4,
501                       "Maximum BPS: %u", tvb_get_ntohl(tvb, offset));
502   offset += 4;
503
504   bearer = tvb_get_ntohl(tvb, offset);
505   proto_tree_add_text(tree, tvb, offset, 4,
506                       "Bearer capabilities: %s (%u)", bearertype2str(bearer), bearer);
507   offset += 4;
508
509   frame = tvb_get_ntohl(tvb, offset);
510   proto_tree_add_text(tree, tvb, offset, 4,
511                       "Framing capabilities: %s (%u)", frametype2str(frame), frame);
512   offset += 4;
513
514   proto_tree_add_text(tree, tvb, offset, 2,
515                       "Receive window size: %u", tvb_get_ntohs(tvb, offset));
516   offset += 2;
517
518   proto_tree_add_text(tree, tvb, offset, 2,
519                       "Processing delay: %u", tvb_get_ntohs(tvb, offset));
520   offset += 2;
521
522   proto_tree_add_text(tree, tvb, offset, 2,
523                       "Phone number length: %u", tvb_get_ntohs(tvb, offset));
524   offset += 2;
525
526   proto_tree_add_text(tree, tvb, offset, 2,
527                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
528   offset += 2;
529
530   tvb_memcpy(tvb, phone, offset, PHONELEN);
531   phone[PHONELEN] = '\0';
532   proto_tree_add_text(tree, tvb, offset, PHONELEN,
533                       "Phone number: %s", phone);
534   offset += PHONELEN;
535
536   tvb_memcpy(tvb, subaddr, offset, SUBADDRLEN);
537   subaddr[SUBADDRLEN] = '\0';
538   proto_tree_add_text(tree, tvb, offset, SUBADDRLEN,
539                       "Subaddress: %s", subaddr);
540 }
541
542 static void
543 dissect_out_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
544                   proto_tree *tree)
545 {
546   guint8                result;
547   guint8                error;
548
549   proto_tree_add_text(tree, tvb, offset, 2,
550                       "Call ID: %u", tvb_get_ntohs(tvb, offset));
551   offset += 2;
552
553   proto_tree_add_text(tree, tvb, offset, 2,
554                       "Peer's call ID: %u", tvb_get_ntohs(tvb, offset));
555   offset += 2;
556
557   result = tvb_get_guint8(tvb, offset);
558   proto_tree_add_text(tree, tvb, offset, 1,
559                       "Result: %s (%u)", outresulttype2str(result), result);
560   offset += 1;
561
562   error = tvb_get_guint8(tvb, offset);
563   proto_tree_add_text(tree, tvb, offset, 1,
564                       "Error: %s (%u)", errortype2str(error), error);
565   offset += 1;
566
567   proto_tree_add_text(tree, tvb, offset, 2,
568                       "Cause code: %u", tvb_get_ntohs(tvb, offset));
569   offset += 2;
570
571   proto_tree_add_text(tree, tvb, offset, 4,
572                       "Connect speed: %u", tvb_get_ntohl(tvb, offset));
573   offset += 4;
574
575   proto_tree_add_text(tree, tvb, offset, 2,
576                       "Receive window size: %u", tvb_get_ntohs(tvb, offset));
577   offset += 2;
578
579   proto_tree_add_text(tree, tvb, offset, 2,
580                       "Processing delay: %u", tvb_get_ntohs(tvb, offset));
581   offset += 2;
582
583   proto_tree_add_text(tree, tvb, offset, 4,
584                       "Physical channel ID: %u", tvb_get_ntohl(tvb, offset));
585 }
586
587 static void
588 dissect_in_req(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
589                proto_tree *tree)
590 {
591   guint32               bearer;
592   guint8                dialed[PHONELEN+1];
593   guint8                dialing[PHONELEN+1];
594   guint8                subaddr[SUBADDRLEN+1];
595
596   proto_tree_add_text(tree, tvb, offset, 2,
597                       "Call ID: %u", tvb_get_ntohs(tvb, offset));
598   offset += 2;
599
600   proto_tree_add_text(tree, tvb, offset, 2,
601                       "Call serial number: %u", tvb_get_ntohs(tvb, offset));
602   offset += 2;
603
604   bearer = tvb_get_ntohl(tvb, offset);
605   proto_tree_add_text(tree, tvb, offset, 4,
606                       "Bearer capabilities: %s (%u)", bearertype2str(bearer), bearer);
607   offset += 4;
608
609   proto_tree_add_text(tree, tvb, offset, 4,
610                       "Physical channel ID: %u", tvb_get_ntohl(tvb, offset));
611   offset += 4;
612
613   proto_tree_add_text(tree, tvb, offset, 2,
614                       "Dialed number length: %u", tvb_get_ntohs(tvb, offset));
615   offset += 2;
616
617   proto_tree_add_text(tree, tvb, offset, 2,
618                       "Dialing number length: %u", tvb_get_ntohs(tvb, offset));
619   offset += 2;
620
621   tvb_memcpy(tvb, dialing, offset, PHONELEN);
622   dialed[PHONELEN] = '\0';
623   proto_tree_add_text(tree, tvb, offset, PHONELEN,
624                       "Dialed number: %s", dialed);
625   offset += PHONELEN;
626
627   tvb_memcpy(tvb, dialing, offset, PHONELEN);
628   dialing[PHONELEN] = '\0';
629   proto_tree_add_text(tree, tvb, offset, PHONELEN,
630                       "Dialing number: %s", dialing);
631   offset += PHONELEN;
632
633   tvb_memcpy(tvb, subaddr, offset, SUBADDRLEN);
634   subaddr[SUBADDRLEN] = '\0';
635   proto_tree_add_text(tree, tvb, offset, SUBADDRLEN,
636                       "Subaddress: %s", subaddr);
637 }
638
639 static void
640 dissect_in_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
641                  proto_tree *tree)
642 {
643   guint8                result;
644   guint8                error;
645
646   proto_tree_add_text(tree, tvb, offset, 2,
647                       "Call ID: %u", tvb_get_ntohs(tvb, offset));
648   offset += 2;
649
650   proto_tree_add_text(tree, tvb, offset, 2,
651                       "Peer's call ID: %u", tvb_get_ntohs(tvb, offset));
652   offset += 2;
653
654   result = tvb_get_guint8(tvb, offset);
655   proto_tree_add_text(tree, tvb, offset, 1,
656                       "Result: %s (%u)", inresulttype2str(result), result);
657   offset += 1;
658
659   error = tvb_get_guint8(tvb, offset);
660   proto_tree_add_text(tree, tvb, offset, 1,
661                       "Error: %s (%u)", errortype2str(error), error);
662   offset += 1;
663
664   proto_tree_add_text(tree, tvb, offset, 2,
665                       "Receive window size: %u", tvb_get_ntohs(tvb, offset));
666   offset += 2;
667
668   proto_tree_add_text(tree, tvb, offset, 2,
669                       "Processing delay: %u", tvb_get_ntohs(tvb, offset));
670   offset += 2;
671
672   proto_tree_add_text(tree, tvb, offset, 2,
673                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
674 }
675
676 static void
677 dissect_in_connected(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
678                      proto_tree *tree)
679 {
680   guint32               frame;
681
682   proto_tree_add_text(tree, tvb, offset, 2,
683                       "Peer's call ID: %u", tvb_get_ntohs(tvb, offset));
684   offset += 2;
685
686   proto_tree_add_text(tree, tvb, offset, 2,
687                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
688   offset += 2;
689
690   proto_tree_add_text(tree, tvb, offset, 4,
691                       "Connect speed: %u", tvb_get_ntohl(tvb, offset));
692   offset += 4;
693
694   proto_tree_add_text(tree, tvb, offset, 2,
695                       "Receive window size: %u", tvb_get_ntohs(tvb, offset));
696   offset += 2;
697
698   proto_tree_add_text(tree, tvb, offset, 2,
699                       "Processing delay: %u", tvb_get_ntohs(tvb, offset));
700   offset += 2;
701
702   frame = tvb_get_ntohl(tvb, offset);
703   proto_tree_add_text(tree, tvb, offset, 4,
704                       "Framing capabilities: %s (%u)", frametype2str(frame), frame);
705 }
706
707 static void
708 dissect_clear_req(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
709                   proto_tree *tree)
710 {
711   proto_tree_add_text(tree, tvb, offset, 2,
712                       "Call ID: %u", tvb_get_ntohs(tvb, offset));
713   offset += 2;
714
715   proto_tree_add_text(tree, tvb, offset, 2,
716                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
717 }
718
719 static void
720 dissect_disc_notify(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
721                     proto_tree *tree)
722 {
723   guint8                result;
724   guint8                error;
725   guint8                stats[STATSLEN+1];
726
727   proto_tree_add_text(tree, tvb, offset, 2,
728                       "Call ID: %u", tvb_get_ntohs(tvb, offset));
729   offset += 2;
730
731   result = tvb_get_guint8(tvb, offset);
732   proto_tree_add_text(tree, tvb, offset, 1,
733                       "Result: %s (%u)", discresulttype2str(result), result);
734   offset += 1;
735
736   error = tvb_get_guint8(tvb, offset);
737   proto_tree_add_text(tree, tvb, offset, 1,
738                       "Error: %s (%u)", errortype2str(error), error);
739   offset += 1;
740
741   proto_tree_add_text(tree, tvb, offset, 2,
742                       "Cause code: %u", tvb_get_ntohs(tvb, offset));
743   offset += 2;
744
745   proto_tree_add_text(tree, tvb, offset, 2,
746                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
747   offset += 2;
748
749   tvb_memcpy(tvb, stats, offset, STATSLEN);
750   stats[STATSLEN] = '\0';
751   proto_tree_add_text(tree, tvb, offset, STATSLEN,
752                       "Call statistics: %s", stats);
753 }
754
755 static void
756 dissect_error_notify(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
757                      proto_tree *tree)
758 {
759   proto_tree_add_text(tree, tvb, offset, 2,
760                       "Peer's call ID: %u", tvb_get_ntohs(tvb, offset));
761   offset += 2;
762
763   proto_tree_add_text(tree, tvb, offset, 2,
764                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
765   offset += 2;
766
767   proto_tree_add_text(tree, tvb, offset, 4,
768                       "CRC errors: %u", tvb_get_ntohl(tvb, offset));
769   offset += 4;
770
771   proto_tree_add_text(tree, tvb, offset, 4,
772                       "Framing errors: %u", tvb_get_ntohl(tvb, offset));
773   offset += 4;
774
775   proto_tree_add_text(tree, tvb, offset, 4,
776                       "Hardware overruns: %u", tvb_get_ntohl(tvb, offset));
777   offset += 4;
778
779   proto_tree_add_text(tree, tvb, offset, 4,
780                       "Buffer overruns: %u", tvb_get_ntohl(tvb, offset));
781   offset += 4;
782
783   proto_tree_add_text(tree, tvb, offset, 4,
784                       "Time-out errors: %u", tvb_get_ntohl(tvb, offset));
785   offset += 4;
786
787   proto_tree_add_text(tree, tvb, offset, 4,
788                       "Alignment errors: %u", tvb_get_ntohl(tvb, offset));
789 }
790
791 static void
792 dissect_set_link(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
793                  proto_tree *tree)
794 {
795   proto_tree_add_text(tree, tvb, offset, 2,
796                       "Peer's call ID: %u", tvb_get_ntohs(tvb, offset));
797   offset += 2;
798
799   proto_tree_add_text(tree, tvb, offset, 2,
800                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
801   offset += 2;
802
803   proto_tree_add_text(tree, tvb, offset, 4,
804                       "Send ACCM: %#08x", tvb_get_ntohl(tvb, offset));
805   offset += 4;
806
807   proto_tree_add_text(tree, tvb, offset, 4,
808                       "Recv ACCM: %#08x", tvb_get_ntohl(tvb, offset));
809 }
810
811 void
812 proto_register_pptp(void)
813 {
814   static gint *ett[] = {
815     &ett_pptp,
816   };
817
818   static hf_register_info hf[] = {
819     { &hf_pptp_message_type,
820       { "Message type",                 "pptp.type",
821         FT_UINT16,      BASE_DEC,       VALS(msgtype_vals),     0x0,
822         "PPTP message type", HFILL }}
823   };
824
825   proto_pptp = proto_register_protocol("Point-to-Point Tunnelling Protocol",
826                                        "PPTP", "pptp");
827   proto_register_field_array(proto_pptp, hf, array_length(hf));
828   proto_register_subtree_array(ett, array_length(ett));
829 }
830
831 void
832 proto_reg_handoff_pptp(void)
833 {
834   dissector_handle_t pptp_handle;
835
836   pptp_handle = create_dissector_handle(dissect_pptp, proto_pptp);
837   dissector_add("tcp.port", TCP_PORT_PPTP, pptp_handle);
838   data_handle = find_dissector("data");
839 }