Add support for Exif decoding (initial framework).
[obnox/wireshark/wip.git] / packet-gprs-llc.c
1 /* packet-llcgprs.c
2  * Routines for Logical Link Control GPRS dissection ETSI 4.64
3  * Copyright 2000, Josef Korelus <jkor@quick.cz>
4  *
5  * $Id: packet-gprs-llc.c,v 1.5 2004/05/04 09:03:57 guy Exp $
6  *
7  * Ethereal - Network traffic analyzer
8  * By Gerald Combs <gerald@ethereal.com>
9  * Copyright 1998 Gerald Combs
10  * 
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  * 
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <glib.h>
35
36 #ifdef NEED_SNPRINTF_H
37 # include "snprintf.h"
38 #endif
39
40 #include <epan/packet.h>
41 /*
42 #include "packet-llcgprs.h"
43 */
44 #define I_FORMAT        1
45 #define S_FORMAT        2
46 #define UI_FORMAT       3
47 #define U_FORMAT        4
48 #define I_SACK          5
49 #define S_SACK          6
50 #define UI_MASK_FMT    0xe000
51 #define UI_MASK_SPB    0x1800
52 #define UI_MASK_NU     0x07fc
53 #define UI_MASK_E      0x0002
54 #define UI_MASK_PM     0x0001
55
56 /* Initialize the protocol and registered fields */
57 static int proto_llcgprs       = -1;
58 static int hf_llcgprs_pd       = -1;
59 static int hf_llcgprs_cr       = -1;
60 static int hf_llcgprs_sapi     = -1;
61 static int hf_llcgprs_sapib    = -1;
62 static int hf_llcgprs_U_fmt    = -1;/* 3 upper bits in controlfield (UI format) */
63 static int hf_llcgprs_sp_bits  = -1; /*Spare bits in control field*/
64 static int hf_llcgprs_NU       = -1; /*Transmited unconfirmed sequence number*/
65 static int hf_llcgprs_E_bit    = -1;/* Encryption mode bit*/
66 static int hf_llcgprs_PM_bit   = -1;
67 static int hf_llcgprs_Un       = -1;
68 static int hf_llcgprs_As      = -1;
69 static int hf_llcgprs_ucom     = -1;
70 static int hf_llcgprs_PF        = -1;
71 static int hf_llcgprs_S_fmt     = -1;
72 static int hf_llcgprs_NR        = -1;
73 static int hf_llcgprs_sjsd      = -1;
74 /*static int hf_llcgprs_pd       = -1;
75 */
76 /* Initialize the subtree pointers */
77 static gint ett_llcgprs = -1;
78 static gint ett_llcgprs_adf = -1;
79 static gint ett_llcgprs_ctrlf = -1;
80 static gint ett_ui = -1;
81 static gint ett_llcgprs_sframe = -1;
82
83 static dissector_handle_t data_handle;
84 static dissector_table_t llcgprs_subdissector_table;
85 static const value_string sapi_t[] = {
86         {  0, "Reserved"},
87         {  1, "GPRS Mobility Management" },
88         {  2, "Tunnelling of messages 2" },
89         {  3, "User data 3"},
90         {  4, "Reserved" },
91         {  5, "User data 5" },
92         {  6, "Reserved" },
93         {  7, "SMS" },
94         {  8, "Tunneling of messages 8" },
95         {  9, "User data 9" },
96         { 10, "Reserved" },
97         { 11, "User data 11" },
98         { 12, "Reserved" },
99         { 13, "Reserved" },
100         { 14, "Reserved" },
101         { 15, "Reserved" },
102         {  0, NULL },
103 };
104
105 static const value_string sapi_abrv[] = {
106         {  0, "0"},
107         {  1, "LLGMM" },
108         {  2, "TOM2" },
109         {  3, "LL3"},
110         {  4, "4" },
111         {  5, "LL5" },
112         {  6, "6" },
113         {  7, "LLSMS" },
114         {  8, "TOM8" },
115         {  9, "LL9" },
116         { 10, "10" },
117         { 11, "LL11" },
118         { 12, "12" },
119         { 13, "13" },
120         { 14, "14" },
121         { 15, "15" },
122         {  0, NULL },
123 };
124 static const true_false_string a_bit = {
125         "To solicit an acknowledgement from the peer LLE. ",
126         "The peer LLE is not requested to send an acknowledgment."
127 };
128
129 static const true_false_string pd_bit = {
130         "Invalid frame PD=1",
131         "OK"
132 };
133 static const true_false_string e_bit = {
134         " encrypted frame",
135         " non encrypted frame"  
136 };
137 static const true_false_string pm_bit = {
138         "FCS covers the frame header and information fields",
139         "FCS covers only the frame header and first N202 octets of the information field"
140 };
141 static const true_false_string cr_bit = {
142         "DownLink/UpLink = Command/Response",
143         "DownLink/UpLink = Response/Command"
144 };
145 /* bits are swaped comparing with "Table 3" in ETSI document*/
146 static const value_string pme[] = {
147         { 0, "unprotected,non-ciphered information" },
148         { 1, "protected, non-ciphered information" },
149         { 2, "unprotected,ciphered information"},
150         { 3, "protected, ciphered information" },
151         { 0, NULL},
152 };
153
154 static const value_string cr_formats_unnumb[]= {
155         {  0x1, "DM-response" },
156         {  0x4, "DISC-command" },
157         {  0x6, "UA-response" },
158         {  0x7, "SABM" },
159         {  0x8, "FRMR" },
160         { 0xb, "XID" },
161         { 0, NULL },
162 };
163 static const value_string cr_formats_ipluss[] = {
164         { 0x0,"RR" },
165         { 0x1,"ACK" },
166         { 0x2,"RNR" },
167         { 0x3,"SACK" },
168         { 0, NULL },
169 };
170 /* Code to actually dissect the packets */
171 static void
172 dissect_llcgprs(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree)
173 {
174  guint8 addr_fld=0, sapi=0, ctrl_fld_fb=0, frame_format, tmp=0 ;
175  guint16 offset=0 , epm = 0, nu=0,ctrl_fld_ui_s=0,crc_start=0 ;
176  proto_item *ti, *addres_field_item, *ctrl_field_item, *ui_ti;
177  proto_tree *llcgprs_tree=NULL , *ad_f_tree =NULL, *ctrl_f_tree=NULL, *ui_tree=NULL;
178  tvbuff_t *next_tvb;
179 /* Make entries in Protocol column and Info column on summary display */
180         if (check_col(pinfo->cinfo, COL_PROTOCOL)) 
181                 col_set_str(pinfo->cinfo, COL_PROTOCOL, "GPRS-LLC");
182         
183         crc_start = tvb_length(tvb)-3;
184         addr_fld = tvb_get_guint8(tvb,offset);
185         offset++;
186         if (addr_fld > 128 ) {
187                 if (check_col(pinfo->cinfo,COL_INFO))
188                        col_add_str(pinfo->cinfo,COL_INFO,"Invalid packet - Protocol Discriminator bit is set to 1");
189                 return;
190         }
191         sapi = addr_fld & 0xF;
192         if (check_col(pinfo->cinfo, COL_INFO)) 
193                 col_add_fstr(pinfo->cinfo, COL_INFO, "SAPI: %s", match_strval(sapi,sapi_abrv));
194         
195                           
196         
197 /* In the interest of speed, if "tree" is NULL, don't do any work not
198    necessary to generate protocol tree items. */
199         if (tree) {
200
201                 ti = proto_tree_add_protocol_format(tree, proto_llcgprs, tvb, 0, -1,"MS-SGSN LLC (Mobile Station - Serving GPRS Support Node Logical Link Control)  SAPI: %s", match_strval(sapi,sapi_t));
202
203                 llcgprs_tree = proto_item_add_subtree(ti, ett_llcgprs);
204
205 /* add an item to the subtree, see section 1.6 for more information */
206                 proto_tree_add_text( llcgprs_tree, tvb, crc_start,3, "CRC of LLC layer" );
207                 addres_field_item = proto_tree_add_uint_format(llcgprs_tree,hf_llcgprs_sapi,
208                      tvb, 0,1, sapi, "Address field  SAPI: %s", match_strval(sapi,sapi_abrv));
209                 ad_f_tree = proto_item_add_subtree(addres_field_item, ett_llcgprs_adf);
210                 proto_tree_add_boolean(ad_f_tree, hf_llcgprs_pd, tvb,0,1, addr_fld );
211                 proto_tree_add_boolean(ad_f_tree, hf_llcgprs_cr, tvb,0,1, addr_fld );
212                 proto_tree_add_uint(ad_f_tree, hf_llcgprs_sapib, tvb, 0, 1, addr_fld );
213         }       
214
215         ctrl_fld_fb = tvb_get_guint8(tvb,offset);
216         if ( ctrl_fld_fb < 0xc0 ){
217                 frame_format = ( ctrl_fld_fb < 0x80)? I_FORMAT : S_FORMAT;
218         }
219         else {
220                frame_format = ( ctrl_fld_fb < 0xe0 )? UI_FORMAT : U_FORMAT;
221         }         
222         switch (frame_format){
223                 case I_FORMAT:
224                         if (check_col(pinfo->cinfo,COL_INFO)){
225                                 col_append_str(pinfo->cinfo,COL_INFO, ", I");
226                         }
227                                 
228                         break;
229                 case S_FORMAT:
230                 case UI_FORMAT:
231                         nu = ctrl_fld_ui_s = tvb_get_ntohs(tvb, offset);
232                         offset +=2;
233                         epm = ctrl_fld_ui_s & 0x3;
234                         nu = (nu >>2)&0x01FF;
235                         if (frame_format == S_FORMAT){
236                           if (check_col(pinfo->cinfo, COL_INFO)){
237                                 col_append_str(pinfo->cinfo, COL_INFO, ", S, ");
238                                 col_append_str(pinfo->cinfo, COL_INFO, match_strval(epm,cr_formats_ipluss));
239                                 col_append_fstr(pinfo->cinfo, COL_INFO, ", N(R) = %u", nu);
240                           }
241                           if (tree){
242                                 ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset-2,2,"Supervisory format: %s: N(R) = %u",match_strval(epm,cr_formats_ipluss), nu);
243                                 ctrl_f_tree = proto_item_add_subtree( ctrl_field_item, ett_llcgprs_sframe);
244                                 proto_tree_add_uint( ctrl_f_tree, hf_llcgprs_S_fmt, tvb, offset-2,2, ctrl_fld_ui_s );
245                                 proto_tree_add_boolean( ctrl_f_tree, hf_llcgprs_As, tvb, offset-2, 2, ctrl_fld_ui_s );
246                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_NR, tvb, offset-2, 2, ctrl_fld_ui_s );
247                                 proto_tree_add_uint(ctrl_f_tree, hf_llcgprs_sjsd, tvb, offset-2, 2, ctrl_fld_ui_s );
248                           }
249                         }else{
250 /*UI format*/
251                           if (check_col(pinfo->cinfo, COL_INFO)) {
252                                 col_append_str(pinfo->cinfo, COL_INFO, ", UI, ");
253                                 col_append_str(pinfo->cinfo, COL_INFO, match_strval(epm, pme ));
254                                 col_append_fstr(pinfo->cinfo,COL_INFO, ", N(U) = %u", nu);
255                           }
256                           if (tree){    
257                                 ctrl_field_item = proto_tree_add_text(llcgprs_tree, tvb, offset-2, 2, "Unnumbered Information format - UI, N(U) = %u", nu);
258                                 ctrl_f_tree = proto_item_add_subtree(ctrl_field_item, ett_llcgprs_ctrlf);
259                                 proto_tree_add_uint( ctrl_f_tree, hf_llcgprs_U_fmt, tvb, offset-2, 2, ctrl_fld_ui_s);
260                                 proto_tree_add_uint( ctrl_f_tree, hf_llcgprs_sp_bits, tvb, offset-2,2,ctrl_fld_ui_s);
261                                 proto_tree_add_uint( ctrl_f_tree, hf_llcgprs_NU, tvb, offset-2, 2, ctrl_fld_ui_s);
262                                 proto_tree_add_boolean( ctrl_f_tree, hf_llcgprs_E_bit, tvb, offset-2,2,ctrl_fld_ui_s);
263                                 proto_tree_add_boolean( ctrl_f_tree, hf_llcgprs_PM_bit, tvb, offset-2,2,ctrl_fld_ui_s);
264                           }
265
266                           next_tvb = tvb_new_subset(tvb, offset,crc_start-3, -1 );
267                           if (epm < 2){
268                             if  (!dissector_try_port(llcgprs_subdissector_table,sapi, next_tvb, pinfo, tree))
269                                 call_dissector(data_handle, next_tvb, pinfo, tree);
270                           }
271                           else  call_dissector(data_handle, next_tvb, pinfo, tree);
272                         }
273                         break;
274                 case U_FORMAT:
275                      offset +=1;
276                      tmp = 0;
277                      tmp =  ctrl_fld_fb & 0xf;
278                         if (check_col(pinfo->cinfo, COL_INFO)) {
279                                 col_append_str(pinfo->cinfo, COL_INFO, ", U, ");
280                                 col_append_str(pinfo->cinfo, COL_INFO, val_to_str(tmp, cr_formats_unnumb,"Unknown/invalid code:%X"));
281                         }
282                         if(tree){
283                                 ui_ti = proto_tree_add_text(llcgprs_tree,tvb,offset-1,crc_start-1,"Unnumbered frame: %s",val_to_str(tmp,cr_formats_unnumb,"Unknown/invalid code:%X"));
284                                 ui_tree = proto_item_add_subtree( ui_ti, ett_ui);
285                                 proto_tree_add_uint( ui_tree, hf_llcgprs_Un, tvb, offset-1, 1, ctrl_fld_fb);
286                                 proto_tree_add_boolean( ui_tree, hf_llcgprs_PF, tvb, offset-1, 1, ctrl_fld_fb);
287                                 proto_tree_add_uint( ui_tree, hf_llcgprs_ucom, tvb, offset-1, 1, ctrl_fld_fb);
288                         }
289                         break;
290 /*              case I_SACK:
291                         break;
292                 case S_SACK:
293                         break;  
294 */
295                 }               
296 /*              proto_tree_add_item(llcgprs_tree,
297                     hf_llcgprs_FIELDABBREV, tvb, offset, len, FALSE)
298 */
299 /* Continue adding tree items to process the packet here */
300
301
302
303 /* If this protocol has a sub-dissector call it here, see section 1.8 */
304 }
305
306
307 /* Register the protocol with Ethereal */
308
309 /* this format is require because a script is used to build the C function
310    that calls all the protocol registration.
311 */
312
313 void
314 proto_register_llcgprs(void)
315 {                 
316
317 /* Setup list of header fields  See Section 1.6.1 for details*/
318         static hf_register_info hf[] = {
319                 { &hf_llcgprs_sapi,
320                         { "SAPI", "llcgprs.sapi", FT_UINT8, BASE_DEC, VALS(sapi_abrv), 0x0,"Service Access Point Identifier", HFILL }},
321                 { &hf_llcgprs_pd, 
322                         { "Protocol Discriminator_bit", "llcgprs.pd", FT_BOOLEAN,8, TFS(&pd_bit), 0x80, " Protocol Discriminator bit (should be 0)", HFILL }},
323                 {&hf_llcgprs_sjsd,
324                         { "Supervisory function bits","llcgprs.s1s2", FT_UINT16, BASE_HEX, VALS(cr_formats_ipluss),0x3, "Supervisory functions bits",HFILL }},
325                 { &hf_llcgprs_cr, 
326                         { "Command/Response bit", "llcgprs.cr", FT_BOOLEAN, 8, TFS(&cr_bit), 0x40, " Command/Response bit", HFILL}},
327                 { &hf_llcgprs_sapib,
328                         { "SAPI", "llcgprs.sapib", FT_UINT8, BASE_DEC , VALS(sapi_t), 0xf, "Service Access Point Identifier ",HFILL }}, 
329                 { &hf_llcgprs_U_fmt,
330                         { "UI format", "llcgprs.ui", FT_UINT16, BASE_HEX, NULL, UI_MASK_FMT, "UI frame format",HFILL}},
331                 { &hf_llcgprs_Un,
332                         { "U format", "llcgprs.u", FT_UINT8, BASE_DEC, NULL, 0xe0, " U frame format", HFILL}},
333                 { &hf_llcgprs_sp_bits,
334                         { "Spare bits", "llcgprs.ui_sp_bit", FT_UINT16, BASE_HEX, NULL, UI_MASK_SPB, "Spare bits", HFILL}},
335                 { &hf_llcgprs_NU,
336                         { "N(U)", "llcgprs.nu", FT_UINT16, BASE_DEC, NULL, UI_MASK_NU, "Transmited unconfirmed sequence number", HFILL}},
337                 { &hf_llcgprs_E_bit,
338                         { "E bit", "llcgprs.e", FT_BOOLEAN, 16, TFS(&e_bit), UI_MASK_E,"Encryption mode bit",HFILL }},
339                 { &hf_llcgprs_PM_bit,
340                         { "PM bit", "llcgprs.pm", FT_BOOLEAN, 16, TFS(&pm_bit), UI_MASK_PM, "Protected mode bit",HFILL}},
341                 { &hf_llcgprs_As,
342                         { "Ackn request bit", "llcgprs.as", FT_BOOLEAN, 16, TFS(&a_bit), 0x2000 ,"Acknowledgement request bit A", HFILL}},
343                 { &hf_llcgprs_PF,
344                         { "P/F bit", "llcgprs.pf", FT_BOOLEAN, 8, NULL, 0x10,"Poll /Finall bit", HFILL}},
345                 { &hf_llcgprs_ucom,
346                         { "Command/Response","llcgprs.ucom", FT_UINT8, BASE_HEX, VALS(cr_formats_unnumb),0xf,"Commands and Responses",HFILL }}, 
347                 { &hf_llcgprs_NR,
348                         { "Receive sequence number", "llcgprs.nr",FT_UINT16, BASE_DEC, NULL, UI_MASK_NU,"Receive sequence number N(R)",HFILL }},
349                 {&hf_llcgprs_S_fmt,
350                         { "S format", "llcgprs.s", FT_UINT16, BASE_DEC, NULL, 0xc000,"Supervisory format S", HFILL}}
351         };
352
353 /* Setup protocol subtree array */
354         static gint *ett[] = {
355                 &ett_llcgprs,
356                 &ett_llcgprs_adf,
357                 &ett_llcgprs_ctrlf,
358                 &ett_ui,
359                 &ett_llcgprs_sframe,
360         };
361
362 /* Register the protocol name and description */
363         proto_llcgprs = proto_register_protocol("Logical Link Control GPRS",
364             "GPRS-LLC", "llcgprs");
365         llcgprs_subdissector_table = register_dissector_table("llcgprs.sapi","GPRS LLC SAPI", FT_UINT8,BASE_HEX);
366 /* Required function calls to register the header fields and subtrees used */
367         proto_register_field_array(proto_llcgprs, hf, array_length(hf));
368         proto_register_subtree_array(ett, array_length(ett));
369         register_dissector( "llcgprs", dissect_llcgprs, proto_llcgprs);
370 }
371
372
373 /* If this dissector uses sub-dissector registration add a registration routine.
374    This format is required because a script is used to find these routines and
375    create the code that calls these routines.
376 */
377 void
378 proto_reg_handoff_llcgprs(void)
379 {
380         dissector_handle_t llcgprs_handle;
381
382         llcgprs_handle = create_dissector_handle(dissect_llcgprs,
383             proto_llcgprs);
384 /*      dissector_add("PARENT_SUBFIELD", ID_VALUE, llcgprs_handle);
385 */
386         data_handle = find_dissector("data");
387 }
388