nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | /* decode_as_utils.c |
2 | * |
||
3 | * Routines to modify dissector tables on the fly. |
||
4 | * |
||
5 | * By David Hampton <dhampton@mac.com> |
||
6 | * Copyright 2001 David Hampton |
||
7 | * |
||
8 | * This program is free software; you can redistribute it and/or |
||
9 | * modify it under the terms of the GNU General Public License |
||
10 | * as published by the Free Software Foundation; either version 2 |
||
11 | * of the License, or (at your option) any later version. |
||
12 | * |
||
13 | * This program is distributed in the hope that it will be useful, |
||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
16 | * GNU General Public License for more details. |
||
17 | * |
||
18 | * You should have received a copy of the GNU General Public License |
||
19 | * along with this program; if not, write to the Free Software |
||
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
21 | */ |
||
22 | #include "config.h" |
||
23 | |||
24 | #include <stdlib.h> |
||
25 | |||
26 | #include <errno.h> |
||
27 | |||
28 | #include "epan/decode_as.h" |
||
29 | #include "epan/packet.h" |
||
30 | #include "epan/prefs.h" |
||
31 | #include "epan/prefs-int.h" |
||
32 | |||
33 | #include "epan/dissectors/packet-dcerpc.h" |
||
34 | |||
35 | #include "ui/decode_as_utils.h" |
||
36 | #include "ui/simple_dialog.h" |
||
37 | |||
38 | #include "wsutil/file_util.h" |
||
39 | #include "wsutil/filesystem.h" |
||
40 | #include "wsutil/cmdarg_err.h" |
||
41 | #include "ws_version_info.h" |
||
42 | |||
43 | /* XXX - We might want to switch this to a UAT */ |
||
44 | |||
45 | /* |
||
46 | * A list of dissectors that need to be reset. |
||
47 | */ |
||
48 | static GSList *dissector_reset_list = NULL; |
||
49 | |||
50 | /* |
||
51 | * Data structure used as user data when iterating dissector handles |
||
52 | */ |
||
53 | typedef struct lookup_entry { |
||
54 | gchar* dissector_short_name; |
||
55 | dissector_handle_t handle; |
||
56 | } lookup_entry_t; |
||
57 | |||
58 | /* |
||
59 | * Data structure for tracking which dissector need to be reset. This |
||
60 | * structure is necessary as a hash table entry cannot be removed |
||
61 | * while a g_hash_table_foreach walk is in progress. |
||
62 | */ |
||
63 | typedef struct dissector_delete_item { |
||
64 | /* The name of the dissector table */ |
||
65 | gchar *ddi_table_name; |
||
66 | /* The type of the selector in that dissector table */ |
||
67 | ftenum_t ddi_selector_type; |
||
68 | /* The selector in the dissector table */ |
||
69 | union { |
||
70 | guint sel_uint; |
||
71 | char *sel_string; |
||
72 | } ddi_selector; |
||
73 | } dissector_delete_item_t; |
||
74 | |||
75 | /* |
||
76 | * A callback function to changed a dissector_handle if matched |
||
77 | * This is used when iterating a dissector table |
||
78 | */ |
||
79 | static void |
||
80 | change_dissector_if_matched(gpointer item, gpointer user_data) |
||
81 | { |
||
82 | dissector_handle_t handle = (dissector_handle_t)item; |
||
83 | lookup_entry_t * lookup = (lookup_entry_t *)user_data; |
||
84 | const gchar *proto_short_name = dissector_handle_get_short_name(handle); |
||
85 | if (proto_short_name && strcmp(lookup->dissector_short_name, proto_short_name) == 0) { |
||
86 | lookup->handle = handle; |
||
87 | } |
||
88 | } |
||
89 | |||
90 | /* |
||
91 | * A callback function to parse each "decode as" entry in the file and apply the change |
||
92 | */ |
||
93 | static prefs_set_pref_e |
||
94 | read_set_decode_as_entries(gchar *key, const gchar *value, |
||
95 | void *user_data _U_, |
||
96 | gboolean return_range_errors _U_) |
||
97 | { |
||
98 | gchar *values[4] = {NULL, NULL, NULL, NULL}; |
||
99 | gchar delimiter[4] = {',', ',', ',','\0'}; |
||
100 | gchar *pch; |
||
101 | guint i, j; |
||
102 | dissector_table_t sub_dissectors; |
||
103 | prefs_set_pref_e retval = PREFS_SET_OK; |
||
104 | gboolean is_valid = FALSE; |
||
105 | |||
106 | if (strcmp(key, DECODE_AS_ENTRY) == 0) { |
||
107 | /* Parse csv into table, selector, initial, current */ |
||
108 | for (i = 0; i < 4; i++) { |
||
109 | pch = strchr(value, delimiter[i]); |
||
110 | if (pch == NULL) { |
||
111 | for (j = 0; j < i; j++) { |
||
112 | g_free(values[j]); |
||
113 | } |
||
114 | return PREFS_SET_SYNTAX_ERR; |
||
115 | } |
||
116 | values[i] = g_strndup(value, pch - value); |
||
117 | value = pch + 1; |
||
118 | } |
||
119 | sub_dissectors = find_dissector_table(values[0]); |
||
120 | if (sub_dissectors != NULL) { |
||
121 | lookup_entry_t lookup; |
||
122 | ftenum_t selector_type; |
||
123 | |||
124 | lookup.dissector_short_name = values[3]; |
||
125 | lookup.handle = NULL; |
||
126 | selector_type = dissector_table_get_type(sub_dissectors); |
||
127 | |||
128 | g_slist_foreach(dissector_table_get_dissector_handles(sub_dissectors), |
||
129 | change_dissector_if_matched, &lookup); |
||
130 | if (lookup.handle != NULL || g_ascii_strcasecmp(values[3], DECODE_AS_NONE) == 0) { |
||
131 | is_valid = TRUE; |
||
132 | } |
||
133 | |||
134 | if (is_valid) { |
||
135 | if (IS_FT_STRING(selector_type)) { |
||
136 | dissector_change_string(values[0], values[1], lookup.handle); |
||
137 | } else { |
||
138 | char *p; |
||
139 | long long_value; |
||
140 | |||
141 | long_value = strtol(values[1], &p, 0); |
||
142 | if (p == values[0] || *p != '\0' || long_value < 0 || |
||
143 | (unsigned long)long_value > UINT_MAX) { |
||
144 | retval = PREFS_SET_SYNTAX_ERR; |
||
145 | is_valid = FALSE; |
||
146 | } else |
||
147 | dissector_change_uint(values[0], (guint)long_value, lookup.handle); |
||
148 | } |
||
149 | } |
||
150 | if (is_valid) { |
||
151 | decode_build_reset_list(values[0], selector_type, values[1], NULL, NULL); |
||
152 | } |
||
153 | } else { |
||
154 | retval = PREFS_SET_SYNTAX_ERR; |
||
155 | } |
||
156 | |||
157 | } else { |
||
158 | retval = PREFS_SET_NO_SUCH_PREF; |
||
159 | } |
||
160 | |||
161 | for (i = 0; i < 4; i++) { |
||
162 | g_free(values[i]); |
||
163 | } |
||
164 | return retval; |
||
165 | } |
||
166 | |||
167 | void |
||
168 | load_decode_as_entries(void) |
||
169 | { |
||
170 | char *daf_path; |
||
171 | FILE *daf; |
||
172 | |||
173 | if (dissector_reset_list) { |
||
174 | decode_clear_all(); |
||
175 | } |
||
176 | |||
177 | daf_path = get_persconffile_path(DECODE_AS_ENTRIES_FILE_NAME, TRUE); |
||
178 | if ((daf = ws_fopen(daf_path, "r")) != NULL) { |
||
179 | read_prefs_file(daf_path, daf, read_set_decode_as_entries, NULL); |
||
180 | fclose(daf); |
||
181 | } |
||
182 | g_free(daf_path); |
||
183 | } |
||
184 | |||
185 | void |
||
186 | decode_build_reset_list (const gchar *table_name, ftenum_t selector_type, |
||
187 | gpointer key, gpointer value _U_, |
||
188 | gpointer user_data _U_) |
||
189 | { |
||
190 | dissector_delete_item_t *item; |
||
191 | |||
192 | item = g_new(dissector_delete_item_t,1); |
||
193 | item->ddi_table_name = g_strdup(table_name); |
||
194 | item->ddi_selector_type = selector_type; |
||
195 | switch (selector_type) { |
||
196 | |||
197 | case FT_UINT8: |
||
198 | case FT_UINT16: |
||
199 | case FT_UINT24: |
||
200 | case FT_UINT32: |
||
201 | item->ddi_selector.sel_uint = GPOINTER_TO_UINT(key); |
||
202 | break; |
||
203 | |||
204 | case FT_STRING: |
||
205 | case FT_STRINGZ: |
||
206 | case FT_UINT_STRING: |
||
207 | case FT_STRINGZPAD: |
||
208 | item->ddi_selector.sel_string = g_strdup((char *)key); |
||
209 | break; |
||
210 | |||
211 | default: |
||
212 | g_assert_not_reached(); |
||
213 | } |
||
214 | dissector_reset_list = g_slist_prepend(dissector_reset_list, item); |
||
215 | } |
||
216 | |||
217 | /* clear all settings */ |
||
218 | void |
||
219 | decode_clear_all(void) |
||
220 | { |
||
221 | dissector_delete_item_t *item; |
||
222 | GSList *tmp; |
||
223 | |||
224 | dissector_all_tables_foreach_changed(decode_build_reset_list, NULL); |
||
225 | |||
226 | for (tmp = dissector_reset_list; tmp; tmp = g_slist_next(tmp)) { |
||
227 | item = (dissector_delete_item_t *)tmp->data; |
||
228 | switch (item->ddi_selector_type) { |
||
229 | |||
230 | case FT_UINT8: |
||
231 | case FT_UINT16: |
||
232 | case FT_UINT24: |
||
233 | case FT_UINT32: |
||
234 | dissector_reset_uint(item->ddi_table_name, |
||
235 | item->ddi_selector.sel_uint); |
||
236 | break; |
||
237 | |||
238 | case FT_STRING: |
||
239 | case FT_STRINGZ: |
||
240 | case FT_UINT_STRING: |
||
241 | case FT_STRINGZPAD: |
||
242 | dissector_reset_string(item->ddi_table_name, |
||
243 | item->ddi_selector.sel_string); |
||
244 | g_free(item->ddi_selector.sel_string); |
||
245 | break; |
||
246 | |||
247 | default: |
||
248 | g_assert_not_reached(); |
||
249 | } |
||
250 | g_free(item->ddi_table_name); |
||
251 | g_free(item); |
||
252 | } |
||
253 | g_slist_free(dissector_reset_list); |
||
254 | dissector_reset_list = NULL; |
||
255 | |||
256 | decode_dcerpc_reset_all(); |
||
257 | } |
||
258 | |||
259 | static void |
||
260 | decode_as_write_entry (const gchar *table_name, ftenum_t selector_type, |
||
261 | gpointer key, gpointer value, gpointer user_data) |
||
262 | { |
||
263 | FILE *da_file = (FILE *)user_data; |
||
264 | dissector_handle_t current, initial; |
||
265 | const gchar *current_proto_name, *initial_proto_name; |
||
266 | |||
267 | current = dtbl_entry_get_handle((dtbl_entry_t *)value); |
||
268 | if (current == NULL) |
||
269 | current_proto_name = DECODE_AS_NONE; |
||
270 | else |
||
271 | current_proto_name = dissector_handle_get_short_name(current); |
||
272 | initial = dtbl_entry_get_initial_handle((dtbl_entry_t *)value); |
||
273 | if (initial == NULL) |
||
274 | initial_proto_name = DECODE_AS_NONE; |
||
275 | else |
||
276 | initial_proto_name = dissector_handle_get_short_name(initial); |
||
277 | |||
278 | switch (selector_type) { |
||
279 | |||
280 | case FT_UINT8: |
||
281 | case FT_UINT16: |
||
282 | case FT_UINT24: |
||
283 | case FT_UINT32: |
||
284 | /* |
||
285 | * XXX - write these in decimal, regardless of the base of |
||
286 | * the dissector table's selector, as older versions of |
||
287 | * Wireshark used atoi() when reading this file, and |
||
288 | * failed to handle hex or octal numbers. |
||
289 | * |
||
290 | * That will be fixed in future 1.10 and 1.12 releases, |
||
291 | * but pre-1.10 releases are at end-of-life and won't |
||
292 | * be fixed. |
||
293 | */ |
||
294 | fprintf (da_file, |
||
295 | DECODE_AS_ENTRY ": %s,%u,%s,%s\n", |
||
296 | table_name, GPOINTER_TO_UINT(key), initial_proto_name, |
||
297 | current_proto_name); |
||
298 | break; |
||
299 | |||
300 | case FT_STRING: |
||
301 | case FT_STRINGZ: |
||
302 | case FT_UINT_STRING: |
||
303 | case FT_STRINGZPAD: |
||
304 | fprintf (da_file, |
||
305 | DECODE_AS_ENTRY ": %s,%s,%s,%s\n", |
||
306 | table_name, (gchar *)key, initial_proto_name, |
||
307 | current_proto_name); |
||
308 | break; |
||
309 | |||
310 | default: |
||
311 | g_assert_not_reached(); |
||
312 | break; |
||
313 | } |
||
314 | } |
||
315 | |||
316 | int |
||
317 | save_decode_as_entries(gchar** err) |
||
318 | { |
||
319 | char *pf_dir_path; |
||
320 | char *daf_path; |
||
321 | FILE *da_file; |
||
322 | |||
323 | if (create_persconffile_dir(&pf_dir_path) == -1) { |
||
324 | *err = g_strdup_printf("Can't create directory\n\"%s\"\nfor recent file: %s.", |
||
325 | pf_dir_path, g_strerror(errno)); |
||
326 | g_free(pf_dir_path); |
||
327 | return -1; |
||
328 | } |
||
329 | |||
330 | daf_path = get_persconffile_path(DECODE_AS_ENTRIES_FILE_NAME, TRUE); |
||
331 | if ((da_file = ws_fopen(daf_path, "w")) == NULL) { |
||
332 | *err = g_strdup_printf("Can't open decode_as_entries file\n\"%s\": %s.", |
||
333 | daf_path, g_strerror(errno)); |
||
334 | g_free(daf_path); |
||
335 | return -1; |
||
336 | } |
||
337 | |||
338 | fputs("# \"Decode As\" entries file for Wireshark " VERSION ".\n" |
||
339 | "#\n" |
||
340 | "# This file is regenerated each time \"Decode As\" preferences\n" |
||
341 | "# are saved within Wireshark. Making manual changes should be safe,\n" |
||
342 | "# however.\n", da_file); |
||
343 | |||
344 | dissector_all_tables_foreach_changed(decode_as_write_entry, da_file); |
||
345 | fclose(da_file); |
||
346 | return 0; |
||
347 | } |
||
348 | |||
349 | static const char* prev_display_dissector_name = NULL; |
||
350 | |||
351 | /* |
||
352 | * For a dissector table, print on the stream described by output, |
||
353 | * its short name (which is what's used in the "-d" option) and its |
||
354 | * descriptive name. |
||
355 | */ |
||
356 | static void |
||
357 | display_dissector_table_names(const char *table_name, const char *ui_name, |
||
358 | gpointer output) |
||
359 | { |
||
360 | if ((prev_display_dissector_name == NULL) || |
||
361 | (strcmp(prev_display_dissector_name, table_name) != 0)) { |
||
362 | fprintf((FILE *)output, "\t%s (%s)\n", table_name, ui_name); |
||
363 | prev_display_dissector_name = table_name; |
||
364 | } |
||
365 | } |
||
366 | |||
367 | /* |
||
368 | * For a dissector handle, print on the stream described by output, |
||
369 | * the filter name (which is what's used in the "-d" option) and the full |
||
370 | * name for the protocol that corresponds to this handle. |
||
371 | */ |
||
372 | static void |
||
373 | display_dissector_names(const gchar *table _U_, gpointer handle, gpointer output) |
||
374 | { |
||
375 | int proto_id; |
||
376 | const gchar *proto_filter_name; |
||
377 | const gchar *proto_ui_name; |
||
378 | |||
379 | proto_id = dissector_handle_get_protocol_index((dissector_handle_t)handle); |
||
380 | |||
381 | if (proto_id != -1) { |
||
382 | proto_filter_name = proto_get_protocol_filter_name(proto_id); |
||
383 | proto_ui_name = proto_get_protocol_name(proto_id); |
||
384 | g_assert(proto_filter_name != NULL); |
||
385 | g_assert(proto_ui_name != NULL); |
||
386 | |||
387 | if ((prev_display_dissector_name == NULL) || |
||
388 | (strcmp(prev_display_dissector_name, proto_filter_name) != 0)) { |
||
389 | fprintf((FILE *)output, "\t%s (%s)\n", |
||
390 | proto_filter_name, |
||
391 | proto_ui_name); |
||
392 | prev_display_dissector_name = proto_filter_name; |
||
393 | } |
||
394 | } |
||
395 | } |
||
396 | |||
397 | /* |
||
398 | * Allow dissector key names to be sorted alphabetically |
||
399 | */ |
||
400 | |||
401 | static gint |
||
402 | compare_dissector_key_name(gconstpointer dissector_a, gconstpointer dissector_b) |
||
403 | { |
||
404 | return strcmp((const char*)dissector_a, (const char*)dissector_b); |
||
405 | } |
||
406 | |||
407 | /* |
||
408 | * Print all layer type names supported. |
||
409 | * We send the output to the stream described by the handle output. |
||
410 | */ |
||
411 | static void |
||
412 | fprint_all_layer_types(FILE *output) |
||
413 | |||
414 | { |
||
415 | prev_display_dissector_name = NULL; |
||
416 | dissector_all_tables_foreach_table(display_dissector_table_names, (gpointer)output, (GCompareFunc)compare_dissector_key_name); |
||
417 | } |
||
418 | |||
419 | /* |
||
420 | * Print all protocol names supported for a specific layer type. |
||
421 | * table_name contains the layer type name in which the search is performed. |
||
422 | * We send the output to the stream described by the handle output. |
||
423 | */ |
||
424 | static void |
||
425 | fprint_all_protocols_for_layer_types(FILE *output, gchar *table_name) |
||
426 | |||
427 | { |
||
428 | prev_display_dissector_name = NULL; |
||
429 | dissector_table_foreach_handle(table_name, |
||
430 | display_dissector_names, |
||
431 | (gpointer)output); |
||
432 | } |
||
433 | |||
434 | /* |
||
435 | * The protocol_name_search structure is used by find_protocol_name_func() |
||
436 | * to pass parameters and store results |
||
437 | */ |
||
438 | struct protocol_name_search{ |
||
439 | gchar *searched_name; /* Protocol filter name we are looking for */ |
||
440 | dissector_handle_t matched_handle; /* Handle for a dissector whose protocol has the specified filter name */ |
||
441 | guint nb_match; /* How many dissectors matched searched_name */ |
||
442 | }; |
||
443 | typedef struct protocol_name_search *protocol_name_search_t; |
||
444 | |||
445 | /* |
||
446 | * This function parses all dissectors associated with a table to find the |
||
447 | * one whose protocol has the specified filter name. It is called |
||
448 | * as a reference function in a call to dissector_table_foreach_handle. |
||
449 | * The name we are looking for, as well as the results, are stored in the |
||
450 | * protocol_name_search struct pointed to by user_data. |
||
451 | * If called using dissector_table_foreach_handle, we actually parse the |
||
452 | * whole list of dissectors. |
||
453 | */ |
||
454 | static void |
||
455 | find_protocol_name_func(const gchar *table _U_, gpointer handle, gpointer user_data) |
||
456 | |||
457 | { |
||
458 | int proto_id; |
||
459 | const gchar *protocol_filter_name; |
||
460 | protocol_name_search_t search_info; |
||
461 | |||
462 | g_assert(handle); |
||
463 | |||
464 | search_info = (protocol_name_search_t)user_data; |
||
465 | |||
466 | proto_id = dissector_handle_get_protocol_index((dissector_handle_t)handle); |
||
467 | if (proto_id != -1) { |
||
468 | protocol_filter_name = proto_get_protocol_filter_name(proto_id); |
||
469 | g_assert(protocol_filter_name != NULL); |
||
470 | if (strcmp(protocol_filter_name, search_info->searched_name) == 0) { |
||
471 | /* Found a match */ |
||
472 | if (search_info->nb_match == 0) { |
||
473 | /* Record this handle only if this is the first match */ |
||
474 | search_info->matched_handle = (dissector_handle_t)handle; /* Record the handle for this matching dissector */ |
||
475 | } |
||
476 | search_info->nb_match++; |
||
477 | } |
||
478 | } |
||
479 | } |
||
480 | |||
481 | /* |
||
482 | * The function below parses the command-line parameters for the decode as |
||
483 | * feature (a string pointer by cl_param). |
||
484 | * It checks the format of the command-line, searches for a matching table |
||
485 | * and dissector. If a table/dissector match is not found, we display a |
||
486 | * summary of the available tables/dissectors (on stderr) and return FALSE. |
||
487 | * If everything is fine, we get the "Decode as" preference activated, |
||
488 | * then we return TRUE. |
||
489 | */ |
||
490 | gboolean decode_as_command_option(const gchar *cl_param) |
||
491 | { |
||
492 | gchar *table_name; |
||
493 | guint32 selector, selector2; |
||
494 | gchar *decoded_param; |
||
495 | gchar *remaining_param; |
||
496 | gchar *selector_str; |
||
497 | gchar *dissector_str; |
||
498 | dissector_handle_t dissector_matching; |
||
499 | dissector_table_t table_matching; |
||
500 | ftenum_t dissector_table_selector_type; |
||
501 | struct protocol_name_search user_protocol_name; |
||
502 | guint64 i; |
||
503 | char op; |
||
504 | |||
505 | /* The following code will allocate and copy the command-line options in a string pointed by decoded_param */ |
||
506 | |||
507 | g_assert(cl_param); |
||
508 | decoded_param = g_strdup(cl_param); |
||
509 | g_assert(decoded_param); |
||
510 | |||
511 | |||
512 | /* The lines below will parse this string (modifying it) to extract all |
||
513 | necessary information. Note that decoded_param is still needed since |
||
514 | strings are not copied - we just save pointers. */ |
||
515 | |||
516 | /* This section extracts a layer type (table_name) from decoded_param */ |
||
517 | table_name = decoded_param; /* Layer type string starts from beginning */ |
||
518 | |||
519 | remaining_param = strchr(table_name, '='); |
||
520 | if (remaining_param == NULL) { |
||
521 | cmdarg_err("Parameter \"%s\" doesn't follow the template \"%s\"", cl_param, DECODE_AS_ARG_TEMPLATE); |
||
522 | /* If the argument does not follow the template, carry on anyway to check |
||
523 | if the table name is at least correct. If remaining_param is NULL, |
||
524 | we'll exit anyway further down */ |
||
525 | } |
||
526 | else { |
||
527 | *remaining_param = '\0'; /* Terminate the layer type string (table_name) where '=' was detected */ |
||
528 | } |
||
529 | |||
530 | /* Remove leading and trailing spaces from the table name */ |
||
531 | while (table_name[0] == ' ') |
||
532 | table_name++; |
||
533 | while (table_name[strlen(table_name) - 1] == ' ') |
||
534 | table_name[strlen(table_name) - 1] = '\0'; /* Note: if empty string, while loop will eventually exit */ |
||
535 | |||
536 | /* The following part searches a table matching with the layer type specified */ |
||
537 | table_matching = NULL; |
||
538 | |||
539 | /* Look for the requested table */ |
||
540 | if (!(*(table_name))) { /* Is the table name empty, if so, don't even search for anything, display a message */ |
||
541 | cmdarg_err("No layer type specified"); /* Note, we don't exit here, but table_matching will remain NULL, so we exit below */ |
||
542 | } |
||
543 | else { |
||
544 | table_matching = find_dissector_table(table_name); |
||
545 | if (!table_matching) { |
||
546 | cmdarg_err("Unknown layer type -- %s", table_name); /* Note, we don't exit here, but table_matching will remain NULL, so we exit below */ |
||
547 | } |
||
548 | } |
||
549 | |||
550 | if (!table_matching) { |
||
551 | /* Display a list of supported layer types to help the user, if the |
||
552 | specified layer type was not found */ |
||
553 | cmdarg_err("Valid layer types are:"); |
||
554 | fprint_all_layer_types(stderr); |
||
555 | } |
||
556 | if (remaining_param == NULL || !table_matching) { |
||
557 | /* Exit if the layer type was not found, or if no '=' separator was found |
||
558 | (see above) */ |
||
559 | g_free(decoded_param); |
||
560 | return FALSE; |
||
561 | } |
||
562 | |||
563 | if (*(remaining_param + 1) != '=') { /* Check for "==" and not only '=' */ |
||
564 | cmdarg_err("WARNING: -d requires \"==\" instead of \"=\". Option will be treated as \"%s==%s\"", table_name, remaining_param + 1); |
||
565 | } |
||
566 | else { |
||
567 | remaining_param++; /* Move to the second '=' */ |
||
568 | *remaining_param = '\0'; /* Remove the second '=' */ |
||
569 | } |
||
570 | remaining_param++; /* Position after the layer type string */ |
||
571 | |||
572 | /* This section extracts a selector value (selector_str) from decoded_param */ |
||
573 | |||
574 | selector_str = remaining_param; /* Next part starts with the selector number */ |
||
575 | |||
576 | remaining_param = strchr(selector_str, ','); |
||
577 | if (remaining_param == NULL) { |
||
578 | cmdarg_err("Parameter \"%s\" doesn't follow the template \"%s\"", cl_param, DECODE_AS_ARG_TEMPLATE); |
||
579 | /* If the argument does not follow the template, carry on anyway to check |
||
580 | if the selector value is at least correct. If remaining_param is NULL, |
||
581 | we'll exit anyway further down */ |
||
582 | } |
||
583 | else { |
||
584 | *remaining_param = '\0'; /* Terminate the selector number string (selector_str) where ',' was detected */ |
||
585 | } |
||
586 | |||
587 | dissector_table_selector_type = get_dissector_table_selector_type(table_name); |
||
588 | |||
589 | switch (dissector_table_selector_type) { |
||
590 | |||
591 | case FT_UINT8: |
||
592 | case FT_UINT16: |
||
593 | case FT_UINT24: |
||
594 | case FT_UINT32: |
||
595 | /* The selector for this table is an unsigned number. Parse it as such. |
||
596 | There's no need to remove leading and trailing spaces from the |
||
597 | selector number string, because sscanf will do that for us. */ |
||
598 | switch (sscanf(selector_str, "%u%c%u", &selector, &op, &selector2)) { |
||
599 | case 1: |
||
600 | op = '\0'; |
||
601 | break; |
||
602 | case 3: |
||
603 | if (op != ':' && op != '-') { |
||
604 | cmdarg_err("Invalid selector numeric range \"%s\"", selector_str); |
||
605 | g_free(decoded_param); |
||
606 | return FALSE; |
||
607 | } |
||
608 | if (op == ':') { |
||
609 | if ((selector2 == 0) || ((guint64)selector + selector2 - 1) > G_MAXUINT32) { |
||
610 | cmdarg_err("Invalid selector numeric range \"%s\"", selector_str); |
||
611 | g_free(decoded_param); |
||
612 | return FALSE; |
||
613 | } |
||
614 | } |
||
615 | else if (selector2 < selector) { |
||
616 | /* We could swap them for the user, but maybe it's better to call |
||
617 | * this out as an error in case it's not what was intended? */ |
||
618 | cmdarg_err("Invalid selector numeric range \"%s\"", selector_str); |
||
619 | g_free(decoded_param); |
||
620 | return FALSE; |
||
621 | } |
||
622 | break; |
||
623 | default: |
||
624 | cmdarg_err("Invalid selector number \"%s\"", selector_str); |
||
625 | g_free(decoded_param); |
||
626 | return FALSE; |
||
627 | } |
||
628 | break; |
||
629 | |||
630 | case FT_STRING: |
||
631 | case FT_STRINGZ: |
||
632 | case FT_UINT_STRING: |
||
633 | case FT_STRINGZPAD: |
||
634 | /* The selector for this table is a string. */ |
||
635 | break; |
||
636 | |||
637 | default: |
||
638 | /* There are currently no dissector tables with any types other |
||
639 | than the ones listed above. */ |
||
640 | g_assert_not_reached(); |
||
641 | } |
||
642 | |||
643 | if (remaining_param == NULL) { |
||
644 | /* Exit if no ',' separator was found (see above) */ |
||
645 | cmdarg_err("Valid protocols for layer type \"%s\" are:", table_name); |
||
646 | fprint_all_protocols_for_layer_types(stderr, table_name); |
||
647 | g_free(decoded_param); |
||
648 | return FALSE; |
||
649 | } |
||
650 | |||
651 | remaining_param++; /* Position after the selector number string */ |
||
652 | |||
653 | /* This section extracts a protocol filter name (dissector_str) from decoded_param */ |
||
654 | |||
655 | dissector_str = remaining_param; /* All the rest of the string is the dissector (decode as protocol) name */ |
||
656 | |||
657 | /* Remove leading and trailing spaces from the dissector name */ |
||
658 | while (dissector_str[0] == ' ') |
||
659 | dissector_str++; |
||
660 | while (dissector_str[strlen(dissector_str) - 1] == ' ') |
||
661 | dissector_str[strlen(dissector_str) - 1] = '\0'; /* Note: if empty string, while loop will eventually exit */ |
||
662 | |||
663 | dissector_matching = NULL; |
||
664 | |||
665 | /* We now have a pointer to the handle for the requested table inside the variable table_matching */ |
||
666 | if (!(*dissector_str)) { /* Is the dissector name empty, if so, don't even search for a matching dissector and display all dissectors found for the selected table */ |
||
667 | cmdarg_err("No protocol name specified"); /* Note, we don't exit here, but dissector_matching will remain NULL, so we exit below */ |
||
668 | } |
||
669 | else { |
||
670 | user_protocol_name.nb_match = 0; |
||
671 | user_protocol_name.searched_name = dissector_str; |
||
672 | user_protocol_name.matched_handle = NULL; |
||
673 | |||
674 | dissector_table_foreach_handle(table_name, find_protocol_name_func, &user_protocol_name); /* Go and perform the search for this dissector in the this table's dissectors' names and shortnames */ |
||
675 | |||
676 | if (user_protocol_name.nb_match != 0) { |
||
677 | dissector_matching = user_protocol_name.matched_handle; |
||
678 | if (user_protocol_name.nb_match > 1) { |
||
679 | cmdarg_err("WARNING: Protocol \"%s\" matched %u dissectors, first one will be used", dissector_str, user_protocol_name.nb_match); |
||
680 | } |
||
681 | } |
||
682 | else { |
||
683 | /* OK, check whether the problem is that there isn't any such |
||
684 | protocol, or that there is but it's not specified as a protocol |
||
685 | that's valid for that dissector table. |
||
686 | Note, we don't exit here, but dissector_matching will remain NULL, |
||
687 | so we exit below */ |
||
688 | if (proto_get_id_by_filter_name(dissector_str) == -1) { |
||
689 | /* No such protocol */ |
||
690 | cmdarg_err("Unknown protocol -- \"%s\"", dissector_str); |
||
691 | } |
||
692 | else { |
||
693 | cmdarg_err("Protocol \"%s\" isn't valid for layer type \"%s\"", |
||
694 | dissector_str, table_name); |
||
695 | } |
||
696 | } |
||
697 | } |
||
698 | |||
699 | if (!dissector_matching) { |
||
700 | cmdarg_err("Valid protocols for layer type \"%s\" are:", table_name); |
||
701 | fprint_all_protocols_for_layer_types(stderr, table_name); |
||
702 | g_free(decoded_param); |
||
703 | return FALSE; |
||
704 | } |
||
705 | |||
706 | /* This is the end of the code that parses the command-line options. |
||
707 | All information is now stored in the variables: |
||
708 | table_name |
||
709 | selector |
||
710 | dissector_matching |
||
711 | The above variables that are strings are still pointing to areas within |
||
712 | decoded_parm. decoded_parm thus still needs to be kept allocated in |
||
713 | until we stop needing these variables |
||
714 | decoded_param will be deallocated at each exit point of this function */ |
||
715 | |||
716 | |||
717 | /* We now have a pointer to the handle for the requested dissector |
||
718 | (requested protocol) inside the variable dissector_matching */ |
||
719 | switch (dissector_table_selector_type) { |
||
720 | |||
721 | case FT_UINT8: |
||
722 | case FT_UINT16: |
||
723 | case FT_UINT24: |
||
724 | case FT_UINT32: |
||
725 | /* The selector for this table is an unsigned number. */ |
||
726 | if (op == '\0') { |
||
727 | dissector_change_uint(table_name, selector, dissector_matching); |
||
728 | } |
||
729 | else if (op == ':') { |
||
730 | for (i = selector; i < (guint64)selector + selector2; i++) { |
||
731 | dissector_change_uint(table_name, (guint32)i, dissector_matching); |
||
732 | } |
||
733 | } |
||
734 | else { /* op == '-' */ |
||
735 | for (i = selector; i <= selector2; i++) { |
||
736 | dissector_change_uint(table_name, (guint32)i, dissector_matching); |
||
737 | } |
||
738 | } |
||
739 | break; |
||
740 | |||
741 | case FT_STRING: |
||
742 | case FT_STRINGZ: |
||
743 | case FT_UINT_STRING: |
||
744 | case FT_STRINGZPAD: |
||
745 | /* The selector for this table is a string. */ |
||
746 | dissector_change_string(table_name, selector_str, dissector_matching); |
||
747 | break; |
||
748 | |||
749 | default: |
||
750 | /* There are currently no dissector tables with any types other |
||
751 | than the ones listed above. */ |
||
752 | g_assert_not_reached(); |
||
753 | } |
||
754 | g_free(decoded_param); /* "Decode As" rule has been successfully added */ |
||
755 | return TRUE; |
||
756 | } |
||
757 | |||
758 | /* |
||
759 | * Editor modelines |
||
760 | * |
||
761 | * Local Variables: |
||
762 | * c-basic-offset: 4 |
||
763 | * tab-width: 8 |
||
764 | * indent-tabs-mode: nil |
||
765 | * End: |
||
766 | * |
||
767 | * ex: set shiftwidth=4 tabstop=8 expandtab: |
||
768 | * :indentSize=4:tabSize=8:noTabs=true: |
||
769 | */ |