1 /* nettrace_3gpp_32_423.c
3 * Decoder for 3GPP TS 32.423 file format for the Wiretap library.
4 * The main purpose is to have Wireshark decode raw message content (<rawMsg> tag).
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * Ref: http://www.3gpp.org/DynaReport/32423.htm
25 #ifdef HAVE_SYS_TYPES_H
26 #include <sys/types.h>
39 #include "file_wrappers.h"
40 #include "pcap-encap.h"
42 #include <wsutil/buffer.h>
43 #include "wsutil/tempfile.h"
44 #include "wsutil/os_version_info.h"
45 #include "ws_version_info.h"
46 #include "wsutil/str_util.h"
50 #include "nettrace_3gpp_32_423.h"
53 * Impose a not-too-large limit on the maximum file size, to avoid eating
54 * up 99% of the (address space, swap partition, disk space for swap/page
55 * files); if we were to return smaller chunks and let the dissector do
56 * reassembly, it would *still* have to allocate a buffer the size of
57 * the file, so it's not as if we'd never try to allocate a buffer the
58 * size of the file. Laeve space for the exported PDU tag 12 bytes.
60 #define MAX_FILE_SIZE (G_MAXINT-12)
62 static const guint8 xml_magic[] = { '<', '?', 'x', 'm', 'l' };
63 static const guint8 Threegpp_doc_no[] = { '3', '2', '.', '4', '2', '3' };
65 typedef struct nettrace_3gpp_32_423_file_info {
68 } nettrace_3gpp_32_423_file_info_t;
70 /* From epan/address.h Types of port numbers Wireshark knows about. */
72 PT_NONE, /* no port number */
77 PT_IPX, /* IPX sockets */
78 PT_NCP, /* NCP connection */
79 PT_EXCHG, /* Fibre Channel exchange */
80 PT_DDP, /* DDP AppleTalk connection */
82 PT_IDP, /* XNS IDP sockets */
83 PT_TIPC, /* TIPC PORT */
84 PT_USB, /* USB endpoint 0xffff means the host */
86 PT_IBQP, /* Infiniband QP number */
91 typedef struct exported_pdu_info {
92 guint32 precense_flags;
93 /*const char* proto_name;*/
98 port_type ptype; /* epan/address.h port_type valid for both src and dst*/
106 }exported_pdu_info_t ;
108 /* From epan/epxported_pdu.h*/
109 #define EXP_PDU_TAG_END_OF_OPT 0 /**< End-of-options Tag. */
111 #define EXP_PDU_TAG_OPTIONS_LENGTH 10 /**< Total length of the options excluding this TLV */
112 #define EXP_PDU_TAG_PROTO_NAME 12 /**< The value part should be an ASCII non NULL terminated string
113 * of the registered dissector used by Wireshark e.g "sip"
114 * Will be used to call the next dissector.
116 #define EXP_PDU_TAG_DISSECTOR_TABLE_NAME 14 /**< The value part should be an ASCII non NULL terminated string
117 * containing the dissector table name given
118 * during registration, e.g "gsm_map.v3.arg.opcode"
119 * Will be used to call the next dissector.
122 #define EXP_PDU_TAG_IPV4_SRC 20
123 #define EXP_PDU_TAG_IPV4_DST 21
124 #define EXP_PDU_TAG_SRC_PORT 25
125 #define EXP_PDU_TAG_PORT_TYPE 24 /**< value part is port_type enum from epan/address.h */
126 #define EXP_PDU_TAG_DST_PORT 26
127 #define EXP_PDU_TAG_SS7_OPC 28
128 #define EXP_PDU_TAG_SS7_DPC 29
130 #define EXP_PDU_TAG_ORIG_FNO 30
132 #define EXP_PDU_TAG_DVBCI_EVT 31
134 #define EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL 32 /**< value part is the numeric value to be used calling the dissector table
135 * given with tag EXP_PDU_TAG_DISSECTOR_TABLE_NAME, must follow emediatly after the table tag.
138 #define EXP_PDU_TAG_COL_PROT_TEXT 33 /**< Text string to put in COL_PROTOCOL, one use case is in conjunction with dissector tables where
139 * COL_PROTOCOL might not be filled in.
142 #define EXP_PDU_TAG_IP_SRC_BIT 0x01
143 #define EXP_PDU_TAG_IP_DST_BIT 0x02
144 #define EXP_PDU_TAG_SRC_PORT_BIT 0x04
145 #define EXP_PDU_TAG_DST_PORT_BIT 0x08
146 #define EXP_PDU_TAG_SS7_OPC_BIT 0x20
147 #define EXP_PDU_TAG_SS7_DPC_BIT 0x40
148 #define EXP_PDU_TAG_ORIG_FNO_BIT 0x80
150 /* 2nd byte of optional tags bitmap */
151 #define EXP_PDU_TAG_DVBCI_EVT_BIT 0x0100
152 #define EXP_PDU_TAG_COL_PROT_BIT 0x0200
154 #define EXP_PDU_TAG_IPV4_SRC_LEN 4
155 #define EXP_PDU_TAG_IPV4_DST_LEN 4
156 #define EXP_PDU_TAG_PORT_TYPE_LEN 4
157 #define EXP_PDU_TAG_SRC_PORT_LEN 4
158 #define EXP_PDU_TAG_DST_PORT_LEN 4
162 nettrace_read(wtap *wth, int *err, gchar **err_info, gint64 *data_offset)
164 struct Buffer *frame_buffer_saved;
167 nettrace_3gpp_32_423_file_info_t *file_info = (nettrace_3gpp_32_423_file_info_t *)wth->priv;
169 frame_buffer_saved = file_info->wth_tmp_file->frame_buffer;
170 file_info->wth_tmp_file->frame_buffer = wth->frame_buffer;
171 /* we read the created pcapng file instead */
172 result = wtap_read(file_info->wth_tmp_file, err, err_info, data_offset);
173 file_info->wth_tmp_file->frame_buffer = frame_buffer_saved;
176 wth->phdr.rec_type = file_info->wth_tmp_file->phdr.rec_type;
177 wth->phdr.presence_flags = file_info->wth_tmp_file->phdr.presence_flags;
178 wth->phdr.ts = file_info->wth_tmp_file->phdr.ts;
179 wth->phdr.caplen = file_info->wth_tmp_file->phdr.caplen;
180 wth->phdr.len = file_info->wth_tmp_file->phdr.len;
181 wth->phdr.pkt_encap = file_info->wth_tmp_file->phdr.pkt_encap;
182 wth->phdr.pkt_tsprec = file_info->wth_tmp_file->phdr.pkt_tsprec;
183 wth->phdr.interface_id = file_info->wth_tmp_file->phdr.interface_id;
184 wth->phdr.opt_comment = file_info->wth_tmp_file->phdr.opt_comment;
185 wth->phdr.drop_count = file_info->wth_tmp_file->phdr.drop_count;
186 wth->phdr.pack_flags = file_info->wth_tmp_file->phdr.pack_flags;
187 wth->phdr.ft_specific_data = file_info->wth_tmp_file->phdr.ft_specific_data;
193 nettrace_seek_read(wtap *wth, gint64 seek_off, struct wtap_pkthdr *phdr, Buffer *buf, int *err, gchar **err_info)
195 struct Buffer *frame_buffer_saved;
197 nettrace_3gpp_32_423_file_info_t *file_info = (nettrace_3gpp_32_423_file_info_t *)wth->priv;
199 frame_buffer_saved = file_info->wth_tmp_file->frame_buffer;
200 file_info->wth_tmp_file->frame_buffer = wth->frame_buffer;
202 result = wtap_seek_read(file_info->wth_tmp_file, seek_off, phdr, buf, err, err_info);
203 file_info->wth_tmp_file->frame_buffer = frame_buffer_saved;
208 /* classic wtap: close capture file */
210 nettrace_close(wtap *wth)
212 nettrace_3gpp_32_423_file_info_t *file_info = (nettrace_3gpp_32_423_file_info_t *)wth->priv;
214 wtap_close(file_info->wth_tmp_file);
216 /*Clear the shb info, it's been freed by wtap_close*/
217 wtap_optionblock_set_option_string(wth->shb_hdr, OPT_COMMENT, NULL, 0);
218 wtap_optionblock_set_option_string(wth->shb_hdr, OPT_SHB_HARDWARE, NULL, 0);
219 wtap_optionblock_set_option_string(wth->shb_hdr, OPT_SHB_OS, NULL, 0);
220 wtap_optionblock_set_option_string(wth->shb_hdr, OPT_SHB_USERAPPL, NULL, 0);
222 /* delete the temp file */
223 ws_unlink(file_info->tmpname);
227 /* This attribute specification contains a timestamp that refers to the start of the
228 * first trace data that is stored in this file.
230 * It is a complete timestamp including day, time and delta UTC hour. E.g.
231 * "2001-09-11T09:30:47-05:00".
234 #define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0))
237 nettrace_parse_begin_time(guint8 *curr_pos, struct wtap_pkthdr *phdr)
240 guint year, month, day, hour, minute, second, ms;
244 static const guint days_in_month[12] = {
245 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
248 guint8 *prev_pos, *next_pos;
252 next_pos = strstr(curr_pos, "\"/>");
253 length = (int)(next_pos - prev_pos);
258 /* Scan for all fields */
259 scan_found = sscanf(curr_pos, "%4u-%2u-%2uT%2u:%2u:%2u%3d:%2u",
260 &year, &month, &day, &hour, &minute, &second, &UTCdiffh, &UTCdiffm);
263 if (scan_found != 8) {
264 /* Found this format in a file:
265 * beginTime="2013-09-11T15:45:00,666+02:00"/>
267 scan_found = sscanf(curr_pos, "%4u-%2u-%2uT%2u:%2u:%2u,%3u%3d:%2u",
268 &year, &month, &day, &hour, &minute, &second, &ms, &UTCdiffh, &UTCdiffm);
270 if (scan_found == 9) {
271 phdr->ts.nsecs = ms * 1000;
272 /* Use the code below to set the time stamp */
275 phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
278 g_warning("Failed to parse second time format, scan_found %u", scan_found);
282 if (scan_found == 8) {
284 /* Only set time if we managed to parse it*/
285 /* Fill in remaining fields and return it in a time_t */
286 tm.tm_year = year - 1900;
287 if (month < 1 || month > 12) {
288 phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
291 g_warning("Failed to parse time, month is %u", month);
294 tm.tm_mon = month - 1; /* Zero count*/
295 if (day > ((month == 2 && isleap(year)) ? 29 : days_in_month[month - 1])) {
296 phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
299 g_warning("Failed to parse time, %u-%02u-%2u is not a valid day",
305 phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
308 g_warning("Failed to parse time, hour is %u", hour);
313 phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
316 g_warning("Failed to parse time, minute is %u", minute);
322 * Yes, 60, for leap seconds - POSIX's and Windows'
323 * refusal to believe in them nonwithstanding.
325 phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
328 g_warning("Failed to parse time, second is %u", second);
332 tm.tm_isdst = -1; /* daylight saving time info not known */
334 /* Get seconds from this time */
335 phdr->presence_flags = WTAP_HAS_TS;
336 phdr->ts.secs = mktime(&tm);
338 UTCdiffsec = (abs(UTCdiffh) * 60 * 60) + (UTCdiffm * 60);
341 phdr->ts.secs = phdr->ts.secs - UTCdiffsec;
343 phdr->ts.secs = phdr->ts.secs + UTCdiffsec;
346 g_warning("Failed to parse time, only %u fields", scan_found);
347 phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
354 /* Parsing something like
356 * protocol="Diameter"
358 * [truncated]010001244000012C01000...
361 static wtap_open_return_val
362 write_packet_data(wtap_dumper *wdh, struct wtap_pkthdr *phdr, int *err, gchar **err_info, guint8 *file_buf, time_t start_time, int ms, exported_pdu_info_t *exported_pdu_info, char name_str[64])
364 char *curr_pos, *next_pos;
365 char proto_name_str[16];
366 char dissector_table_str[32];
367 int dissector_table_val=0;
369 int proto_str_len, dissector_table_str_len, raw_data_len, pkt_data_len, exp_pdu_tags_len, i, j;
373 gboolean port_type_defined = FALSE;
374 gboolean use_proto_table = FALSE;
376 memset(proto_name_str, 0, sizeof(proto_name_str));
377 /* Extract the protocol name */
378 curr_pos = strstr(file_buf, "protocol=\"");
380 return WTAP_OPEN_ERROR;
382 curr_pos = curr_pos + 10;
383 next_pos = strstr(curr_pos, "\"");
384 proto_str_len = (int)(next_pos - curr_pos);
385 if (proto_str_len > 15){
386 return WTAP_OPEN_ERROR;
389 g_strlcpy(proto_name_str, curr_pos, proto_str_len+1);
390 ascii_strdown_inplace(proto_name_str);
392 /* Do string matching and replace with Wiresharks protocol name */
393 if (strcmp(proto_name_str, "gtpv2-c") == 0){
394 /* Change to gtpv2 */
395 proto_name_str[5] = '\0';
396 proto_name_str[6] = '\0';
399 /* XXX Do we need to check for function="S1" */
400 if (strcmp(proto_name_str, "nas") == 0){
401 /* Change to nas-eps_plain */
402 g_strlcpy(proto_name_str, "nas-eps_plain", 14);
403 proto_name_str[13] = '\0';
406 if (strcmp(proto_name_str, "map") == 0) {
407 /* For /GSM) map, it looks like the message data is stored like SendAuthenticationInfoArg
408 * use the GSM MAP dissector table to dissect the content.
410 exported_pdu_info->proto_col_str = g_strdup("GSM MAP");
412 if (strcmp(name_str, "sai_request") == 0) {
413 use_proto_table = TRUE;
414 g_strlcpy(dissector_table_str, "gsm_map.v3.arg.opcode", 22);
415 dissector_table_str[21] = '\0';
416 dissector_table_str_len = 21;
417 dissector_table_val = 56;
418 exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_COL_PROT_BIT;
420 else if (strcmp(name_str, "sai_response") == 0) {
421 use_proto_table = TRUE;
422 g_strlcpy(dissector_table_str, "gsm_map.v3.res.opcode", 22);
423 dissector_table_str[21] = '\0';
424 dissector_table_str_len = 21;
425 dissector_table_val = 56;
426 exported_pdu_info->precense_flags = exported_pdu_info->precense_flags + EXP_PDU_TAG_COL_PROT_BIT;
429 /* Find the start of the raw data*/
430 curr_pos = strstr(next_pos, ">") + 1;
431 next_pos = strstr(next_pos, "<");
433 raw_data_len = (int)(next_pos - curr_pos);
435 /* Calculate the space needed for exp pdu tags*/
436 if (use_proto_table == FALSE) {
437 tag_str_len = (proto_str_len + 3) & 0xfffffffc;
438 exp_pdu_tags_len = tag_str_len + 4;
440 tag_str_len = (dissector_table_str_len + 3) & 0xfffffffc;
441 exp_pdu_tags_len = tag_str_len + 4;
442 /* Add EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL + length*/
443 exp_pdu_tags_len = exp_pdu_tags_len + 4 + 4;
446 if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_COL_PROT_BIT) == EXP_PDU_TAG_COL_PROT_BIT) {
447 exp_pdu_tags_len += 4 + (int)strlen(exported_pdu_info->proto_col_str);
450 if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_SRC_BIT) == EXP_PDU_TAG_IP_SRC_BIT) {
451 exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV4_SRC_LEN;
453 if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_SRC_PORT_BIT) == EXP_PDU_TAG_SRC_PORT_BIT) {
454 if (!port_type_defined) {
455 exp_pdu_tags_len += 4 + EXP_PDU_TAG_PORT_TYPE_LEN;
456 port_type_defined = TRUE;
458 exp_pdu_tags_len += 4 + EXP_PDU_TAG_SRC_PORT_LEN;
461 if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_DST_BIT) == EXP_PDU_TAG_IP_DST_BIT) {
462 exp_pdu_tags_len += 4 + EXP_PDU_TAG_IPV4_DST_LEN;
465 if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_DST_PORT_BIT) == EXP_PDU_TAG_DST_PORT_BIT) {
466 if (!port_type_defined) {
467 exp_pdu_tags_len += 4 + EXP_PDU_TAG_PORT_TYPE_LEN;
469 exp_pdu_tags_len += 4 + EXP_PDU_TAG_SRC_PORT_LEN;
472 port_type_defined = FALSE;
474 /* Allocate the packet buf */
475 pkt_data_len = raw_data_len / 2;
476 packet_buf = (guint8 *)g_malloc0(pkt_data_len + exp_pdu_tags_len +4);
478 /* Fill packet buff */
479 if (use_proto_table == FALSE) {
481 packet_buf[1] = 12; /* EXP_PDU_TAG_PROTO_NAME */
483 packet_buf[3] = tag_str_len;
484 for (i = 4, j = 0; j < tag_str_len; i++, j++) {
485 packet_buf[i] = proto_name_str[j];
489 packet_buf[1] = 14; /* EXP_PDU_TAG_DISSECTOR_TABLE_NAME */
491 packet_buf[3] = tag_str_len;
492 for (i = 4, j = 0; j < tag_str_len; i++, j++) {
493 packet_buf[i] = dissector_table_str[j];
497 packet_buf[i] = EXP_PDU_TAG_DISSECTOR_TABLE_NAME_NUM_VAL;
501 packet_buf[i] = 4; /* tag length */;
509 packet_buf[i] = dissector_table_val;
513 if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_COL_PROT_BIT) == EXP_PDU_TAG_COL_PROT_BIT) {
516 packet_buf[i] = EXP_PDU_TAG_COL_PROT_TEXT;
520 packet_buf[i] = (guint8)strlen(exported_pdu_info->proto_col_str);
522 for (j = 0; j < (int)strlen(exported_pdu_info->proto_col_str); i++, j++) {
523 packet_buf[i] = exported_pdu_info->proto_col_str[j];
525 g_free(exported_pdu_info->proto_col_str);
529 if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_SRC_BIT) == EXP_PDU_TAG_IP_SRC_BIT) {
532 packet_buf[i] = EXP_PDU_TAG_IPV4_SRC;
536 packet_buf[i] = EXP_PDU_TAG_IPV4_SRC_LEN; /* tag length */;
538 packet_buf[i] = exported_pdu_info->src_ipv4_d1;
540 packet_buf[i] = exported_pdu_info->src_ipv4_d2;
542 packet_buf[i] = exported_pdu_info->src_ipv4_d3;
544 packet_buf[i] = exported_pdu_info->src_ipv4_d4;
548 if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_SRC_PORT_BIT) == EXP_PDU_TAG_SRC_PORT_BIT) {
549 if (!port_type_defined) {
550 port_type_defined = TRUE;
553 packet_buf[i] = EXP_PDU_TAG_PORT_TYPE;
557 packet_buf[i] = EXP_PDU_TAG_PORT_TYPE_LEN; /* tag length */;
559 packet_buf[i] = (exported_pdu_info->ptype & 0xff000000) >> 24;
561 packet_buf[i] = (exported_pdu_info->ptype & 0x00ff0000) >> 16;
563 packet_buf[i] = (exported_pdu_info->ptype & 0x0000ff00) >> 8;
565 packet_buf[i] = (exported_pdu_info->ptype & 0x000000ff);
570 packet_buf[i] = EXP_PDU_TAG_SRC_PORT;
574 packet_buf[i] = EXP_PDU_TAG_SRC_PORT_LEN; /* tag length */;
576 packet_buf[i] = (exported_pdu_info->src_port & 0xff000000) >> 24;
578 packet_buf[i] = (exported_pdu_info->src_port & 0x00ff0000) >> 16;
580 packet_buf[i] = (exported_pdu_info->src_port & 0x0000ff00) >> 8;
582 packet_buf[i] = (exported_pdu_info->src_port & 0x000000ff);
586 if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_IP_DST_BIT) == EXP_PDU_TAG_IP_DST_BIT) {
589 packet_buf[i] = EXP_PDU_TAG_IPV4_DST;
593 packet_buf[i] = EXP_PDU_TAG_IPV4_DST_LEN; /* tag length */;
595 packet_buf[i] = exported_pdu_info->dst_ipv4_d1;
597 packet_buf[i] = exported_pdu_info->dst_ipv4_d2;
599 packet_buf[i] = exported_pdu_info->dst_ipv4_d3;
601 packet_buf[i] = exported_pdu_info->dst_ipv4_d4;
605 if ((exported_pdu_info->precense_flags & EXP_PDU_TAG_DST_PORT_BIT) == EXP_PDU_TAG_DST_PORT_BIT) {
606 if (!port_type_defined) {
609 packet_buf[i] = EXP_PDU_TAG_PORT_TYPE;
613 packet_buf[i] = EXP_PDU_TAG_PORT_TYPE_LEN; /* tag length */;
615 packet_buf[i] = (exported_pdu_info->ptype & 0xff000000) >> 24;
617 packet_buf[i] = (exported_pdu_info->ptype & 0x00ff0000) >> 16;
619 packet_buf[i] = (exported_pdu_info->ptype & 0x0000ff00) >> 8;
621 packet_buf[i] = (exported_pdu_info->ptype & 0x000000ff);
626 packet_buf[i] = EXP_PDU_TAG_DST_PORT;
630 packet_buf[i] = EXP_PDU_TAG_DST_PORT_LEN; /* tag length */;
632 packet_buf[i] = (exported_pdu_info->src_port & 0xff000000) >> 24;
634 packet_buf[i] = (exported_pdu_info->src_port & 0x00ff0000) >> 16;
636 packet_buf[i] = (exported_pdu_info->src_port & 0x0000ff00) >> 8;
638 packet_buf[i] = (exported_pdu_info->src_port & 0x000000ff);
642 /* Add end of options */
651 exp_pdu_tags_len = exp_pdu_tags_len + 4;
653 /* Convert the hex raw msg data to binary and write to the packet buf*/
654 for (; i < (pkt_data_len + exp_pdu_tags_len); i++){
656 val1 = g_ascii_xdigit_value(chr);
659 val2 = g_ascii_xdigit_value(chr);
660 if ((val1 != -1) && (val2 != -1)){
661 packet_buf[i] = ((guint8)val1 * 16) + val2;
664 /* Something wrong, bail out */
666 return WTAP_OPEN_ERROR;
670 /* Construct the phdr */
671 memset(phdr, 0, sizeof(struct wtap_pkthdr));
672 phdr->rec_type = REC_TYPE_PACKET;
673 if (start_time == 0) {
674 phdr->presence_flags = 0; /* yes, we have no bananas^Wtime stamp */
678 phdr->presence_flags = WTAP_HAS_TS;
679 phdr->ts.secs = start_time;
680 phdr->ts.nsecs = ms * 1000000;
683 phdr->caplen = pkt_data_len + exp_pdu_tags_len;
684 phdr->len = pkt_data_len + exp_pdu_tags_len;
686 if (!wtap_dump(wdh, phdr, packet_buf, err, err_info)) {
689 case WTAP_ERR_UNWRITABLE_REC_DATA:
697 return WTAP_OPEN_ERROR;
701 return WTAP_OPEN_MINE;
705 * Opens an .xml file with Trace data formated according to 3GPP TS 32.423 and converts it to
706 * an "Exported PDU type file with the entire xml file as the first "packet" appending the
707 * raw messages as subsequent packages to be dissected by wireshark.
709 static wtap_open_return_val
710 create_temp_pcapng_file(wtap *wth, int *err, gchar **err_info, nettrace_3gpp_32_423_file_info_t *file_info)
713 wtap_dumper* wdh_exp_pdu;
714 int exp_pdu_file_err;
715 wtap_open_return_val result = WTAP_OPEN_MINE;
718 wtap_optionblock_t shb_hdr = NULL;
719 wtapng_iface_descriptions_t *idb_inf = NULL;
720 wtap_optionblock_t int_data;
721 wtapng_if_descr_mandatory_t *int_data_mand;
722 GString *os_info_str;
725 guint8 *packet_buf = NULL;
727 gchar *wrt_err_info = NULL;
728 struct wtap_pkthdr phdr;
732 gboolean do_random = FALSE;
733 char *curr_pos, *next_msg_pos, *next_pos, *prev_pos;
737 /* Info to build exported_pdu tags*/
738 exported_pdu_info_t exported_pdu_info;
740 exported_pdu_info.precense_flags = 0;
741 exported_pdu_info.src_ipv4_d1 = 0;
742 exported_pdu_info.src_ipv4_d2 = 0;
743 exported_pdu_info.src_ipv4_d3 = 0;
744 exported_pdu_info.src_ipv4_d4 = 0;
745 exported_pdu_info.ptype = PT_NONE;
746 exported_pdu_info.src_port = 0;
747 exported_pdu_info.dst_ipv4_d1 = 0;
748 exported_pdu_info.dst_ipv4_d2 = 0;
749 exported_pdu_info.dst_ipv4_d3 = 0;
750 exported_pdu_info.dst_ipv4_d4 = 0;
751 exported_pdu_info.dst_port = 0;
752 exported_pdu_info.proto_col_str = NULL;
754 import_file_fd = create_tempfile(&(file_info->tmpname), "Wireshark_PDU_");
756 /* Now open a file and dump to it */
757 /* Create data for SHB */
758 os_info_str = g_string_new("");
759 get_os_version_info(os_info_str);
761 shb_hdr = wtap_optionblock_create(WTAP_OPTION_BLOCK_NG_SECTION);
763 wtap_optionblock_set_option_string(wth->shb_hdr, OPT_COMMENT, "File converted to Exported PDU format during opening",
764 strlen("File converted to Exported PDU format during opening"));
766 * UTF-8 string containing the name of the operating system used to create
769 opt_len = os_info_str->len;
770 wtap_optionblock_set_option_string(wth->shb_hdr, OPT_SHB_OS, g_string_free(os_info_str, TRUE), opt_len);
773 * UTF-8 string containing the name of the application used to create
776 wtap_optionblock_set_option_string_format(wth->shb_hdr, OPT_SHB_USERAPPL, "Wireshark %s", get_ws_vcs_version_info());
778 /* Create fake IDB info */
779 idb_inf = g_new(wtapng_iface_descriptions_t, 1);
780 idb_inf->interface_data = g_array_new(FALSE, FALSE, sizeof(wtap_optionblock_t));
782 /* create the fake interface data */
783 int_data = wtap_optionblock_create(WTAP_OPTION_BLOCK_IF_DESCR);
784 int_data_mand = (wtapng_if_descr_mandatory_t*)wtap_optionblock_get_mandatory_data(int_data);
785 int_data_mand->wtap_encap = WTAP_ENCAP_WIRESHARK_UPPER_PDU;
786 int_data_mand->time_units_per_second = 1000000; /* default microsecond resolution */
787 int_data_mand->link_type = wtap_wtap_encap_to_pcap_encap(WTAP_ENCAP_WIRESHARK_UPPER_PDU);
788 int_data_mand->snap_len = WTAP_MAX_PACKET_SIZE;
789 wtap_optionblock_set_option_string(int_data, OPT_IDB_NAME, "Fake IF", strlen("Fake IF"));
790 int_data_mand->num_stat_entries = 0; /* Number of ISB:s */
791 int_data_mand->interface_statistics = NULL;
793 g_array_append_val(idb_inf->interface_data, int_data);
795 wdh_exp_pdu = wtap_dump_fdopen_ng(import_file_fd, WTAP_FILE_TYPE_SUBTYPE_PCAPNG, WTAP_ENCAP_WIRESHARK_UPPER_PDU,
796 WTAP_MAX_PACKET_SIZE, FALSE, shb_hdr, idb_inf, NULL, &exp_pdu_file_err);
797 if (wdh_exp_pdu == NULL) {
798 result = WTAP_OPEN_ERROR;
802 /* OK we've opend a new pcap-ng file and written the headers, time to do the packets, strt by finding the file size */
804 if ((file_size = wtap_file_size(wth, err)) == -1) {
805 result = WTAP_OPEN_ERROR;
809 if (file_size > MAX_FILE_SIZE) {
811 * Don't blow up trying to allocate space for an
812 * immensely-large file.
814 *err = WTAP_ERR_BAD_FILE;
815 *err_info = g_strdup_printf("mime_file: File has %" G_GINT64_MODIFIER "d-byte packet, bigger than maximum of %u",
816 file_size, MAX_FILE_SIZE);
817 result = WTAP_OPEN_ERROR;
820 packet_size = (int)file_size;
821 /* Allocate the packet buffer
822 * (the whole file + Exported PDU tag "protocol" and
823 * the string "xml" + 1 filler to end on 4 byte boundary for the tag
824 * + End of options 4 bytes
826 /* XXX add the length of exported bdu tag(s) here */
827 packet_buf = (guint8 *)g_malloc(packet_size + 12 + 1);
830 packet_buf[1] = EXP_PDU_TAG_PROTO_NAME;
843 if (!wtap_read_bytes(wth->fh, packet_buf + 12, packet_size, &wrt_err, &wrt_err_info)){
844 result = WTAP_OPEN_ERROR;
848 /* Null-terminate buffer; we'll be processing it as a string. */
849 packet_buf[packet_size + 12] = '\0';
851 /* Create the packet header */
852 memset(&phdr, 0, sizeof(struct wtap_pkthdr));
854 /* Read the file header of the input file, currently we only need the beginTime*/
856 /* Advance *packet_buf to point at the raw file data */
857 curr_pos = packet_buf + 12;
858 /* Find the file header */
859 curr_pos = strstr(curr_pos, "<fileHeader");
860 curr_pos = curr_pos + 11;
862 /* Find start time */
863 curr_pos = strstr(curr_pos, "<traceCollec beginTime=\"");
864 curr_pos = curr_pos + 24;
866 curr_pos = nettrace_parse_begin_time(curr_pos, &phdr);
868 start_time = phdr.ts.secs;
870 /* set rest of the pkt hdr data */
871 phdr.rec_type = REC_TYPE_PACKET;
873 phdr.caplen = packet_size + 12;
874 phdr.len = packet_size + 12;
876 /* XXX: report errors! */
877 if (!wtap_dump(wdh_exp_pdu, &phdr, packet_buf, &wrt_err, &wrt_err_info)) {
880 case WTAP_ERR_UNWRITABLE_REC_DATA:
881 g_free(wrt_err_info);
888 result = WTAP_OPEN_ERROR;
892 /* Lets add the raw messages as packets after the main "packet" with the whole file */
893 while ((curr_pos = strstr(curr_pos, "<msg")) != NULL){
894 wtap_open_return_val temp_val;
895 /* Clear for each itteration */
896 exported_pdu_info.precense_flags = 0;
897 exported_pdu_info.ptype = PT_NONE;
899 curr_pos = curr_pos + 4;
900 next_msg_pos = strstr(curr_pos, "</msg>");
902 /* Somethings wrong, bail out */
905 next_msg_pos = next_msg_pos + 6;
906 /* Check if we have a time stamp "changeTime"
907 * expressed in number of seconds and milliseconds (nbsec.ms).
911 /* See if we have a "name" */
912 curr_pos = strstr(curr_pos, "name=");
913 if ((curr_pos) && (curr_pos < next_msg_pos)) {
914 /* extract the name */
915 curr_pos = curr_pos + 6;
916 next_pos = strstr(curr_pos, "\"");
917 name_str_len = (int)(next_pos - curr_pos);
918 if (name_str_len > 63) {
919 return WTAP_OPEN_ERROR;
922 g_strlcpy(name_str, curr_pos, name_str_len + 1);
923 ascii_strdown_inplace(name_str);
929 curr_pos = strstr(curr_pos, "changeTime");
930 /* Check if we have the tag or if we pased the end of the current message */
931 if ((curr_pos)&&(curr_pos < next_msg_pos)){
932 curr_pos = curr_pos + 12;
933 scan_found = sscanf(curr_pos, "%u.%u",&second, &ms);
935 if ((scan_found == 2) && (start_time != 0)) {
936 start_time = start_time + second;
941 /* Check if we have "<initiator>"
942 * It might contain an address
945 curr_pos = strstr(curr_pos, "<initiator>");
946 /* Check if we have the tag or if we pased the end of the current message */
947 if ((curr_pos) && (curr_pos < next_msg_pos)) {
948 curr_pos = curr_pos + 11;
949 next_pos = strstr(curr_pos, "</initiator>");
951 curr_pos = strstr(curr_pos, "address");
952 if ((curr_pos) && (curr_pos < next_pos)) {
953 guint d1, d2, d3, d4, port;
956 curr_pos = curr_pos + 7;
957 /* Excample from one trace, unsure if it's generic...
958 * {address == 192.168.73.1, port == 5062, transport == Udp}
960 scan_found = sscanf(curr_pos, "%*s %3u.%3u.%3u.%3u, %*s %*s %5u, %*s %*s %4s",
961 &d1, &d2, &d3, &d4, &port, transp_str);
962 if (scan_found == 6) {
963 exported_pdu_info.precense_flags = exported_pdu_info.precense_flags + EXP_PDU_TAG_IP_SRC_BIT + EXP_PDU_TAG_SRC_PORT_BIT;
964 exported_pdu_info.src_ipv4_d1 = d1;
965 exported_pdu_info.src_ipv4_d2 = d2;
966 exported_pdu_info.src_ipv4_d3 = d3;
967 exported_pdu_info.src_ipv4_d4 = d4;
969 /* Only add port_type once */
970 if(exported_pdu_info.ptype == PT_NONE){
971 if (g_ascii_strncasecmp(transp_str, "udp", 3) == 0) exported_pdu_info.ptype = PT_UDP;
972 else if (g_ascii_strncasecmp(transp_str, "tcp", 3) == 0) exported_pdu_info.ptype = PT_TCP;
973 else if (g_ascii_strncasecmp(transp_str, "sctp", 4) == 0) exported_pdu_info.ptype = PT_SCTP;
975 exported_pdu_info.src_port = port;
977 g_warning("scan_found:%u, %u.%u.%u.%u Port %u transport %s", scan_found, d1, d2, d3, d4, port, transp_str);
980 /* address not found*/
984 /*"<initiator>" not found */
988 /* Check if we have "<target>"
989 * It might contain an address
992 curr_pos = strstr(curr_pos, "<target>");
993 /* Check if we have the tag or if we pased the end of the current message */
994 if ((curr_pos) && (curr_pos < next_msg_pos)) {
995 curr_pos = curr_pos + 8;
996 next_pos = strstr(curr_pos, "</target>");
998 curr_pos = strstr(curr_pos, "address");
999 if ((curr_pos) && (curr_pos < next_pos)) {
1000 guint d1, d2, d3, d4, port;
1003 curr_pos = curr_pos + 7;
1004 /* Excample from one trace, unsure if it's generic...
1005 * {address == 192.168.73.1, port == 5062, transport == Udp}
1007 scan_found = sscanf(curr_pos, "%*s %3u.%3u.%3u.%3u, %*s %*s %5u, %*s %*s %4s",
1008 &d1, &d2, &d3, &d4, &port, transp_str);
1009 if (scan_found == 6) {
1010 exported_pdu_info.precense_flags = exported_pdu_info.precense_flags + EXP_PDU_TAG_IP_DST_BIT + EXP_PDU_TAG_DST_PORT_BIT;
1011 exported_pdu_info.dst_ipv4_d1 = d1;
1012 exported_pdu_info.dst_ipv4_d2 = d2;
1013 exported_pdu_info.dst_ipv4_d3 = d3;
1014 exported_pdu_info.dst_ipv4_d4 = d4;
1015 /* Only add port_type once */
1016 if (exported_pdu_info.ptype == PT_NONE) {
1017 if (g_ascii_strncasecmp(transp_str, "udp", 3) == 0) exported_pdu_info.ptype = PT_UDP;
1018 else if (g_ascii_strncasecmp(transp_str, "tcp", 3) == 0) exported_pdu_info.ptype = PT_TCP;
1019 else if (g_ascii_strncasecmp(transp_str, "sctp", 4) == 0) exported_pdu_info.ptype = PT_SCTP;
1021 exported_pdu_info.dst_port = port;
1023 g_warning("scan_found:%u, %u.%u.%u.%u Port %u transport %s", scan_found, d1, d2, d3, d4, port, transp_str);
1027 /* address not found */
1028 curr_pos = next_pos;
1031 /* "<target>" not found */
1032 curr_pos = prev_pos;
1035 /* Do we have a raw msg?) */
1036 curr_pos = strstr(curr_pos, "<rawMsg");
1038 /* No rawMsg, continue */
1039 curr_pos = next_msg_pos;
1042 curr_pos = curr_pos + 7;
1043 /* Add the raw msg*/
1044 temp_val = write_packet_data(wdh_exp_pdu, &phdr, &wrt_err, &wrt_err_info, curr_pos, start_time, ms, &exported_pdu_info, name_str);
1045 if (temp_val != WTAP_OPEN_MINE){
1049 curr_pos = next_msg_pos;
1052 /* Close the written file*/
1053 if (!wtap_dump_close(wdh_exp_pdu, err)){
1054 result = WTAP_OPEN_ERROR;
1058 /* Now open the file for reading */
1060 /* Find out if random read was requested */
1061 if (wth->random_fh){
1064 file_info->wth_tmp_file =
1065 wtap_open_offline(file_info->tmpname, WTAP_TYPE_AUTO, err, err_info, do_random);
1067 if (!file_info->wth_tmp_file){
1068 result = WTAP_OPEN_ERROR;
1073 g_free(wrt_err_info);
1075 wtap_optionblock_free(shb_hdr);
1076 wtap_free_idb_info(idb_inf);
1081 wtap_open_return_val
1082 nettrace_3gpp_32_423_file_open(wtap *wth, int *err, gchar **err_info)
1084 char magic_buf[512+1]; /* increase buffer size when needed */
1087 nettrace_3gpp_32_423_file_info_t *file_info;
1088 wtap_open_return_val temp_val;
1091 bytes_read = file_read(magic_buf, 512, wth->fh);
1093 if (bytes_read < 0) {
1094 *err = file_error(wth->fh, err_info);
1095 return WTAP_OPEN_ERROR;
1097 if (bytes_read == 0){
1098 return WTAP_OPEN_NOT_MINE;
1101 if (memcmp(magic_buf, xml_magic, sizeof(xml_magic)) != 0){
1102 return WTAP_OPEN_NOT_MINE;
1105 /* Null-terminate buffer; we'll be processing it as a string. */
1106 magic_buf[512] = '\0';
1108 /* File header should contain something like fileFormatVersion="32.423 V8.1.0" */
1109 curr_pos = strstr(magic_buf, "fileFormatVersion");
1112 return WTAP_OPEN_NOT_MINE;
1115 if (memcmp(curr_pos, Threegpp_doc_no, sizeof(Threegpp_doc_no)) != 0){
1116 return WTAP_OPEN_NOT_MINE;
1119 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
1120 return WTAP_OPEN_ERROR;
1122 /* Ok it's our file, open a temp file and do the conversion */
1123 file_info = g_new0(nettrace_3gpp_32_423_file_info_t, 1);
1124 temp_val = create_temp_pcapng_file(wth, err, err_info, file_info);
1126 if (temp_val != WTAP_OPEN_MINE){
1130 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1)
1131 return WTAP_OPEN_ERROR;
1133 /* Copy data from the temp file wth */
1134 wtap_optionblock_copy_options(wth->shb_hdr, file_info->wth_tmp_file->shb_hdr);
1136 wth->file_type_subtype = WTAP_FILE_TYPE_SUBTYPE_NETTRACE_3GPP_32_423;
1137 wth->file_encap = file_info->wth_tmp_file->file_encap;
1138 wth->file_tsprec = file_info->wth_tmp_file->file_tsprec;
1139 wth->subtype_read = nettrace_read;
1140 wth->subtype_seek_read = nettrace_seek_read;
1141 wth->subtype_close = nettrace_close;
1142 wth->snapshot_length = 0;
1144 wth->priv = (void*)file_info;
1146 return WTAP_OPEN_MINE;
1151 * Editor modelines - http://www.wireshark.org/tools/modelines.html
1156 * indent-tabs-mode: t
1159 * vi: set shiftwidth=8 tabstop=8 noexpandtab:
1160 * :indentSize=8:tabSize=8:noTabs=false: