dcerpc-netlogon: improve NetrLogonGetCapabilities dissection
[wireshark-sm.git] / wiretap / ems.c
blobcf3380b31c6c6aad9734fdcdc97ab7fe59e33ac9
1 /* ems.c
3 * File format support for EGNOS Message Server files
4 * Copyright (c) 2023 by Timo Warns <timo.warns@gmail.com>
6 * SPDX-License-Identifier: GPL-2.0-or-later
7 */
9 #include "config.h"
11 #define WS_LOG_DOMAIN LOG_DOMAIN_WIRETAP
13 #include "ems.h"
15 #include <stdio.h>
17 #include "wtap-int.h"
18 #include "file_wrappers.h"
20 #include <wsutil/buffer.h>
21 #include <wsutil/nstime.h>
22 #include <wsutil/strtoi.h>
23 #include <wsutil/wslog.h>
25 static bool ems_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, char
26 **err_info, int64_t *data_offset);
27 static bool ems_seek_read(wtap *wth, int64_t seek_off, wtap_rec *rec, Buffer
28 *buf, int *err, char **err_info);
30 #define MAX_EMS_LINE_LEN 256
31 #define EMS_MSG_SIZE 40
33 typedef struct ems_msg_s {
34 unsigned int prn;
35 unsigned int year;
36 unsigned int month;
37 unsigned int day;
38 unsigned int hour;
39 unsigned int minute;
40 unsigned int second;
41 unsigned int mt;
42 char sbas_msg[64];
43 } ems_msg_t;
45 static int ems_file_type_subtype = -1;
47 /**
48 * Gets one character and returns in case of error.
49 * Without error, peeks at next character and returns it.
51 static int get_and_peek(FILE_T fh) {
52 int c;
54 c = file_getc(fh);
56 if (c < 0) {
57 return c;
60 return file_peekc(fh);
63 /**
64 * Peeks / returns next relevant character.
65 * Skips whitespace at the beginning of a line, comment lines, and empty
66 * lines.
68 static int peek_relevant_character(FILE_T fh) {
69 int c;
71 while (true) {
72 c = file_peekc(fh);
74 if (c < 0) {
75 return c;
78 // ignore whitespace at the beginning of a line
79 else if (g_ascii_isspace(c)) {
80 ws_debug("ignoring whitespace at the beginning of line");
81 do {
82 c = get_and_peek(fh);
83 if (c < 0) {
84 return c;
86 } while (g_ascii_isspace(c));
88 continue;
91 // ignore comment and empty lines
92 else if (c == '\r' || c == '\n' || c == '#') {
93 ws_debug("ignoring comment or empty line");
94 do {
95 c = get_and_peek(fh);
96 if (c < 0) {
97 return c;
99 } while (c != '\n');
101 continue;
104 // return current character for further inspection
105 else {
106 return c;
112 * Parses EMS line to ems_msg struct.
113 * Return false on error, true otherwise.
115 static bool parse_ems_line(FILE_T fh, ems_msg_t* ems_msg) {
116 char line[MAX_EMS_LINE_LEN];
117 int i;
119 if (!file_gets(line, array_length(line), fh)) {
120 return false;
123 i = sscanf(line, "%03u %02u %02u %02u %02u %02u %02u %u %64c",
124 &ems_msg->prn,
125 &ems_msg->year,
126 &ems_msg->month,
127 &ems_msg->day,
128 &ems_msg->hour,
129 &ems_msg->minute,
130 &ems_msg->second,
131 &ems_msg->mt,
132 ems_msg->sbas_msg);
133 if (9 != i) {
134 return false;
137 if (ems_msg->prn > 255 ||
138 ems_msg->year > 255 ||
139 ems_msg->month > 12 ||
140 ems_msg->day > 31 ||
141 ems_msg->hour > 23 ||
142 ems_msg->minute > 59 ||
143 ems_msg->second > 59 ||
144 ems_msg->mt > 255) {
145 return false;
148 return true;
151 wtap_open_return_val ems_open(wtap *wth, int *err, char **err_info) {
152 int c;
153 ems_msg_t msg;
155 ws_debug("opening file");
157 // skip irrelevant characters
158 c = peek_relevant_character(wth->fh);
159 if (c < 0) {
160 if (file_eof(wth->fh)) {
161 return WTAP_OPEN_NOT_MINE;
163 *err = file_error(wth->fh, err_info);
164 return WTAP_OPEN_ERROR;
167 // EMS nav msg lines start with a digit (first digit of PRN).
168 // Check whether current line starts with a digit.
169 if (!g_ascii_isdigit(c)) {
170 return WTAP_OPEN_NOT_MINE;
173 // Check whether the current line matches the EMS format
174 if (parse_ems_line(wth->fh, &msg)) {
175 /* return to the beginning of the file */
176 if (file_seek(wth->fh, 0, SEEK_SET, err) == -1) {
177 *err = file_error(wth->fh, err_info);
178 return WTAP_OPEN_ERROR;
181 wth->file_encap = WTAP_ENCAP_EMS;
182 wth->snapshot_length = 0;
183 wth->file_tsprec = WTAP_TSPREC_SEC;
184 wth->subtype_read = ems_read;
185 wth->subtype_seek_read = ems_seek_read;
186 wth->file_type_subtype = ems_file_type_subtype;
188 return WTAP_OPEN_MINE;
191 return WTAP_OPEN_NOT_MINE;
194 static bool ems_read_message(FILE_T fh, wtap_rec *rec, Buffer *buf,
195 int *err, char **err_info) {
197 int c;
198 ems_msg_t msg;
200 // skip irrelevant characters
201 c = peek_relevant_character(fh);
202 if (c < 0) {
203 *err = file_error(fh, err_info);
204 return false;
207 // parse line with EMS message
208 if (parse_ems_line(fh, &msg)) {
209 char ts[NSTIME_ISO8601_BUFSIZE + 1];
211 ws_buffer_assure_space(buf, EMS_MSG_SIZE);
213 ws_buffer_end_ptr(buf)[0] = msg.prn;
214 ws_buffer_end_ptr(buf)[1] = msg.year;
215 ws_buffer_end_ptr(buf)[2] = msg.month;
216 ws_buffer_end_ptr(buf)[3] = msg.day;
217 ws_buffer_end_ptr(buf)[4] = msg.hour;
218 ws_buffer_end_ptr(buf)[5] = msg.minute;
219 ws_buffer_end_ptr(buf)[6] = msg.second;
220 ws_buffer_end_ptr(buf)[7] = msg.mt;
222 int i;
223 for (i = 0; i < 32; i++) {
224 uint8_t v;
225 char s[3] = {msg.sbas_msg[i*2], msg.sbas_msg[i*2+1], 0};
226 if (!ws_hexstrtou8(s, NULL, &v)) {
227 return false;
229 ws_buffer_end_ptr(buf)[8 + i] = v;
232 ws_buffer_increase_length(buf, EMS_MSG_SIZE);
234 rec->rec_type = REC_TYPE_PACKET;
235 rec->block = wtap_block_create(WTAP_BLOCK_PACKET);
236 rec->presence_flags = WTAP_HAS_TS;
237 rec->rec_header.packet_header.len = EMS_MSG_SIZE;
238 rec->rec_header.packet_header.caplen = EMS_MSG_SIZE;
240 // use EMS timestamp as packet timestamp
241 snprintf(ts, sizeof(ts), "%04u-%02u-%02uT%02u:%02u:%02uZ", msg.year
242 + 2000, msg.month, msg.day, msg.hour, msg.minute, msg.second);
243 iso8601_to_nstime(&rec->ts, ts, ISO8601_DATETIME);
245 return true;
248 return false;
251 static bool ems_read(wtap *wth, wtap_rec *rec, Buffer *buf, int *err, char
252 **err_info, int64_t *offset) {
254 *offset = file_tell(wth->fh);
255 ws_debug("reading at offset %" PRId64, *offset);
257 if (!ems_read_message(wth->fh, rec, buf, err, err_info)) {
258 return false;
261 return true;
264 static bool ems_seek_read(wtap *wth, int64_t offset, wtap_rec *rec, Buffer
265 *buf, int *err, char **err_info) {
267 if (file_seek(wth->random_fh, offset, SEEK_SET, err) == -1) {
268 *err = file_error(wth->fh, err_info);
269 return false;
272 if (!ems_read_message(wth->random_fh, rec, buf, err, err_info)) {
273 return false;
276 return true;
279 static const struct supported_block_type ems_blocks_supported[] = {
280 { WTAP_BLOCK_PACKET, MULTIPLE_BLOCKS_SUPPORTED, NO_OPTIONS_SUPPORTED }
283 static const struct file_type_subtype_info ems_info = {
284 "EGNOS Message Server File Format", "ems", "ems", "ems",
285 false, BLOCKS_SUPPORTED(ems_blocks_supported),
286 NULL, NULL, NULL
289 void register_ems(void)
291 ems_file_type_subtype = wtap_register_file_type_subtype(&ems_info);
293 wtap_register_backwards_compatibility_lua_name("EMS",
294 ems_file_type_subtype);