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