2dc26cb3c41dde941df583ac35ab37effeea9c5b
[obnox/wireshark/wip.git] / plugins / opsi / packet-opsi.c
1 /* packet-opsi.c
2  * Routines for OPSI protocol dissection
3  * Copyright 2004, Laurent Rabret (France Telecom R&D) <laurent.rabret@i.hate.spams.org>
4  *
5  * $Id$
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 "plugins/plugin_api.h"
31 #include "moduleinfo.h"
32 #include <gmodule.h>
33 #include "plugins/plugin_api_defs.h"
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include <glib.h>
40
41 #ifdef NEED_SNPRINTF_H
42 # include "snprintf.h"
43 #endif
44
45 #include <epan/packet.h>
46 #include <epan/dissectors/packet-tcp.h>
47 #include "prefs.h"
48
49 #include "packet-opsi.h"
50
51 /* Plugin exported constants */
52 #ifndef ENABLE_STATIC
53 G_MODULE_EXPORT const gchar version[] = VERSION;
54 #endif 
55
56
57 /* Initialize the protocol and registered fields */
58 static int proto_opsi                   = -1;
59 static int hf_opsi_major_version        = -1;
60 static int hf_opsi_minor_version        = -1;
61 static int hf_opsi_opcode               = -1;
62 static int hf_opsi_hook_id              = -1;
63 static int hf_opsi_length               = -1;
64 static int hf_opsi_session_id           = -1;
65 static int hf_user_name_att             = -1;
66 static int hf_password_att              = -1;
67 static int hf_chap_password_att         = -1;
68 static int hf_nas_ip_add_att            = -1;
69 static int hf_nas_port_att              = -1;
70 static int hf_service_type_att          = -1;
71 static int hf_framed_protocol_att       = -1;
72 static int hf_framed_address_att        = -1;
73 static int hf_framed_netmask_att        = -1;
74 static int hf_framed_routing_att        = -1;
75 static int hf_framed_filter_att         = -1;
76 static int hf_framed_mtu_att            = -1;
77 static int hf_framed_compression_att    = -1;
78 static int hf_called_station_att        = -1;
79 static int hf_calling_station_att       = -1;
80 static int hf_nas_identifier_att        = -1;
81 static int hf_accounting_att            = -1;
82 static int hf_acct_session_id_att       = -1;
83 static int hf_chap_challenge_att        = -1;
84 static int hf_nas_port_type_att         = -1;
85 static int hf_designation_num_att       = -1;
86 static int hf_nas_port_id_att           = -1;
87 static int hf_smc_aaa_id_att            = -1;
88 static int hf_smc_vpn_id_att            = -1;
89 static int hf_smc_vpn_name_att          = -1;
90 static int hf_smc_ran_id_att            = -1;
91 static int hf_smc_ran_ip_att            = -1;
92 static int hf_smc_ran_name_att          = -1;
93 static int hf_smc_pop_id_att            = -1;
94 static int hf_smc_pop_name_att          = -1;
95 static int hf_smc_id_att                = -1;
96 static int hf_smc_receive_time_att      = -1;
97 static int hf_smc_stat_time_att         = -1;
98
99 /* Initialize the subtree pointers */
100 static gint ett_opsi                    = -1;
101 static gint ett_opsi_user_name          = -1;
102 static gint ett_opsi_user_password      = -1;
103 static gint ett_opsi_chap_password      = -1;
104 static gint ett_opsi_nas_ip_address     = -1;
105 static gint ett_opsi_nas_port           = -1;
106 static gint ett_opsi_service_type       = -1;
107 static gint ett_opsi_framed_protocol    = -1;
108 static gint ett_opsi_framed_address     = -1;
109 static gint ett_opsi_framed_netmask     = -1;
110 static gint ett_opsi_framed_routing     = -1;
111 static gint ett_opsi_framed_filter      = -1;
112 static gint ett_opsi_framed_mtu         = -1;
113 static gint ett_opsi_framed_compression = -1;
114 static gint ett_opsi_called_station_id  = -1;
115 static gint ett_opsi_calling_station_id = -1;
116 static gint ett_opsi_nas_identifier     = -1;
117 static gint ett_opsi_accounting         = -1;
118 static gint ett_opsi_acct_session_id    = -1;
119 static gint ett_opsi_chap_challenge     = -1;
120 static gint ett_opsi_nas_port_type      = -1;
121 static gint ett_opsi_designation_number = -1;
122 static gint ett_opsi_nas_port_id        = -1;
123 static gint ett_opsi_smc_aaa_id         = -1;
124 static gint ett_opsi_smc_vpn_id         = -1;
125 static gint ett_opsi_smc_vpn_name       = -1;
126 static gint ett_opsi_smc_ran_id         = -1;
127 static gint ett_opsi_smc_ran_ip         = -1;
128 static gint ett_opsi_smc_ran_name       = -1;
129 static gint ett_opsi_smc_pop_id         = -1;
130 static gint ett_opsi_smc_pop_name       = -1;
131 static gint ett_opsi_smc_id             = -1;
132 static gint ett_opsi_smc_receive_time   = -1;
133 static gint ett_opsi_smc_stat_time      = -1;
134
135
136 /* Code mapping */
137 static const value_string opsi_opcode[] = {
138                 { DISCOVER_REQUEST,     "Discover Request" },
139                 { DISCOVER_RESPONSE,    "Discover Response" },
140                 { SERVICE_REQUEST,      "Service Request" },
141                 { SERVICE_ACCEPT,       "Service Accept" }, 
142                 { SERVICE_REJECT,       "Service Reject" },
143                 { TERMINATE_REQUEST,    "Terminate Request" },
144                 { 0,                    NULL }
145         };
146         
147 static const value_string opsi_service_type_code[] = {  
148                 { 1, "Login" },
149                 { 2, "Framed" },
150                 { 3, "Callback Login" },
151                 { 4, "Callback Framed" },
152                 { 5, "Outbound" },
153                 { 6, "Administrative" },
154                 { 7, "NAS Prompt" },
155                 { 8, "Authenticate Only" },
156                 { 9, "Callback NAS Prompt" },
157                 { 0,                    NULL }
158         };
159
160 static const value_string opsi_framed_protocol_code[] = {       
161                 { 1,    "PPP" },
162                 { 2,    "SLIP" },
163                 { 3,    "AppleTalk Remote Access Protocol (ARAP)" },
164                 { 4,    "Gandalf proprietary SingleLink/MultiLink protocol" },
165                 { 5,    "Xylogics proprietary IPX/SLIP" },
166                 { 255,  "Ascend ARA" },
167                 { 256,  "MPP" },
168                 { 257,  "EURAW" },
169                 { 258,  "EUUI" },
170                 { 259,  "X25" },
171                 { 260,  "COMB" },
172                 { 261,  "FR" },
173                 { 262,  "MP" },
174                 { 263,  "FR-CIR"},
175                 { 0,                    NULL }
176         };
177         
178 static const value_string opsi_framed_routing_code[] = {
179                 { 0,    "None" },
180                 { 1,    "Broadcast" },
181                 { 2,    "Listen" },
182                 { 3,    "Broadcast-Listen" },
183                 { 4,    "Broadcast V2" },
184                 { 5,    "Listen V2" },
185                 { 6,    "Broadcast-Listen V2" },
186                 { 0,    NULL },
187         };
188
189 static const value_string opsi_framed_compression_code[] = {
190                 { 0,    "None" },
191                 { 1,    "Van Jacobsen TCP/IP" },
192                 { 2,    "IPX header compression" },
193                 { 0,    NULL }
194         };
195
196 static const value_string opsi_nas_port_type_code[] = { 
197                 { 0, "Async" },
198                 { 1, "Sync" },
199                 { 2, "ISDN Sync" },
200                 { 3, "ISDN Async V.120" },
201                 { 4, "ISDN Async V.110" },
202                 { 5, "Virtual" },
203                 { 6, "PIAFS" },
204                 { 7, "HDLC Clear Channel" },
205                 { 8, "X.25" },
206                 { 9, "X.75" },
207                 { 10, "G.3 Fax" },
208                 { 11, "SDSL - Symmetric DSL" },
209                 { 12, "ADSL-CAP - Asymmetric DSL, Carrierless Amplitude Phase Modulation" },
210                 { 13, "ADSL-DMT - Asymmetric DSL, Discrete Multi-Tone" },
211                 { 14, "IDSL - ISDN Digital Subscriber Line" },
212                 { 15, "Ethernet" },
213                 { 16, "xDSL - Digital Subscriber Line of unknown type" },
214                 { 17, "Cable" },
215                 { 18, "Wireless - Other" },
216                 { 19, "Wireless - IEEE 802.11" },
217                 { 201,"Voice over IP" },
218                 { 0,                    NULL }
219         };
220
221         
222 /* Structure used to decode OPSI frame attributes       */
223 /* CAUTION : it is compulsory to sort this array        */
224 /* (first argument of the opsi_attribute_handle_t)      */
225 /* in ascending order                                   */
226 /*                                                      */
227 static opsi_attribute_handle_t opsi_attributes[] = {
228         { USER_NAME_ATTRIBUTE,          /* 1 */
229         "User name attribute", &ett_opsi_user_name, &hf_user_name_att, decode_string_attribute },
230         { USER_PASSWD_ATTRIBUTE,        /* 2 */
231         "User password attribute" , &ett_opsi_user_password, &hf_password_att, decode_string_attribute },
232         { CHAP_PASSWD_ATTRIBUTE,        /* 3 */
233         "CHAP password attribute", &ett_opsi_chap_password, &hf_chap_password_att, decode_string_attribute },
234         { NAS_IP_ADDRESS_ATTRIBUTE,     /* 4 */
235         "NAS IP address attribute", &ett_opsi_nas_ip_address, &hf_nas_ip_add_att, decode_ipv4_attribute },
236         {NAS_PORT_ATTRIBUTE,            /* 5 */
237         "NAS port attribute", &ett_opsi_nas_port, &hf_nas_port_att, decode_longint_attribute },
238         {SERVICE_TYPE_ATTRIBUTE,        /* 6 */
239         "Service type attribute", &ett_opsi_service_type, &hf_service_type_att, decode_value_string_attribute },
240         {FRAMED_PROTOCOL_ATTRIBUTE,     /* 7 */
241         "Framed protocol attribute", &ett_opsi_framed_protocol, &hf_framed_protocol_att, decode_value_string_attribute },
242         {FRAMED_ADDRESS_ATTRIBUTE,      /* 8 */
243         "Framed address attribute", &ett_opsi_framed_address, &hf_framed_address_att, decode_ipv4_attribute },
244         {FRAMED_NETMASK_ATTRIBUTE,      /* 9 */
245         "Framed netmask attribute", &ett_opsi_framed_netmask, &hf_framed_netmask_att, decode_ipv4_attribute },
246         {FRAMED_ROUTING_ATTRIBUTE,      /* 10 */
247         "Framed routing attribute", &ett_opsi_framed_routing, &hf_framed_routing_att, decode_value_string_attribute },
248         {FRAMED_FILTER_ATTRIBUTE,       /* 11 */
249         "Framed filter attribute", &ett_opsi_framed_filter, &hf_framed_filter_att, decode_string_attribute },
250         {FRAMED_MTU_ATTRIBUTE,          /* 12 */
251         "Framed MTU attribute", &ett_opsi_framed_mtu, &hf_framed_mtu_att, decode_longint_attribute },
252         {FRAMED_COMPRESSION_ATTRIBUTE,  /* 13 */
253         "Framed compression attribute", &ett_opsi_framed_compression, &hf_framed_compression_att, decode_value_string_attribute },
254         {CALLED_STATION_ID_ATTRIBUTE,   /* 30 */
255         "Called station ID attribute", &ett_opsi_called_station_id, &hf_called_station_att, decode_string_attribute },
256         {CALLING_STATION_ID_ATTRIBUTE,  /* 31 */
257         "Calling station ID attribute", &ett_opsi_calling_station_id, &hf_calling_station_att, decode_string_attribute },
258         {NAS_IDENTIFIER,                /* 32 */
259         "NAS Identifier attribute", &ett_opsi_nas_identifier, &hf_nas_identifier_att, decode_string_attribute },
260         {ACCOUNTING_40_ATTRIBUTE,       /* 40 */
261         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
262         {ACCOUNTING_41_ATTRIBUTE,       /* 41 */
263         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
264         {ACCOUNTING_42_ATTRIBUTE,       /* 42 */
265         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
266         {ACCOUNTING_43_ATTRIBUTE,       /* 43 */
267         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
268         {ACCOUNTING_SESSION_ID_ATTRIBUTE,       /* 44 */ 
269         "Accounting session ID attribute", &ett_opsi_acct_session_id, &hf_acct_session_id_att, decode_string_attribute },
270         {ACCOUNTING_45_ATTRIBUTE,       /* 45 */
271         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
272         {ACCOUNTING_46_ATTRIBUTE,       /* 46 */
273         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
274         {ACCOUNTING_47_ATTRIBUTE,       /* 47 */
275         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
276         {ACCOUNTING_48_ATTRIBUTE,       /* 48 */
277         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
278         {ACCOUNTING_49_ATTRIBUTE,       /* 49 */
279         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
280         {ACCOUNTING_50_ATTRIBUTE,       /* 50 */
281         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
282         {ACCOUNTING_51_ATTRIBUTE,       /* 51 */
283         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
284         {ACCOUNTING_52_ATTRIBUTE,       /* 52 */
285         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
286         {ACCOUNTING_53_ATTRIBUTE,       /* 53 */
287         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
288         {ACCOUNTING_54_ATTRIBUTE,       /* 54 */
289         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
290         {ACCOUNTING_55_ATTRIBUTE,       /* 55 */
291         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
292         {ACCOUNTING_56_ATTRIBUTE,       /* 56 */
293         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
294         {ACCOUNTING_57_ATTRIBUTE,       /* 57 */
295         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
296         {ACCOUNTING_58_ATTRIBUTE,       /* 58 */
297         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
298         {ACCOUNTING_59_ATTRIBUTE,       /* 59 */
299         "Accounting attribute", &ett_opsi_accounting, &hf_accounting_att, decode_string_attribute },
300         {CHAP_CHALLENGE_ATTRIBUTE,      /* 60 */
301         "CHAP challenge",       &ett_opsi_chap_challenge, &hf_chap_challenge_att, decode_string_attribute },
302         {NAS_PORT_TYPE_ATTRIBUTE,       /* 61 */
303         "NAS port type attribute", &ett_opsi_nas_port_type, &hf_nas_port_type_att, decode_value_string_attribute },
304         {DESIGNATION_NUMBER_ATTRIBUTE,  /* 77 */
305         "Designation number attribute", &ett_opsi_designation_number, &hf_designation_num_att, decode_string_attribute },
306         {NAS_PORT_ID_ATTRIBUTE,         /* 87 */
307         "NAS port ID attribute", &ett_opsi_nas_port_id, &hf_nas_port_id_att, decode_string_attribute },
308         {SMC_AAAID_ATTRIBUTE,           /* 651 */
309         "SMC AAA ID attribute", &ett_opsi_smc_aaa_id, &hf_smc_aaa_id_att, decode_longint_attribute },
310         {SMC_VPNID_ATTRIBUTE,           /* 652 */
311         "SMC VPN ID attribute", &ett_opsi_smc_vpn_id, &hf_smc_vpn_id_att, decode_longint_attribute },
312         {SMC_VPNNAME_ATTRIBUTE,         /* 653 */
313         "SMC VPN name attribute", &ett_opsi_smc_vpn_name, &hf_smc_vpn_name_att, decode_string_attribute },
314         {SMC_RANID_ATTRIBUTE,           /* 654 */
315         "SMC RAN ID attribute", &ett_opsi_smc_ran_id, &hf_smc_ran_id_att, decode_longint_attribute },
316         {SMC_RANIP_ATTRIBUTE,           /* 655 */
317         "SMC RAN IP attribute", &ett_opsi_smc_ran_ip, &hf_smc_ran_ip_att, decode_ipv4_attribute },
318         {SMC_RANNAME_ATTRIBUTE,         /* 656 */
319         "SMC RAN name attribute", &ett_opsi_smc_ran_name, &hf_smc_ran_name_att, decode_string_attribute },
320         {SMC_POPID_ATTRIBUTE,           /* 657 */
321         "SMC POP ID attribute", &ett_opsi_smc_pop_id, &hf_smc_pop_id_att, decode_longint_attribute },
322         {SMC_POPNAME_ATTRIBUTE,         /* 658 */
323         "SMC POP name attribute", &ett_opsi_smc_pop_name, &hf_smc_pop_name_att, decode_string_attribute },
324         {SMC_SMCID_ATTRIBUTE,           /* 659 */
325         "SMC ID attribute", &ett_opsi_smc_id, &hf_smc_id_att, decode_longint_attribute },
326         {SMC_RECEIVE_TIME_ATTRIBUTE,    /* 660 */
327         "SMC receive time attribute", &ett_opsi_smc_receive_time, &hf_smc_receive_time_att, decode_time_attribute },
328         {SMC_STAT_TIME_ATTRIBUTE,       /* 661 */
329         "SMC stat time attribute", &ett_opsi_smc_stat_time, &hf_smc_stat_time_att, decode_longint_attribute },
330 };
331 #define OPSI_ATTRIBUTES_COUNT (sizeof(opsi_attributes)/sizeof(opsi_attribute_handle_t))
332
333 /* Desegmentation of OPSI (over TCP) */
334 static gboolean opsi_desegment = TRUE;
335 /* To check if we must create or update the information column  */
336 static gboolean opsi_first;
337
338 void decode_string_attribute(tvbuff_t *tvb, proto_tree *tree, int* hfValue, int offset, int length)
339 {
340         guint8* pbuffer;
341         if (length < 4) {
342                 proto_tree_add_text(tree, tvb, offset, length, "Too short attribute!");
343                 return;
344         }
345         
346         pbuffer=tvb_get_string(tvb, offset+4, length-4);
347         proto_tree_add_string(tree, *hfValue, tvb, offset+4, length-4, pbuffer);
348         g_free(pbuffer);        
349 }
350
351
352 void decode_ipv4_attribute(tvbuff_t *tvb, proto_tree *tree, int* hfValue, int offset, int length)
353 {
354         guint32 ip_address;
355         if (length < 8) {
356                 proto_tree_add_text(tree, tvb, offset, length, "Too short attribute!");
357                 return;
358         }
359         tvb_memcpy(tvb, (guint8 *)&ip_address, offset+4, 4);
360         proto_tree_add_ipv4(tree, *hfValue, tvb, offset+4, 4, ip_address);
361 }
362
363 void decode_longint_attribute(tvbuff_t *tvb, proto_tree *tree, int* hfValue, int offset, int length)
364 {
365         if (length < 8) {
366                 proto_tree_add_text(tree, tvb, offset, length, "Too short attribute!");
367                 return;
368         }
369         proto_tree_add_uint(tree, *hfValue, tvb, offset+4, 4, tvb_get_ntohl(tvb, offset+4));
370 }
371
372 void decode_value_string_attribute(tvbuff_t *tvb, proto_tree *tree, int* hfValue, int offset, int length)
373 {
374         if (length < 8) {
375                 proto_tree_add_text(tree, tvb, offset, length, "Too short attribute!");
376                 return;
377         }
378         proto_tree_add_item(tree, *hfValue, tvb, offset+4, 4, FALSE);
379 }
380
381 void decode_time_attribute(tvbuff_t *tvb, proto_tree *tree, int* hfValue, int offset, int length)
382 {
383         nstime_t ns;
384         
385         if (length < 8) {
386                 proto_tree_add_text(tree, tvb, offset, length, "Too short attribute!");
387                 return;
388         }
389       ns.secs  = tvb_get_ntohl(tvb, offset+4);
390       ns.nsecs = 0;
391       proto_tree_add_time(tree, *hfValue, tvb, offset+4, 4, &ns);
392 }
393
394 /****************************************************************************/
395 /********** End of attribute decoding ***************************************/
396 /****************************************************************************/
397
398 /* To find the correct size of the PDU. Needed by the desegmentation feature*/
399 static guint get_opsi_pdu_len(tvbuff_t *tvb, int offset)
400 {
401   /*
402    * Get the length of the OPSI packet.
403    * We are guaranteed there're enough chars in tvb in order to
404    * extract the length value. No exception thrown !!
405    */
406   return tvb_get_ntohs(tvb, offset + 4);
407 }
408
409 static int get_opsi_attribute_index(int min, int max, int attribute_type)
410 {
411         int middle, at;
412         
413         middle = (min+max)/2;
414         at = opsi_attributes[middle].attribute_type;
415         if (at == attribute_type) return middle;
416         if (attribute_type > at) {
417                 return (middle == max) ? -1 : get_opsi_attribute_index(middle+1, max, attribute_type);
418         }
419         return (middle == min) ? -1 : get_opsi_attribute_index(min, middle-1, attribute_type);
420 }
421
422
423 static void 
424 dissect_attributes(tvbuff_t *tvb, proto_tree *opsi_tree, int offset, int length)
425 {
426         int i;
427         int attribute_type;
428         int attribute_length;
429         proto_item *ti;
430         proto_tree *ntree = NULL;
431         
432         while (length >= 4) {
433                 attribute_type          = tvb_get_ntohs(tvb, offset);
434                 attribute_length        = tvb_get_ntohs(tvb, offset+2);
435                 if (attribute_length > length) break;
436                 /* We perform a standard log(n) lookup */
437                 i = get_opsi_attribute_index(0, OPSI_ATTRIBUTES_COUNT-1, attribute_type);
438                 if (i == -1) {
439                         proto_tree_add_text(opsi_tree, tvb, offset, attribute_length, "Unknown attribute (%d)", attribute_type);                        
440                 }
441                 else {
442                         ti = proto_tree_add_text(opsi_tree, tvb, offset, attribute_length, "%s (%d)", opsi_attributes[i].tree_text, attribute_type);
443                         ntree = proto_item_add_subtree(ti, *opsi_attributes[i].tree_id);
444                         proto_tree_add_text(ntree, tvb, offset+2, 2, "Length (%d)", attribute_length);
445                         opsi_attributes[i].dissect(tvb, ntree, opsi_attributes[i].hf_type_attribute, offset, attribute_length);
446                 }
447                 offset += attribute_length;
448                 length -= attribute_length;
449         }
450         if (length) {
451                 proto_tree_add_text(opsi_tree, tvb, offset, -1, "Short frame");
452         }
453 }
454
455 static void
456 dissect_opsi_pdu(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
457 {
458         proto_item *ti;
459         proto_tree *opsi_tree;
460         
461         if (opsi_first == TRUE) {
462                 opsi_first = FALSE;
463                 
464                 if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
465                         col_set_str(pinfo->cinfo, COL_PROTOCOL, "OPSI");
466     
467                 if (check_col(pinfo->cinfo, COL_INFO)) {
468                         col_clear(pinfo->cinfo, COL_INFO);
469                         if (tvb_length(tvb) < CODE_OFFSET+1) {
470                                 col_set_str(pinfo->cinfo, COL_INFO, "Open Policy Service Interface");
471                         }
472                         else {
473                                 col_add_fstr(pinfo->cinfo, COL_INFO, "Open Policy Service Interface, %s",
474                                         val_to_str(tvb_get_guint8(tvb, CODE_OFFSET), opsi_opcode,  
475                                      "<Unknown opcode %d>"));
476                         }
477                 }
478         }
479         else if (check_col(pinfo->cinfo, COL_INFO) && (tvb_length(tvb) > CODE_OFFSET)) {
480                 col_append_fstr(pinfo->cinfo, COL_INFO, ", %s",
481                           val_to_str(tvb_get_guint8(tvb, CODE_OFFSET), opsi_opcode, 
482                                      "<Unknown opcode %d>"));
483         }
484
485         if (tree) {
486                 ti = proto_tree_add_item(tree, proto_opsi, tvb, 0, -1, FALSE);
487                 opsi_tree = proto_item_add_subtree(ti, ett_opsi);
488                 if (tvb_length(tvb) < 8 ) {
489                         proto_tree_add_text(opsi_tree, tvb, 0, -1, "Too short OPSI packet!");
490                         return;
491                 }
492                 
493                 proto_tree_add_item(opsi_tree, hf_opsi_major_version, tvb, MAJOR_VERSION_OFFSET, 1, FALSE);
494                 proto_tree_add_item(opsi_tree, hf_opsi_minor_version, tvb, MINOR_VERSION_OFFSET, 1, FALSE);
495                 proto_tree_add_item(opsi_tree, hf_opsi_opcode, tvb, CODE_OFFSET, 1, FALSE);
496                 proto_tree_add_item(opsi_tree, hf_opsi_hook_id, tvb, HOOK_ID_OFFSET, 1, FALSE);
497                 proto_tree_add_item(opsi_tree, hf_opsi_length, tvb, PACKET_LENGTH_OFFSET, 2, FALSE);
498                 proto_tree_add_item(opsi_tree, hf_opsi_session_id, tvb, SESSION_OFFSET, 2, FALSE);
499                 
500                 dissect_attributes(tvb, opsi_tree, HEADER_LENGTH, MIN(((int)tvb_length(tvb)-HEADER_LENGTH), (tvb_get_ntohs(tvb, PACKET_LENGTH_OFFSET)-HEADER_LENGTH)));
501         }
502 }
503
504
505 static void
506 dissect_opsi(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
507 {
508         opsi_first = TRUE;
509         /* we need at least 6 bytes to get the payload size ! */
510         tcp_dissect_pdus(tvb, pinfo, tree, opsi_desegment, 6, get_opsi_pdu_len,
511                 dissect_opsi_pdu);
512 }
513
514
515 void
516 proto_register_opsi(void)
517 {                 
518
519 /* Setup list of header fields  See Section 1.6.1 for details*/
520         static hf_register_info hf[] = {
521                 { &hf_opsi_major_version,
522                         { "Major version",           "opsi.major",
523                         FT_UINT8, BASE_DEC, NULL, 0x0,          
524                         "", HFILL }
525                 },
526                 { &hf_opsi_minor_version,
527                         { "Minor version",           "opsi.minor",
528                         FT_UINT8, BASE_DEC, NULL, 0x0,          
529                         "", HFILL }
530                 },
531                 { &hf_opsi_opcode,
532                         { "Operation code",             "opsi.opcode",
533                         FT_UINT8, BASE_DEC, VALS(opsi_opcode), 0x0,
534                         "", HFILL }
535                 },
536                 { &hf_opsi_hook_id,
537                         { "Hook ID",                    "opsi.hook",
538                         FT_UINT8, BASE_DEC, NULL, 0x0,
539                         "", HFILL }
540                 },
541                 { &hf_opsi_length,
542                         { "Message length",             "opsi.length",
543                         FT_UINT16, BASE_DEC, NULL, 0x0,
544                         "", HFILL }
545                 },
546                 { &hf_opsi_session_id,
547                         { "Session ID",                 "opsi.session_id",
548                         FT_UINT16, BASE_DEC, NULL, 0x0,
549                         "", HFILL }
550                 },
551                 { &hf_user_name_att,
552                         { "User name",                  "opsi.attr.user_name",
553                         FT_STRING, BASE_NONE, NULL, 0x00,
554                         "", HFILL }
555                 },
556                 { &hf_password_att,
557                         { "User password",              "opsi.attr.password",
558                         FT_STRING, BASE_NONE, NULL, 0x00,
559                         "", HFILL }
560                 },
561                 { &hf_chap_password_att,
562                         { "CHAP password attribute",    "opsi.attr.chap_password",
563                         FT_STRING, BASE_NONE, NULL, 0x00,
564                         "", HFILL }
565                 },
566                 { &hf_nas_ip_add_att,
567                         { "NAS IP address",             "opsi.attr.nas_ip_addr",
568                         FT_IPv4, BASE_DEC, NULL, 0x00,
569                         "", HFILL }
570                 },
571                 { &hf_nas_port_att,
572                         { "NAS port",                   "opsi.attr.nas_port",
573                         FT_UINT32, BASE_HEX, NULL, 0x00,
574                         "", HFILL }
575                 },
576                 { &hf_service_type_att,
577                         { "Service type",               "opsi.attr.service_type",
578                         FT_UINT32, BASE_DEC, VALS(opsi_service_type_code), 0x0,
579                         "", HFILL }
580                 },
581                 { &hf_framed_protocol_att,
582                         { "Framed protocol",            "opsi.attr.framed_protocol",
583                         FT_UINT32, BASE_DEC, VALS(opsi_framed_protocol_code), 0x0,
584                         "", HFILL }
585                 },
586                 { &hf_framed_address_att,
587                         { "Framed address",             "opsi.attr.framed_address",
588                         FT_IPv4, BASE_DEC, NULL, 0x00,
589                         "", HFILL }
590                 },
591                 { &hf_framed_netmask_att,
592                         { "Framed netmask",             "opsi.attr.framed_netmask",
593                         FT_IPv4, BASE_DEC, NULL, 0x00,
594                         "", HFILL }
595                 },
596                 { &hf_framed_routing_att,
597                         { "Framed routing",             "opsi.attr.framed_routing",
598                         FT_UINT32, BASE_DEC, VALS(opsi_framed_routing_code), 0x0,
599                         "", HFILL }
600                 },
601                 { &hf_framed_filter_att,
602                         { "Framed filter",              "opsi.attr.framed_filter",
603                         FT_STRING, BASE_NONE, NULL, 0x00,
604                         "", HFILL }
605                 },
606                 { &hf_framed_mtu_att,
607                         { "Framed MTU",         "opsi.attr.framed_mtu",
608                         FT_UINT32, BASE_DEC, NULL, 0x00,
609                         "", HFILL }
610                 },
611                 { &hf_framed_compression_att,
612                         { "Framed compression",         "opsi.attr.framed_compression",
613                         FT_UINT32, BASE_DEC, VALS(opsi_framed_compression_code), 0x0,
614                         "", HFILL }
615                 },
616                 { &hf_called_station_att,
617                         { "Called station ID",          "opsi.attr.called_station_id",
618                         FT_STRING, BASE_NONE, NULL, 0x00,       
619                         "", HFILL }
620                 },
621                 { &hf_calling_station_att,
622                         { "Calling station ID",         "opsi.attr.calling_station_id",
623                         FT_STRING, BASE_NONE, NULL, 0x00,
624                         "", HFILL }
625                 },
626                 { &hf_nas_identifier_att,
627                         { "NAS ID",                     "opsi.attr.nas_id",
628                         FT_STRING, BASE_NONE, NULL, 0x00,
629                         "", HFILL }
630                 },
631                 { &hf_accounting_att,
632                         { "Accounting",                 "opsi.attr.accounting",
633                         FT_STRING, BASE_NONE, NULL, 0x00,
634                         "", HFILL }
635                 },
636                 { &hf_acct_session_id_att,
637                         { "Accounting session ID",      "opsi.attr.acct.session_id",
638                         FT_STRING, BASE_NONE, NULL, 0x00,
639                         "", HFILL }
640                 },
641                 { &hf_chap_challenge_att,
642                         { "CHAP challenge",             "opsi.attr.chap_challenge",
643                         FT_STRING, BASE_NONE, NULL, 0x00,
644                         "", HFILL }
645                 },
646                 { &hf_nas_port_type_att,
647                         { "NAS port type",              "opsi.attr.nas_port_type",
648                         FT_UINT32, BASE_DEC, VALS(opsi_nas_port_type_code), 0x0,
649                         "", HFILL }
650                 },
651                 { &hf_designation_num_att,
652                         { "Designation number",         "opsi.attr.designation_number",
653                         FT_STRING, BASE_NONE, NULL, 0x00,
654                         "", HFILL }
655                 },
656                 { &hf_nas_port_id_att,
657                         { "NAS port ID",                "opsi.attr.nas_port_id",
658                         FT_STRING, BASE_NONE, NULL, 0x00,
659                         "", HFILL }
660                 },
661                 { &hf_smc_aaa_id_att,
662                         { "SMC AAA ID",                 "opsi.attr.smc_aaa_id",
663                         FT_UINT32, BASE_DEC, NULL, 0x00,
664                         "", HFILL }
665                 },
666                 { &hf_smc_vpn_id_att,   
667                         { "SMC VPN ID",                 "opsi.attr.smc_vpn_id",
668                         FT_UINT32, BASE_DEC, NULL, 0x00,
669                         "", HFILL }
670                 },
671                 { &hf_smc_vpn_name_att,
672                         { "SMC VPN name",               "opsi.attr.smc_vpn_name",
673                         FT_STRING, BASE_NONE, NULL, 0x00,
674                         "", HFILL }
675                 },
676                 { &hf_smc_ran_id_att,
677                         { "SMC RAN ID",                 "opsi.attr.smc_ran_id",
678                         FT_UINT32, BASE_DEC, NULL, 0x00,
679                         "", HFILL }
680                 },
681                 { &hf_smc_ran_ip_att,   
682                         { "SMC RAN IP address",         "opsi.attr.smc_ran_ip",
683                         FT_IPv4, BASE_DEC, NULL, 0x00,
684                         "", HFILL }
685                 },
686                 { &hf_smc_ran_name_att,
687                         { "SMC RAN name",               "opsi.attr.smc_ran_name",
688                         FT_STRING, BASE_NONE, NULL, 0x00,
689                         "", HFILL }
690                 },
691                 { &hf_smc_pop_id_att,
692                         { "SMC POP id",                 "opsi.attr.smc_pop_id",
693                         FT_UINT32, BASE_DEC, NULL, 0x00,
694                         "", HFILL }
695                 },
696                 { &hf_smc_pop_name_att,
697                         { "SMC POP name",               "opsi.attr.smc_pop_name",
698                         FT_STRING, BASE_NONE, NULL, 0x00,
699                         "", HFILL }
700                 },
701                 { &hf_smc_id_att,        
702                         { "SMC ID",                     "opsi.attr.smc_id",
703                         FT_UINT32, BASE_DEC, NULL, 0x00,
704                         "", HFILL }
705                 },
706                 { &hf_smc_receive_time_att,
707                         { "SMC receive time",           "opsi.attr.smc_receive_time",
708                         FT_ABSOLUTE_TIME, BASE_NONE, NULL, 0x00,
709                         "", HFILL }
710                 },
711                 { &hf_smc_stat_time_att,
712                         { "SMC stat time",              "opsi.attr.smc_stat_time",
713                         FT_UINT32, BASE_DEC, NULL, 0x00,
714                         "", HFILL }
715                 },
716         };
717
718 /* Setup protocol subtree array */
719         static gint *ett[] = {
720                 &ett_opsi,
721                 &ett_opsi_user_name,
722                 &ett_opsi_user_password,
723                 &ett_opsi_chap_password,
724                 &ett_opsi_nas_ip_address,
725                 &ett_opsi_nas_port,
726                 &ett_opsi_service_type,
727                 &ett_opsi_framed_protocol,
728                 &ett_opsi_framed_address,
729                 &ett_opsi_framed_netmask,
730                 &ett_opsi_framed_routing,
731                 &ett_opsi_framed_filter,
732                 &ett_opsi_framed_mtu,
733                 &ett_opsi_framed_compression,
734                 &ett_opsi_called_station_id,
735                 &ett_opsi_calling_station_id,
736                 &ett_opsi_nas_identifier,
737                 &ett_opsi_accounting,
738                 &ett_opsi_acct_session_id,
739                 &ett_opsi_chap_challenge,
740                 &ett_opsi_nas_port_type,
741                 &ett_opsi_designation_number,
742                 &ett_opsi_nas_port_id,
743                 &ett_opsi_smc_aaa_id,
744                 &ett_opsi_smc_vpn_id,           
745                 &ett_opsi_smc_vpn_name,
746                 &ett_opsi_smc_ran_id,   
747                 &ett_opsi_smc_ran_ip,           
748                 &ett_opsi_smc_ran_name,
749                 &ett_opsi_smc_pop_id,   
750                 &ett_opsi_smc_pop_name,
751                 &ett_opsi_smc_id,               
752                 &ett_opsi_smc_receive_time,
753                 &ett_opsi_smc_stat_time,
754         };
755         
756 /* For desegmentation / reassembly */
757         module_t *opsi_module;  
758
759 /* Register the protocol name and description */
760         proto_opsi = proto_register_protocol("Open Policy Service Interface",
761             "OPSI", "opsi");
762
763 /* Required function calls to register the header fields and subtrees used */
764         proto_register_field_array(proto_opsi, hf, array_length(hf));
765         proto_register_subtree_array(ett, array_length(ett));
766         
767 /* We activate the desegmentation / reassembly feature */       
768         opsi_module = prefs_register_protocol(proto_opsi, NULL);
769         prefs_register_bool_preference(opsi_module, "desegment_opsi_messages",
770                 "Desegment all OPSI messages spanning multiple TCP segments",
771                 "Whether the OPSI dissector should desegment all messages spanning multiple TCP segments",
772                 &opsi_desegment);
773 }
774
775
776 void
777 proto_reg_handoff_opsi(void)
778 {
779         dissector_handle_t opsi_handle;
780         opsi_handle = create_dissector_handle(dissect_opsi, proto_opsi);
781         dissector_add("tcp.port", TCP_PORT_OPSI, opsi_handle);
782 }
783
784 #ifndef ENABLE_STATIC
785 G_MODULE_EXPORT void
786 plugin_init(plugin_address_table_t *pat
787 #ifndef PLUGINS_NEED_ADDRESS_TABLE
788 _U_
789 #endif
790 )
791 {
792         /* initialise the table of pointers needed in Win32 DLLs */
793         plugin_address_table_init(pat);
794
795         /* register the new protocol, protocol fields, and subtrees */
796         if (proto_opsi == -1) { /* execute protocol initialization only once */
797                 proto_register_opsi();
798         }
799
800 }
801 #endif
802
803 #ifndef ENABLE_STATIC
804 G_MODULE_EXPORT void
805 plugin_reg_handoff(void)
806 {
807         proto_reg_handoff_opsi();
808 }
809 #endif