Check whether the array of procedure hf values has an element for the
[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.26 2002/08/28 21:00:25 jmayer 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",
59   "SYNCHRONOUS",
60   "EITHER"
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",
70   "DIGITAL",
71   "EITHER"
72 };
73
74 #define NUM_CNTRLRESULT_TYPES   6
75 #define cntrlresulttype2str(t)  \
76   ((t < NUM_CNTRLRESULT_TYPES) ? cntrlresulttypestr[t] : "UNKNOWN-CNTRLRESULT-TYPE")
77
78 static const char *cntrlresulttypestr[NUM_CNTRLRESULT_TYPES] = {
79   "UNKNOWN-CNTRLRESULT-TYPE",
80   "SUCCESS",
81   "GENERAL-ERROR",
82   "COMMAND-CHANNEL-EXISTS",
83   "NOT-AUTHORIZED",
84   "VERSION-NOT-SUPPORTED"
85 };
86
87 #define NUM_ERROR_TYPES         7
88 #define errortype2str(t)        \
89   ((t < NUM_ERROR_TYPES) ? errortypestr[t] : "UNKNOWN-ERROR-TYPE")
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-REASON-TYPE")
104
105 static const char *reasontypestr[NUM_REASON_TYPES] = {
106   "UNKNOWN-REASON-TYPE",
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-STOPRESULT-TYPE")
115
116 static const char *stopresulttypestr[NUM_STOPRESULT_TYPES] = {
117   "UNKNOWN-STOPRESULT-TYPE",
118   "SUCCESS",
119   "GENERAL-ERROR"
120 };
121
122 #define NUM_ECHORESULT_TYPES    3
123 #define echoresulttype2str(t)   \
124   ((t < NUM_ECHORESULT_TYPES) ? echoresulttypestr[t] : "UNKNOWN-ECHORESULT-TYPE")
125
126 static const char *echoresulttypestr[NUM_ECHORESULT_TYPES] = {
127   "UNKNOWN-ECHORESULT-TYPE",
128   "SUCCESS",
129   "GENERAL-ERROR"
130 };
131
132 #define NUM_OUTRESULT_TYPES     8
133 #define outresulttype2str(t)    \
134   ((t < NUM_OUTRESULT_TYPES) ? outresulttypestr[t] : "UNKNOWN-OUTRESULT-TYPE")
135
136 static const char *outresulttypestr[NUM_OUTRESULT_TYPES] = {
137   "UNKNOWN-OUTRESULT-TYPE",
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-INRESULT-TYPE")
150
151 static const char *inresulttypestr[NUM_INRESULT_TYPES] = {
152   "UNKNOWN-INRESULT-TYPE",
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-DISCRESULT-TYPE")
161
162 static const char *discresulttypestr[NUM_DISCRESULT_TYPES] = {
163   "UNKNOWN-DISCRESULT-TYPE",
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-REQUEST",   dissect_cntrl_req    },
197   {"START-CONTROL-REPLY",     dissect_cntrl_reply  },
198   {"STOP-CONTROL-REQUEST",    dissect_stop_req     },
199   {"STOP-CONTROL-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   {"CLEAR-CALL-REQUEST",      dissect_clear_req    },
208   {"DISCONNECT-NOTIFY",       dissect_disc_notify  },
209   {"ERROR-NOTIFY",            dissect_error_notify },
210   {"SET-LINK",                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_get_nstringz0(tvb, offset, HOSTLEN, host);
336   proto_tree_add_text(tree, tvb, offset, HOSTLEN,
337                       "Hostname: %s", host);
338   offset += HOSTLEN;
339
340   tvb_get_nstringz0(tvb, offset, VENDORLEN, vendor);
341   proto_tree_add_text(tree, tvb, offset, VENDORLEN,
342                       "Vendor: %s", vendor);
343 }
344
345 static void
346 dissect_cntrl_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
347                     proto_tree *tree)
348 {
349   guint8                major_ver;
350   guint8                minor_ver;
351   guint8                result;
352   guint8                error;
353   guint32               frame;
354   guint32               bearer;
355   guint8                host[HOSTLEN+1];
356   guint8                vendor[VENDORLEN+1];
357
358   major_ver = tvb_get_guint8(tvb, offset);
359   minor_ver = tvb_get_guint8(tvb, offset + 1);
360   proto_tree_add_text(tree, tvb, offset, 2,
361                       "Protocol version: %u.%u", major_ver, minor_ver);
362   offset += 2;
363
364   result = tvb_get_guint8(tvb, offset);
365   proto_tree_add_text(tree, tvb, offset, 1,
366                       "Result: %s (%u)", cntrlresulttype2str(result), result);
367   offset += 1;
368
369   error = tvb_get_guint8(tvb, offset);
370   proto_tree_add_text(tree, tvb, offset, 1,
371                       "Error: %s (%u)", errortype2str(error), error);
372   offset += 1;
373
374   frame = tvb_get_ntohl(tvb, offset);
375   proto_tree_add_text(tree, tvb, offset, 4,
376                       "Framing capabilities: %s (%u)", frametype2str(frame), frame);
377   offset += 4;
378
379   bearer = tvb_get_ntohl(tvb, offset);
380   proto_tree_add_text(tree, tvb, offset, 4,
381                       "Bearer capabilities: %s (%u)", bearertype2str(bearer), bearer);
382   offset += 4;
383
384   proto_tree_add_text(tree, tvb, offset, 2,
385                       "Maximum channels: %u", tvb_get_ntohs(tvb, offset));
386   offset += 2;
387
388   proto_tree_add_text(tree, tvb, offset, 2,
389                       "Firmware revision: %u", tvb_get_ntohs(tvb, offset));
390   offset += 2;
391
392   tvb_get_nstringz0(tvb, offset, HOSTLEN, host);
393   proto_tree_add_text(tree, tvb, offset, HOSTLEN,
394                       "Hostname: %s", host);
395   offset += HOSTLEN;
396
397   tvb_get_nstringz0(tvb, offset, VENDORLEN, vendor);
398   proto_tree_add_text(tree, tvb, offset, VENDORLEN,
399                       "Vendor: %s", vendor);
400 }
401
402 static void
403 dissect_stop_req(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
404                  proto_tree *tree)
405 {
406   guint8                reason;
407
408   reason = tvb_get_guint8(tvb, offset);
409   proto_tree_add_text(tree, tvb, offset, 1,
410                       "Reason: %s (%u)", reasontype2str(reason), reason);
411   offset += 1;
412
413   proto_tree_add_text(tree, tvb, offset, 1,
414                       "Reserved: %u", tvb_get_guint8(tvb, offset));
415   offset += 1;
416
417   proto_tree_add_text(tree, tvb, offset, 2,
418                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
419 }
420
421 static void
422 dissect_stop_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
423                    proto_tree *tree)
424 {
425   guint8                result;
426   guint8                error;
427
428   result = tvb_get_guint8(tvb, offset);
429   proto_tree_add_text(tree, tvb, offset, 1,
430                       "Result: %s (%u)", stopresulttype2str(result), result);
431   offset += 1;
432
433   error = tvb_get_guint8(tvb, offset);
434   proto_tree_add_text(tree, tvb, offset, 1,
435                       "Error: %s (%u)", errortype2str(error), error);
436   offset += 1;
437
438   proto_tree_add_text(tree, tvb, offset, 2,
439                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
440 }
441
442 static void
443 dissect_echo_req(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
444                  proto_tree *tree)
445 {
446   proto_tree_add_text(tree, tvb, offset, 4,
447                       "Identifier: %u", tvb_get_ntohl(tvb, offset));
448 }
449
450 static void
451 dissect_echo_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
452                    proto_tree *tree)
453 {
454   guint8                result;
455   guint8                error;
456
457   proto_tree_add_text(tree, tvb, offset, 4,
458                       "Identifier: %u", tvb_get_ntohl(tvb, offset));
459   offset += 4;
460
461   result = tvb_get_guint8(tvb, offset);
462   proto_tree_add_text(tree, tvb, offset, 1,
463                       "Result: %s (%u)", echoresulttype2str(result), result);
464   offset += 1;
465
466   error = tvb_get_guint8(tvb, offset);
467   proto_tree_add_text(tree, tvb, offset, sizeof(error),
468                       "Error: %s (%u)", errortype2str(error), error);
469   offset += 1;
470
471   proto_tree_add_text(tree, tvb, offset, 2,
472                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
473 }
474
475 static void
476 dissect_out_req(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
477                 proto_tree *tree)
478 {
479   guint32               bearer;
480   guint32               frame;
481   guint8                phone[PHONELEN+1];
482   guint8                subaddr[SUBADDRLEN+1];
483
484   proto_tree_add_text(tree, tvb, offset, 2,
485                       "Call ID: %u", tvb_get_ntohs(tvb, offset));
486   offset += 2;
487
488   proto_tree_add_text(tree, tvb, offset, 2,
489                       "Call Serial Number: %u", tvb_get_ntohs(tvb, offset));
490   offset += 2;
491
492   proto_tree_add_text(tree, tvb, offset, 4,
493                       "Minimum BPS: %u", tvb_get_ntohl(tvb, offset));
494   offset += 4;
495
496   proto_tree_add_text(tree, tvb, offset, 4,
497                       "Maximum BPS: %u", tvb_get_ntohl(tvb, offset));
498   offset += 4;
499
500   bearer = tvb_get_ntohl(tvb, offset);
501   proto_tree_add_text(tree, tvb, offset, 4,
502                       "Bearer capabilities: %s (%u)", bearertype2str(bearer), bearer);
503   offset += 4;
504
505   frame = tvb_get_ntohl(tvb, offset);
506   proto_tree_add_text(tree, tvb, offset, 4,
507                       "Framing capabilities: %s (%u)", frametype2str(frame), frame);
508   offset += 4;
509
510   proto_tree_add_text(tree, tvb, offset, 2,
511                       "Receive window size: %u", tvb_get_ntohs(tvb, offset));
512   offset += 2;
513
514   proto_tree_add_text(tree, tvb, offset, 2,
515                       "Processing delay: %u", tvb_get_ntohs(tvb, offset));
516   offset += 2;
517
518   proto_tree_add_text(tree, tvb, offset, 2,
519                       "Phone number length: %u", tvb_get_ntohs(tvb, offset));
520   offset += 2;
521
522   proto_tree_add_text(tree, tvb, offset, 2,
523                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
524   offset += 2;
525
526   tvb_get_nstringz0(tvb, offset, PHONELEN, phone);
527   proto_tree_add_text(tree, tvb, offset, PHONELEN,
528                       "Phone number: %s", phone);
529   offset += PHONELEN;
530
531   tvb_get_nstringz0(tvb, offset, SUBADDRLEN, subaddr);
532   proto_tree_add_text(tree, tvb, offset, SUBADDRLEN,
533                       "Subaddress: %s", subaddr);
534 }
535
536 static void
537 dissect_out_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
538                   proto_tree *tree)
539 {
540   guint8                result;
541   guint8                error;
542
543   proto_tree_add_text(tree, tvb, offset, 2,
544                       "Call ID: %u", tvb_get_ntohs(tvb, offset));
545   offset += 2;
546
547   proto_tree_add_text(tree, tvb, offset, 2,
548                       "Peer's call ID: %u", tvb_get_ntohs(tvb, offset));
549   offset += 2;
550
551   result = tvb_get_guint8(tvb, offset);
552   proto_tree_add_text(tree, tvb, offset, 1,
553                       "Result: %s (%u)", outresulttype2str(result), result);
554   offset += 1;
555
556   error = tvb_get_guint8(tvb, offset);
557   proto_tree_add_text(tree, tvb, offset, 1,
558                       "Error: %s (%u)", errortype2str(error), error);
559   offset += 1;
560
561   proto_tree_add_text(tree, tvb, offset, 2,
562                       "Cause code: %u", tvb_get_ntohs(tvb, offset));
563   offset += 2;
564
565   proto_tree_add_text(tree, tvb, offset, 4,
566                       "Connect speed: %u", tvb_get_ntohl(tvb, offset));
567   offset += 4;
568
569   proto_tree_add_text(tree, tvb, offset, 2,
570                       "Receive window size: %u", tvb_get_ntohs(tvb, offset));
571   offset += 2;
572
573   proto_tree_add_text(tree, tvb, offset, 2,
574                       "Processing delay: %u", tvb_get_ntohs(tvb, offset));
575   offset += 2;
576
577   proto_tree_add_text(tree, tvb, offset, 4,
578                       "Physical channel ID: %u", tvb_get_ntohl(tvb, offset));
579 }
580
581 static void
582 dissect_in_req(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
583                proto_tree *tree)
584 {
585   guint32               bearer;
586   guint8                dialed[PHONELEN+1];
587   guint8                dialing[PHONELEN+1];
588   guint8                subaddr[SUBADDRLEN+1];
589
590   proto_tree_add_text(tree, tvb, offset, 2,
591                       "Call ID: %u", tvb_get_ntohs(tvb, offset));
592   offset += 2;
593
594   proto_tree_add_text(tree, tvb, offset, 2,
595                       "Call serial number: %u", tvb_get_ntohs(tvb, offset));
596   offset += 2;
597
598   bearer = tvb_get_ntohl(tvb, offset);
599   proto_tree_add_text(tree, tvb, offset, 4,
600                       "Bearer capabilities: %s (%u)", bearertype2str(bearer), bearer);
601   offset += 4;
602
603   proto_tree_add_text(tree, tvb, offset, 4,
604                       "Physical channel ID: %u", tvb_get_ntohl(tvb, offset));
605   offset += 4;
606
607   proto_tree_add_text(tree, tvb, offset, 2,
608                       "Dialed number length: %u", tvb_get_ntohs(tvb, offset));
609   offset += 2;
610
611   proto_tree_add_text(tree, tvb, offset, 2,
612                       "Dialing number length: %u", tvb_get_ntohs(tvb, offset));
613   offset += 2;
614
615   tvb_get_nstringz0(tvb, offset, PHONELEN, dialed);
616   proto_tree_add_text(tree, tvb, offset, PHONELEN,
617                       "Dialed number: %s", dialed);
618   offset += PHONELEN;
619
620   tvb_get_nstringz0(tvb, offset, PHONELEN, dialing);
621   proto_tree_add_text(tree, tvb, offset, PHONELEN,
622                       "Dialing number: %s", dialing);
623   offset += PHONELEN;
624
625   tvb_get_nstringz0(tvb, offset, SUBADDRLEN, subaddr);
626   proto_tree_add_text(tree, tvb, offset, SUBADDRLEN,
627                       "Subaddress: %s", subaddr);
628 }
629
630 static void
631 dissect_in_reply(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
632                  proto_tree *tree)
633 {
634   guint8                result;
635   guint8                error;
636
637   proto_tree_add_text(tree, tvb, offset, 2,
638                       "Call ID: %u", tvb_get_ntohs(tvb, offset));
639   offset += 2;
640
641   proto_tree_add_text(tree, tvb, offset, 2,
642                       "Peer's call ID: %u", tvb_get_ntohs(tvb, offset));
643   offset += 2;
644
645   result = tvb_get_guint8(tvb, offset);
646   proto_tree_add_text(tree, tvb, offset, 1,
647                       "Result: %s (%u)", inresulttype2str(result), result);
648   offset += 1;
649
650   error = tvb_get_guint8(tvb, offset);
651   proto_tree_add_text(tree, tvb, offset, 1,
652                       "Error: %s (%u)", errortype2str(error), error);
653   offset += 1;
654
655   proto_tree_add_text(tree, tvb, offset, 2,
656                       "Receive window size: %u", tvb_get_ntohs(tvb, offset));
657   offset += 2;
658
659   proto_tree_add_text(tree, tvb, offset, 2,
660                       "Processing delay: %u", tvb_get_ntohs(tvb, offset));
661   offset += 2;
662
663   proto_tree_add_text(tree, tvb, offset, 2,
664                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
665 }
666
667 static void
668 dissect_in_connected(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
669                      proto_tree *tree)
670 {
671   guint32               frame;
672
673   proto_tree_add_text(tree, tvb, offset, 2,
674                       "Peer's call ID: %u", tvb_get_ntohs(tvb, offset));
675   offset += 2;
676
677   proto_tree_add_text(tree, tvb, offset, 2,
678                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
679   offset += 2;
680
681   proto_tree_add_text(tree, tvb, offset, 4,
682                       "Connect speed: %u", tvb_get_ntohl(tvb, offset));
683   offset += 4;
684
685   proto_tree_add_text(tree, tvb, offset, 2,
686                       "Receive window size: %u", tvb_get_ntohs(tvb, offset));
687   offset += 2;
688
689   proto_tree_add_text(tree, tvb, offset, 2,
690                       "Processing delay: %u", tvb_get_ntohs(tvb, offset));
691   offset += 2;
692
693   frame = tvb_get_ntohl(tvb, offset);
694   proto_tree_add_text(tree, tvb, offset, 4,
695                       "Framing capabilities: %s (%u)", frametype2str(frame), frame);
696 }
697
698 static void
699 dissect_clear_req(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
700                   proto_tree *tree)
701 {
702   proto_tree_add_text(tree, tvb, offset, 2,
703                       "Call ID: %u", tvb_get_ntohs(tvb, offset));
704   offset += 2;
705
706   proto_tree_add_text(tree, tvb, offset, 2,
707                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
708 }
709
710 static void
711 dissect_disc_notify(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
712                     proto_tree *tree)
713 {
714   guint8                result;
715   guint8                error;
716   guint8                stats[STATSLEN+1];
717
718   proto_tree_add_text(tree, tvb, offset, 2,
719                       "Call ID: %u", tvb_get_ntohs(tvb, offset));
720   offset += 2;
721
722   result = tvb_get_guint8(tvb, offset);
723   proto_tree_add_text(tree, tvb, offset, 1,
724                       "Result: %s (%u)", discresulttype2str(result), result);
725   offset += 1;
726
727   error = tvb_get_guint8(tvb, offset);
728   proto_tree_add_text(tree, tvb, offset, 1,
729                       "Error: %s (%u)", errortype2str(error), error);
730   offset += 1;
731
732   proto_tree_add_text(tree, tvb, offset, 2,
733                       "Cause code: %u", tvb_get_ntohs(tvb, offset));
734   offset += 2;
735
736   proto_tree_add_text(tree, tvb, offset, 2,
737                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
738   offset += 2;
739
740   tvb_get_nstringz0(tvb, offset, STATSLEN, stats);
741   proto_tree_add_text(tree, tvb, offset, STATSLEN,
742                       "Call statistics: %s", stats);
743 }
744
745 static void
746 dissect_error_notify(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
747                      proto_tree *tree)
748 {
749   proto_tree_add_text(tree, tvb, offset, 2,
750                       "Peer's call ID: %u", tvb_get_ntohs(tvb, offset));
751   offset += 2;
752
753   proto_tree_add_text(tree, tvb, offset, 2,
754                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
755   offset += 2;
756
757   proto_tree_add_text(tree, tvb, offset, 4,
758                       "CRC errors: %u", tvb_get_ntohl(tvb, offset));
759   offset += 4;
760
761   proto_tree_add_text(tree, tvb, offset, 4,
762                       "Framing errors: %u", tvb_get_ntohl(tvb, offset));
763   offset += 4;
764
765   proto_tree_add_text(tree, tvb, offset, 4,
766                       "Hardware overruns: %u", tvb_get_ntohl(tvb, offset));
767   offset += 4;
768
769   proto_tree_add_text(tree, tvb, offset, 4,
770                       "Buffer overruns: %u", tvb_get_ntohl(tvb, offset));
771   offset += 4;
772
773   proto_tree_add_text(tree, tvb, offset, 4,
774                       "Time-out errors: %u", tvb_get_ntohl(tvb, offset));
775   offset += 4;
776
777   proto_tree_add_text(tree, tvb, offset, 4,
778                       "Alignment errors: %u", tvb_get_ntohl(tvb, offset));
779 }
780
781 static void
782 dissect_set_link(tvbuff_t *tvb, int offset, packet_info *pinfo _U_,
783                  proto_tree *tree)
784 {
785   proto_tree_add_text(tree, tvb, offset, 2,
786                       "Peer's call ID: %u", tvb_get_ntohs(tvb, offset));
787   offset += 2;
788
789   proto_tree_add_text(tree, tvb, offset, 2,
790                       "Reserved: %u", tvb_get_ntohs(tvb, offset));
791   offset += 2;
792
793   proto_tree_add_text(tree, tvb, offset, 4,
794                       "Send ACCM: %#08x", tvb_get_ntohl(tvb, offset));
795   offset += 4;
796
797   proto_tree_add_text(tree, tvb, offset, 4,
798                       "Recv ACCM: %#08x", tvb_get_ntohl(tvb, offset));
799 }
800
801 void
802 proto_register_pptp(void)
803 {
804   static gint *ett[] = {
805     &ett_pptp,
806   };
807
808   static hf_register_info hf[] = {
809     { &hf_pptp_message_type,
810       { "Message type",                 "pptp.type",
811         FT_UINT16,      BASE_DEC,       VALS(msgtype_vals),     0x0,
812         "PPTP message type", HFILL }}
813   };
814
815   proto_pptp = proto_register_protocol("Point-to-Point Tunnelling Protocol",
816                                        "PPTP", "pptp");
817   proto_register_field_array(proto_pptp, hf, array_length(hf));
818   proto_register_subtree_array(ett, array_length(ett));
819 }
820
821 void
822 proto_reg_handoff_pptp(void)
823 {
824   dissector_handle_t pptp_handle;
825
826   pptp_handle = create_dissector_handle(dissect_pptp, proto_pptp);
827   dissector_add("tcp.port", TCP_PORT_PPTP, pptp_handle);
828   data_handle = find_dissector("data");
829 }