dcerpc-netlogon: improve NetrLogonGetCapabilities dissection
[wireshark-sm.git] / wiretap / log3gpp.c
blob21efe8508157b55db08dd37ecd4af8bd68d8ad0c
1 /* log3gpp.c
2 * Routines encapsulating/dumping 3gpp protocol logs.
3 * The purpose of this format is to be able to log the 3GPP protocol stack on a mobile phone.
4 * Copyright 2008, Vincent Helfre
6 * Wireshark - Network traffic analyzer
7 * By Gerald Combs <gerald@wireshark.org>
8 * Copyright 1998 Gerald Combs
10 * SPDX-License-Identifier: GPL-2.0-or-later
13 #include "config.h"
14 #include "log3gpp.h"
16 #define WS_LOG_DOMAIN LOG_DOMAIN_WIRETAP
18 #include <errno.h>
19 #include <string.h>
20 #include <stdlib.h>
22 #include "wtap-int.h"
23 #include "file_wrappers.h"
25 #define MAX_FIRST_LINE_LENGTH 200
26 #define MAX_TIMESTAMP_LINE_LENGTH 100
27 #define MAX_LINE_LENGTH 65536
28 #define MAX_TIMESTAMP_LEN 32
29 #define MAX_SECONDS_CHARS 16
30 #define MAX_SUBSECOND_DECIMALS 4
31 #define MAX_PROTOCOL_NAME 64
32 #define MAX_PROTOCOL_PAR_STRING 64
34 /* 'u' or 'd' of a packet as read from file */
35 typedef enum packet_direction_t
37 uplink,
38 downlink
39 } packet_direction_t;
41 typedef struct {
42 time_t start_secs;
43 uint32_t start_usecs;
44 } log3gpp_t;
46 int first_packet_offset;
47 char firstline[MAX_FIRST_LINE_LENGTH];
48 char secondline[MAX_TIMESTAMP_LINE_LENGTH];
49 int secondline_length;
51 /***********************************************************/
52 /* Transient data used for parsing */
54 /* 'Magic number' at start of 3gpp log files. */
55 static const char log3gpp_magic[] = "3GPP protocols transcript";
57 /* Protocol name of the packet that the packet was captured at */
58 static char protocol_name[MAX_PROTOCOL_NAME+1];
60 /* Optional string parameter giving info required for the protocol dissector */
61 static char protocol_parameters[MAX_PROTOCOL_PAR_STRING+1];
62 /************************************************************/
63 /* Functions called from wiretap core */
64 static bool log3gpp_read( wtap* wth, wtap_rec* rec, Buffer* buf,
65 int* err, char** err_info, int64_t* data_offset);
66 static bool log3gpp_seek_read(struct wtap *wth, int64_t seek_off,
67 wtap_rec *rec,
68 Buffer *buf,
69 int *err, char **err_info);
71 /************************************************************/
72 /* Private helper functions */
73 static bool read_new_line(FILE_T fh, int* length,
74 char* buf, size_t bufsize, int* err,
75 char** err_info);
77 static bool parse_line(char* linebuff, int line_length, int *seconds, int *useconds,
78 long *data_offset,
79 int *data_chars,
80 packet_direction_t *direction,
81 bool *is_text_data);
82 static int write_stub_header(unsigned char *frame_buffer, char *timestamp_string,
83 packet_direction_t direction);
84 static unsigned char hex_from_char(char c);
85 /*not used static char char_from_hex(unsigned char hex);*/
87 static bool get_file_time_stamp(const char* linebuff, time_t *secs, uint32_t *usecs);
90 static int log3gpp_file_type_subtype = -1;
92 void register_log3gpp(void);
94 /***************************************************************************/
95 /* Free log3gpp-specific capture info from file that was open for reading */
96 /***************************************************************************/
97 static void log3gpp_close(wtap* wth)
99 log3gpp_t* log3gpp = (log3gpp_t*)wth->priv;
100 /* Also free this capture info */
101 g_free(log3gpp);
102 wth->priv = NULL;
105 /********************************************/
106 /* Open file (for reading) */
107 /********************************************/
108 wtap_open_return_val
109 log3gpp_open(wtap *wth, int *err, char **err_info _U_)
111 time_t timestamp;
112 uint32_t usecs;
113 log3gpp_t *log3gpp;
114 wtap_open_return_val retval;
115 /* Buffer to hold a single text line read from the file */
116 static char linebuff[MAX_LINE_LENGTH];
117 int firstline_length = 0;
119 /* Clear errno before reading from the file */
120 errno = 0;
122 /********************************************************************/
123 /* First line needs to contain at least as many characters as magic */
125 /*ws_warning("Open file"); */
127 if (!read_new_line(wth->fh, &firstline_length, linebuff,
128 sizeof linebuff, err, err_info)) {
129 if (*err != 0 && *err != WTAP_ERR_SHORT_READ) {
130 return WTAP_OPEN_ERROR;
132 else {
133 return WTAP_OPEN_NOT_MINE;
137 if (((size_t)firstline_length < strlen(log3gpp_magic)) ||
138 firstline_length >= MAX_FIRST_LINE_LENGTH)
140 retval = WTAP_OPEN_NOT_MINE;
141 return retval;
144 /* This file is not for us if it doesn't match our signature */
145 if (memcmp(log3gpp_magic, linebuff, strlen(log3gpp_magic)) != 0)
147 retval = WTAP_OPEN_NOT_MINE;
148 return retval;
151 /***********************************************************/
152 /* Second line contains file timestamp */
153 if (!read_new_line(wth->fh, &secondline_length,
154 linebuff, sizeof linebuff, err, err_info)) {
155 if (*err != 0 && *err != WTAP_ERR_SHORT_READ) {
156 return WTAP_OPEN_ERROR;
158 else {
159 return WTAP_OPEN_NOT_MINE;
163 first_packet_offset = firstline_length + secondline_length;
165 if ((secondline_length >= MAX_TIMESTAMP_LINE_LENGTH) ||
166 (!get_file_time_stamp(linebuff, &timestamp, &usecs)))
168 /* Give up if file time line wasn't valid */
169 retval = WTAP_OPEN_NOT_MINE;
170 return retval;
173 /* Allocate struct and fill in timestamp (netmon re used)*/
174 log3gpp = g_new(log3gpp_t, 1);
175 log3gpp->start_secs = timestamp;
176 log3gpp->start_usecs = usecs;
177 wth->priv = (void *)log3gpp;
179 /************************************************************/
180 /* File is for us. Fill in details so packets can be read */
182 /* Set our file type */
183 wth->file_type_subtype = log3gpp_file_type_subtype;
185 /* Use our own encapsulation to send all packets to our stub dissector */
186 wth->file_encap = WTAP_ENCAP_LOG_3GPP;
188 /* Callbacks for reading operations */
189 wth->subtype_read = log3gpp_read;
190 wth->subtype_seek_read = log3gpp_seek_read;
191 wth->subtype_close = log3gpp_close;
193 /* Choose microseconds (have 4 decimal places...) */
194 wth->file_tsprec = WTAP_TSPREC_USEC;
196 *err = errno;
199 * Add an IDB; we don't know how many interfaces were
200 * involved, so we just say one interface, about which
201 * we only know the link-layer type, snapshot length,
202 * and time stamp resolution.
204 wtap_add_generated_idb(wth);
206 retval = WTAP_OPEN_MINE;
207 return retval;
211 /**************************************************/
212 /* Read packet function. */
213 /* Look for and read the next usable packet */
214 /* - return true and details if found */
215 /**************************************************/
216 bool log3gpp_read(wtap* wth, wtap_rec* rec, Buffer* buf,
217 int* err, char** err_info, int64_t* data_offset)
219 int64_t offset = file_tell(wth->fh);
220 static char linebuff[MAX_LINE_LENGTH + 1];
221 long dollar_offset;
222 packet_direction_t direction;
223 bool is_text_data;
224 log3gpp_t *log3gpp = (log3gpp_t *)wth->priv;
226 /* Search for a line containing a usable packet */
227 while (1)
229 int line_length, seconds, useconds, data_chars;
230 int64_t this_offset = offset;
232 /* Are looking for first packet after 2nd line */
233 if (file_tell(wth->fh) == 0)
235 this_offset += (int64_t)first_packet_offset +1+1;
238 /* Clear errno before reading from the file */
239 errno = 0;
241 /* Read a new line from file into linebuff */
242 if (!read_new_line(wth->fh, &line_length, linebuff,
243 sizeof linebuff, err, err_info)) {
244 if (*err != 0) {
245 return false; /* error */
247 /* No more lines can be read, so quit. */
248 break;
251 /* Try to parse the line as a frame record */
252 if (parse_line(linebuff, line_length, &seconds, &useconds,
253 &dollar_offset,
254 &data_chars,
255 &direction,
256 &is_text_data))
258 unsigned char *frame_buffer;
259 int n;
260 int stub_offset = 0;
261 char timestamp_string[MAX_TIMESTAMP_LEN+1];
262 /*not used int64_t *pkey = NULL;*/
264 snprintf(timestamp_string, 32, "%d.%04d", seconds, useconds/100);
266 /* All packets go to 3GPP protocol stub dissector */
267 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_LOG_3GPP;
268 rec->rec_type = REC_TYPE_PACKET;
269 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
270 rec->presence_flags = WTAP_HAS_TS;
272 /* Set data_offset to the beginning of the line we're returning.
273 This will be the seek_off parameter when this frame is re-read.
275 *data_offset = this_offset;
277 /* Fill in timestamp (capture base + packet offset) */
278 rec->ts.secs = log3gpp->start_secs + seconds;
279 if ((log3gpp->start_usecs + useconds) >= 1000000)
281 rec->ts.secs++;
283 rec->ts.nsecs =
284 ((log3gpp->start_usecs + useconds) % 1000000) *1000;
286 if (!is_text_data)
288 /* Get buffer pointer ready */
289 ws_buffer_assure_space(buf,
290 strlen(timestamp_string)+1 + /* timestamp */
291 strlen(protocol_name)+1 + /* Protocol name */
292 1 + /* direction */
293 (size_t)(data_chars/2));
295 frame_buffer = ws_buffer_start_ptr(buf);
296 /*********************/
297 /* Write stub header */
298 stub_offset = write_stub_header(frame_buffer, timestamp_string,
299 direction);
301 /* Binary data length is half bytestring length + stub header */
302 rec->rec_header.packet_header.len = data_chars/2 + stub_offset;
303 rec->rec_header.packet_header.caplen = data_chars/2 + stub_offset;
304 /********************************/
305 /* Copy packet data into buffer */
306 for (n=0; n <= data_chars; n+=2)
308 frame_buffer[stub_offset + n/2] = (hex_from_char(linebuff[dollar_offset+n]) << 4) |
309 hex_from_char(linebuff[dollar_offset+n+1]);
311 *err = errno = 0;
312 return true;
314 else
316 /* Get buffer pointer ready */
317 ws_buffer_assure_space(buf,
318 strlen(timestamp_string)+1 + /* timestamp */
319 strlen(protocol_name)+1 + /* Protocol name */
320 1 + /* direction */
321 data_chars);
322 frame_buffer = ws_buffer_start_ptr(buf);
324 /*********************/
325 /* Write stub header */
326 stub_offset = write_stub_header(frame_buffer, timestamp_string,
327 direction);
329 /* Binary data length is bytestring length + stub header */
330 rec->rec_header.packet_header.len = data_chars + stub_offset;
331 rec->rec_header.packet_header.caplen = data_chars + stub_offset;
333 /* do not convert the ascii char */
334 memcpy(&frame_buffer[stub_offset],&linebuff[dollar_offset],data_chars);
335 frame_buffer[stub_offset+data_chars-1]= '\0';
336 *err = errno = 0;
337 return true;
342 /* No packet details to return... */
343 *err = errno;
344 return false;
348 /**************************************************/
349 /* Read & seek function. */
350 /**************************************************/
351 static bool
352 log3gpp_seek_read(wtap *wth, int64_t seek_off,
353 wtap_rec *rec _U_ , Buffer *buf,
354 int *err, char **err_info)
356 long dollar_offset;
357 static char linebuff[MAX_LINE_LENGTH + 1];
358 packet_direction_t direction;
359 int seconds, useconds, data_chars;
360 bool is_text_data;
361 log3gpp_t* log3gpp = (log3gpp_t*)wth->priv;
362 int length = 0;
363 unsigned char *frame_buffer;
365 /* Reset errno */
366 *err = errno = 0;
368 /* Seek to beginning of packet */
369 if (file_seek(wth->random_fh, seek_off, SEEK_SET, err) == -1)
371 return false;
374 /* Re-read whole line (this really should succeed) */
375 if (!read_new_line(wth->random_fh, &length, linebuff,
376 sizeof linebuff, err, err_info)) {
377 return false;
380 /* Try to parse this line again (should succeed as re-reading...) */
381 if (parse_line(linebuff, length, &seconds, &useconds,
382 &dollar_offset,
383 &data_chars,
384 &direction,
385 &is_text_data))
387 int n;
388 int stub_offset = 0;
389 char timestamp_string[32];
390 snprintf(timestamp_string, 32, "%d.%04d", seconds, useconds/100);
392 /* Make sure all packets go to log3gpp dissector */
393 rec->rec_header.packet_header.pkt_encap = WTAP_ENCAP_LOG_3GPP;
394 rec->rec_type = REC_TYPE_PACKET;
395 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
396 rec->presence_flags = WTAP_HAS_TS;
398 /* Fill in timestamp (capture base + packet offset) */
399 rec->ts.secs = log3gpp->start_secs + seconds;
400 if ((log3gpp->start_usecs + useconds) >= 1000000)
402 rec->ts.secs++;
404 rec->ts.nsecs =
405 ((log3gpp->start_usecs + useconds) % 1000000) * 1000;
407 /*********************/
408 /* Write stub header */
409 ws_buffer_assure_space(buf,
410 strlen(timestamp_string)+1 + /* timestamp */
411 strlen(protocol_name)+1 + /* Protocol name */
412 1 + /* direction */
413 data_chars);
414 frame_buffer = ws_buffer_start_ptr(buf);
415 stub_offset = write_stub_header(frame_buffer, timestamp_string,
416 direction);
418 if (!is_text_data)
420 /********************************/
421 /* Copy packet data into buffer */
422 for (n=0; n <= data_chars; n+=2)
424 frame_buffer[stub_offset + n/2] = (hex_from_char(linebuff[dollar_offset+n]) << 4) |
425 hex_from_char(linebuff[dollar_offset+n+1]);
427 *err = errno = 0;
428 return true;
430 else
432 /* do not convert the ascii char */
433 memcpy(&frame_buffer[stub_offset],&linebuff[dollar_offset],data_chars);
434 frame_buffer[stub_offset+data_chars-1] = '\0';
435 *err = errno = 0;
436 return true;
440 /* If get here, must have failed */
441 *err = errno;
442 *err_info = ws_strdup_printf("prot 3gpp: seek_read failed to read/parse "
443 "line at position %" PRId64,
444 seek_off);
445 return false;
448 /****************************/
449 /* Private helper functions */
450 /****************************/
452 /**********************************************************************/
453 /* Read a new line from the file, starting at offset. */
454 /* - writes data to static var linebuff */
455 /* - on return 'offset' will point to the next position to read from */
456 /* - return true if this read is successful */
457 /**********************************************************************/
458 static bool
459 read_new_line(FILE_T fh, int* length,
460 char* linebuff, size_t linebuffsize, int* err, char** err_info)
462 /* Read in a line */
463 int64_t pos_before = file_tell(fh);
465 if (file_gets(linebuff, (int)linebuffsize - 1, fh) == NULL) {
466 /* No characters found, or error */
467 *err = file_error(fh, err_info);
468 return false;
471 /* Set length (avoiding strlen()) and offset.. */
472 *length = (int)(file_tell(fh) - pos_before);
474 /* ...but don't want to include newline in line length */
475 if (*length > 0 && linebuff[*length - 1] == '\n') {
476 linebuff[*length - 1] = '\0';
477 *length = *length - 1;
479 /* Nor do we want '\r' (as will be written when log is created on windows) */
480 if (*length > 0 && linebuff[*length - 1] == '\r') {
481 linebuff[*length - 1] = '\0';
482 *length = *length - 1;
485 return true;
489 /**********************************************************************/
490 /* Parse a line from buffer, by identifying: */
491 /* - timestamp */
492 /* - data position and length */
493 /* Return true if this packet looks valid and can be displayed */
494 /**********************************************************************/
495 bool parse_line(char* linebuff, int line_length, int *seconds, int *useconds,
496 long *data_offset, int *data_chars,
497 packet_direction_t *direction,
498 bool *is_text_data)
500 int n = 0;
501 int protocol_chars = 0;
502 int prot_option_chars = 0;
503 char seconds_buff[MAX_SECONDS_CHARS+1];
504 int seconds_chars;
505 char subsecond_decimals_buff[MAX_SUBSECOND_DECIMALS];
506 int subsecond_decimals_chars;
508 /*********************************************************************/
509 /* Find and read the timestamp */
510 /*********************************************************************/
511 /* Now scan to the next digit, which should be the start of the timestamp */
512 for (; !g_ascii_isdigit((unsigned char)linebuff[n]) && (n < line_length); n++);
513 if (n >= line_length)
515 return false;
518 /* Seconds */
519 for (seconds_chars = 0;
520 (linebuff[n] != '.') &&
521 (seconds_chars <= MAX_SECONDS_CHARS) &&
522 (n < line_length);
523 n++, seconds_chars++)
525 if (!g_ascii_isdigit((unsigned char)linebuff[n]))
527 /* Found a non-digit before decimal point. Fail */
528 return false;
530 seconds_buff[seconds_chars] = linebuff[n];
532 if (seconds_chars > MAX_SECONDS_CHARS || n >= line_length)
534 /* Didn't fit in buffer. Fail rather than use truncated */
535 return false;
538 /* Convert found value into number */
539 seconds_buff[seconds_chars] = '\0';
541 /* Already know they are digits, so avoid expense of ws_strtoi32() */
542 int multiplier = 1;
543 *seconds = 0;
544 for (int d = seconds_chars - 1; d >= 0; d--) {
545 *seconds += ((seconds_buff[d] - '0') * multiplier);
546 multiplier *= 10;
549 /* The decimal point must follow the last of the seconds digits */
550 if (linebuff[n] != '.')
552 return false;
554 /* Skip it */
555 n++;
557 /* Subsecond decimal digits (expect 4-digit accuracy) */
558 for (subsecond_decimals_chars = 0;
559 (linebuff[n] != ' ') && (subsecond_decimals_chars < MAX_SUBSECOND_DECIMALS) && (n < line_length);
560 n++, subsecond_decimals_chars++)
562 if (!g_ascii_isdigit((unsigned char)linebuff[n]))
564 return false;
566 subsecond_decimals_buff[subsecond_decimals_chars] = linebuff[n];
569 if (subsecond_decimals_chars > MAX_SUBSECOND_DECIMALS || n >= line_length)
571 /* More numbers than expected - give up */
572 return false;
575 /* Convert found value into microseconds */
576 while (subsecond_decimals_chars < MAX_SUBSECOND_DECIMALS) {
577 subsecond_decimals_buff[subsecond_decimals_chars++] = '0';
579 /* Already know they are digits, so avoid expense of ws_strtoi32() */
580 *useconds = ((subsecond_decimals_buff[0] - '0') * 100000) +
581 ((subsecond_decimals_buff[1] - '0') * 10000) +
582 ((subsecond_decimals_buff[2] - '0') * 1000) +
583 ((subsecond_decimals_buff[3] - '0') * 100);
585 /* Space character must follow end of timestamp */
586 if (linebuff[n] != ' ')
588 return false;
590 n++;
592 /*********************************************************************/
593 /* Find and read protocol name */
594 /*********************************************************************/
595 for (protocol_chars = 0;
596 (linebuff[n] != ' ') && (protocol_chars < MAX_PROTOCOL_NAME) && (n < line_length);
597 n++, protocol_chars++)
599 if (!g_ascii_isalnum((unsigned char)linebuff[n]) && linebuff[n] != '_' && linebuff[n] != '.' && linebuff[n] != '-')
601 return false;
603 protocol_name[protocol_chars] = linebuff[n];
605 if (protocol_chars == MAX_PROTOCOL_NAME || n >= line_length)
607 /* If doesn't fit, fail rather than truncate */
608 return false;
610 protocol_name[protocol_chars] = '\0';
612 /* Space char must follow protocol name */
613 if (linebuff[n] != ' ')
615 return false;
617 /* Skip it */
618 n++;
620 /* Scan ahead to the next space */
621 for (; (!g_ascii_isalnum((unsigned char)linebuff[n])) && (n < line_length); n++);
622 if (n >= line_length)
624 return false;
628 if (strcmp(protocol_name,"TXT") == 0)
630 *direction = uplink;
631 *data_offset = n;
632 *data_chars = line_length - n;
633 *is_text_data = true;
635 else
637 /* Next character gives direction of message (must be 'u' or 'd') */
638 if (linebuff[n] == 'u')
640 *direction = uplink;
642 else if (linebuff[n] == 'd')
644 *direction = downlink;
646 else
648 return false;
650 n++;
652 /* Now skip ahead to find start of data (marked by '$') */
653 for (; (n <= line_length) && (linebuff[n] != '$') && (prot_option_chars <= MAX_PROTOCOL_PAR_STRING);
654 n++,prot_option_chars++)
656 protocol_parameters[prot_option_chars] = linebuff[n];
658 protocol_parameters[prot_option_chars] = '\0';
659 if (prot_option_chars == MAX_PROTOCOL_PAR_STRING || n >= line_length)
661 /* If doesn't fit, fail rather than truncate */
662 return false;
665 /* Skip it */
666 n++;
668 /* Set offset to data start within line */
669 *data_offset = n;
671 /* Set number of chars that comprise the hex string protocol data */
672 *data_chars = line_length - n;
674 *is_text_data = false;
676 return true;
679 /*****************************************************************/
680 /* Write the stub info to the data buffer while reading a packet */
681 /*****************************************************************/
682 int write_stub_header(unsigned char *frame_buffer, char *timestamp_string,
683 packet_direction_t direction)
685 int stub_offset = 0;
687 /* Timestamp within file */
688 (void) g_strlcpy((char*)&frame_buffer[stub_offset], timestamp_string, MAX_TIMESTAMP_LEN+1);
689 stub_offset += (int)(strlen(timestamp_string) + 1);
691 /* Protocol name */
692 (void) g_strlcpy((char*)&frame_buffer[stub_offset], protocol_name, MAX_PROTOCOL_NAME+1);
693 stub_offset += (int)(strlen(protocol_name) + 1);
695 /* Direction */
696 frame_buffer[stub_offset] = direction;
697 stub_offset++;
699 /* Option string (might be string of length 0) */
700 (void) g_strlcpy((char*)&frame_buffer[stub_offset], protocol_parameters,MAX_PROTOCOL_PAR_STRING+1);
701 stub_offset += (int)(strlen(protocol_parameters) + 1);
702 return stub_offset;
706 /********************************************************/
707 /* Return hex nibble equivalent of hex string character */
708 /********************************************************/
709 unsigned char hex_from_char(char c)
711 if ((c >= '0') && (c <= '9'))
713 return c - '0';
716 if ((c >= 'a') && (c <= 'f'))
718 return 0x0a + (c - 'a');
721 if ((c >= 'A') && (c <= 'F'))
723 return 0x0a + (c - 'A');
725 /* Not a valid hex string character */
726 return 0xff;
730 /********************************************************/
731 /* Return character corresponding to hex nibble value */
732 /********************************************************/
733 /*char char_from_hex(unsigned char hex)
735 static char hex_lookup[16] =
736 { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
738 if (hex > 15)
740 return '?';
743 return hex_lookup[hex];
746 /************************************************************************/
747 /* Parse year, month, day, hour, minute, seconds out of formatted line. */
748 /* Set secs and usecs as output */
749 /* Return false if no valid time can be read */
750 /************************************************************************/
751 bool get_file_time_stamp(const char* linebuff, time_t *secs, uint32_t *usecs)
753 int n;
754 struct tm tm;
755 #define MAX_MONTH_LETTERS 9
756 char month[MAX_MONTH_LETTERS+1];
758 int day, year, hour, minute, second;
759 int scan_found;
761 /* If line longer than expected, file is probably not correctly formatted */
762 if (strlen(linebuff) > MAX_TIMESTAMP_LINE_LENGTH)
764 return false;
767 /**************************************************************/
768 /* First is month. Read until get a space following the month */
769 for (n=0; (n < MAX_MONTH_LETTERS) && (linebuff[n] != ' '); n++)
771 month[n] = linebuff[n];
773 month[n] = '\0';
775 if (strcmp(month, "January" ) == 0) tm.tm_mon = 0;
776 else if (strcmp(month, "February" ) == 0) tm.tm_mon = 1;
777 else if (strcmp(month, "March" ) == 0) tm.tm_mon = 2;
778 else if (strcmp(month, "April" ) == 0) tm.tm_mon = 3;
779 else if (strcmp(month, "May" ) == 0) tm.tm_mon = 4;
780 else if (strcmp(month, "June" ) == 0) tm.tm_mon = 5;
781 else if (strcmp(month, "July" ) == 0) tm.tm_mon = 6;
782 else if (strcmp(month, "August" ) == 0) tm.tm_mon = 7;
783 else if (strcmp(month, "September") == 0) tm.tm_mon = 8;
784 else if (strcmp(month, "October" ) == 0) tm.tm_mon = 9;
785 else if (strcmp(month, "November" ) == 0) tm.tm_mon = 10;
786 else if (strcmp(month, "December" ) == 0) tm.tm_mon = 11;
787 else
789 /* Give up if not found a properly-formatted date */
790 return false;
792 /* Skip space char */
793 n++;
795 /********************************************************/
796 /* Scan for remaining numerical fields */
797 scan_found = sscanf(linebuff+n, "%d, %d %d:%d:%d.%u",
798 &day, &year, &hour, &minute, &second, usecs);
799 if (scan_found != 6)
801 /* Give up if not all found */
802 return false;
805 /******************************************************/
806 /* Fill in remaining fields and return it in a time_t */
807 tm.tm_year = year - 1900;
808 tm.tm_mday = day;
809 tm.tm_hour = hour;
810 tm.tm_min = minute;
811 tm.tm_sec = second;
812 tm.tm_isdst = -1; /* daylight saving time info not known */
814 /* Get seconds from this time */
815 *secs = mktime(&tm);
817 /* Multiply 4 digits given to get micro-seconds */
818 *usecs = *usecs * 100;
820 return true;
823 static const struct supported_block_type log3gpp_blocks_supported[] = {
825 * We support packet blocks, with no comments or other options.
827 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
830 static const struct file_type_subtype_info log3gpp_info = {
831 "3GPP Log", "3gpp_log", "*.log", NULL,
832 true, BLOCKS_SUPPORTED(log3gpp_blocks_supported),
833 NULL, NULL, NULL
836 void register_log3gpp(void)
838 log3gpp_file_type_subtype = wtap_register_file_type_subtype(&log3gpp_info);
841 * Register name for backwards compatibility with the
842 * wtap_filetypes table in Lua.
844 wtap_register_backwards_compatibility_lua_name("LOG_3GPP",
845 log3gpp_file_type_subtype);
849 * Editor modelines - https://www.wireshark.org/tools/modelines.html
851 * Local variables:
852 * c-basic-offset: 4
853 * tab-width: 8
854 * indent-tabs-mode: nil
855 * End:
857 * vi: set shiftwidth=4 tabstop=8 expandtab:
858 * :indentSize=4:tabSize=8:noTabs=true: