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