sync epan/dissectors/pidl/drsuapi/drsuapi.idl
[wireshark-sm.git] / ui / tap-rlc-graph.c
blobb8424ba21a311d032e3204889042168de630672e
1 /* tap-rlc-graph.c
2 * LTE RLC channel graph info
4 * Originally from tcp_graph.c by Pavel Mores <pvl@uh.cz>
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"
15 #include <stdlib.h>
17 #include "tap-rlc-graph.h"
19 #include <file.h>
21 #include <epan/epan_dissect.h>
22 #include <epan/tap.h>
24 /* Return true if the 2 sets of parameters refer to the same channel. */
25 bool compare_rlc_headers(uint8_t rat1, uint8_t rat2,
26 uint16_t ueid1, uint16_t channelType1, uint16_t channelId1, uint8_t rlcMode1, uint8_t direction1,
27 uint16_t ueid2, uint16_t channelType2, uint16_t channelId2, uint8_t rlcMode2, uint8_t direction2,
28 bool frameIsControl)
30 if (rat1 != rat2) {
31 return false;
34 /* Same direction, data - OK. */
35 if (!frameIsControl) {
36 return (direction1 == direction2) &&
37 (ueid1 == ueid2) &&
38 (channelType1 == channelType2) &&
39 (channelId1 == channelId2) &&
40 (rlcMode1 == rlcMode2);
42 else {
43 /* Control case */
44 if ((rlcMode1 == RLC_AM_MODE) && (rlcMode2 == RLC_AM_MODE)) {
45 return ((direction1 != direction2) &&
46 (ueid1 == ueid2) &&
47 (channelType1 == channelType2) &&
48 (channelId1 == channelId2));
50 else {
51 return false;
56 /* This is the tap function used to identify a list of channels found in the current frame. It is only used for the single,
57 currently selected frame. */
58 static tap_packet_status
59 tap_lte_rlc_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip, tap_flags_t flags _U_)
61 int n;
62 bool is_unique = true;
63 th_t *th = (th_t *)pct;
64 const rlc_3gpp_tap_info *header = (const rlc_3gpp_tap_info*)vip;
66 /* Check new header details against any/all stored ones */
67 for (n=0; n < th->num_hdrs; n++) {
68 rlc_3gpp_tap_info *stored = th->rlchdrs[n];
70 if (compare_rlc_headers(stored->rat, header->rat,
71 stored->ueid, stored->channelType, stored->channelId, stored->rlcMode, stored->direction,
72 header->ueid, header->channelType, header->channelId, header->rlcMode, header->direction,
73 header->isControlPDU)) {
74 is_unique = false;
75 break;
79 /* Add address if unique and have space for it */
80 if (is_unique && (th->num_hdrs < MAX_SUPPORTED_CHANNELS)) {
81 /* Copy the tap struct in as next header */
82 /* Need to take a deep copy of the tap struct, it may not be valid
83 to read after this function returns? */
84 th->rlchdrs[th->num_hdrs] = g_new(rlc_3gpp_tap_info,1);
85 *(th->rlchdrs[th->num_hdrs]) = *header;
87 /* Store in direction of data though... */
88 if (th->rlchdrs[th->num_hdrs]->isControlPDU) {
89 th->rlchdrs[th->num_hdrs]->direction = !th->rlchdrs[th->num_hdrs]->direction;
91 th->num_hdrs++;
94 return TAP_PACKET_DONT_REDRAW; /* i.e. no immediate redraw requested */
97 /* Return an array of tap_info structs that were found while dissecting the current frame
98 * in the packet list. Errors are passed back to the caller, as they will be reported differently
99 * depending upon which GUI toolkit is being used. */
100 rlc_3gpp_tap_info* select_rlc_lte_session(capture_file *cf,
101 struct rlc_segment *hdrs,
102 char **err_msg)
104 frame_data *fdata;
105 wtap_rec rec;
106 epan_dissect_t edt;
107 dfilter_t *sfcode;
109 GString *error_string;
110 nstime_t rel_ts;
111 /* Initialised to no known channels */
112 th_t th = {0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};
114 if (cf->state == FILE_CLOSED) {
115 return NULL;
118 /* No real filter yet */
119 if (!dfilter_compile("rlc-lte or rlc-nr", &sfcode, NULL)) {
120 return NULL;
123 fdata = cf->current_frame;
125 /* Dissect the data from the current frame. */
126 wtap_rec_init(&rec, 1514);
127 if (!cf_read_current_record(cf)) {
128 dfilter_free(sfcode);
129 wtap_rec_cleanup(&rec);
130 return NULL; /* error reading the record */
133 /* Set tap listener that will populate th. */
134 error_string = register_tap_listener("rlc-3gpp", &th, NULL, 0, NULL, tap_lte_rlc_packet, NULL, NULL);
135 if (error_string){
136 fprintf(stderr, "wireshark: Couldn't register rlc_lte_graph tap: %s\n",
137 error_string->str);
138 g_string_free(error_string, TRUE);
139 dfilter_free(sfcode);
140 exit(1); /* XXX: fix this */
143 epan_dissect_init(&edt, cf->epan, true, false);
144 epan_dissect_prime_with_dfilter(&edt, sfcode);
145 epan_dissect_run_with_taps(&edt, cf->cd_t, &cf->rec, fdata, NULL);
146 rel_ts = edt.pi.rel_ts;
147 epan_dissect_cleanup(&edt);
148 remove_tap_listener(&th);
150 if (th.num_hdrs == 0){
151 /* This "shouldn't happen", as the graph menu items won't
152 * even be enabled if the selected packet isn't an RLC PDU.
154 wtap_rec_cleanup(&rec);
155 *err_msg = g_strdup("Selected packet doesn't have an RLC PDU");
156 return NULL;
158 /* XXX fix this later, we should show a dialog allowing the user
159 * to select which session he wants here */
160 if (th.num_hdrs>1){
161 /* Can only handle a single RLC channel yet */
162 wtap_rec_cleanup(&rec);
163 *err_msg = g_strdup("The selected packet has more than one LTE RLC channel in it.");
164 return NULL;
167 /* For now, still always choose the first/only one */
168 hdrs->num = fdata->num;
169 hdrs->rel_secs = rel_ts.secs;
170 hdrs->rel_usecs = rel_ts.nsecs/1000;
172 hdrs->rat = th.rlchdrs[0]->rat;
173 hdrs->ueid = th.rlchdrs[0]->ueid;
174 hdrs->channelType = th.rlchdrs[0]->channelType;
175 hdrs->channelId = th.rlchdrs[0]->channelId;
176 hdrs->rlcMode = th.rlchdrs[0]->rlcMode;
177 hdrs->isControlPDU = th.rlchdrs[0]->isControlPDU;
178 /* Flip direction if have control PDU */
179 hdrs->direction = !hdrs->isControlPDU ? th.rlchdrs[0]->direction : !th.rlchdrs[0]->direction;
181 wtap_rec_cleanup(&rec);
183 return th.rlchdrs[0];
186 /* This is the tapping function to update stats when dissecting the whole packet list */
187 static tap_packet_status rlc_lte_tap_for_graph_data(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip, tap_flags_t flags _U_)
189 struct rlc_graph *graph = (struct rlc_graph *)pct;
190 const rlc_3gpp_tap_info *rlchdr = (const rlc_3gpp_tap_info*)vip;
192 /* See if this one matches graph's channel */
193 if (compare_rlc_headers(graph->rat, rlchdr->rat,
194 graph->ueid, graph->channelType, graph->channelId, graph->rlcMode, graph->direction,
195 rlchdr->ueid, rlchdr->channelType, rlchdr->channelId, rlchdr->rlcMode, rlchdr->direction,
196 rlchdr->isControlPDU)) {
198 /* It matches. Copy segment details out of tap struct */
199 struct rlc_segment *segment = g_new(struct rlc_segment, 1);
200 segment->next = NULL;
201 segment->num = pinfo->num;
202 segment->rel_secs = (uint32_t) pinfo->rel_ts.secs;
203 segment->rel_usecs = pinfo->rel_ts.nsecs/1000;
205 segment->rat = rlchdr->rat;
206 segment->ueid = rlchdr->ueid;
207 segment->channelType = rlchdr->channelType;
208 segment->channelId = rlchdr->channelId;
209 segment->direction = rlchdr->direction;
210 segment->rlcMode = rlchdr->rlcMode;
211 segment->sequenceNumberLength = rlchdr->sequenceNumberLength;
213 segment->isControlPDU = rlchdr->isControlPDU;
215 if (!rlchdr->isControlPDU) {
216 if (rlchdr->sequenceNumberGiven) {
217 /* Data */
218 segment->SN = rlchdr->sequenceNumber;
219 segment->isResegmented = rlchdr->isResegmented;
220 segment->pduLength = rlchdr->pduLength;
222 else {
223 /* No sequence number, so not going to show at all */
224 g_free(segment);
225 return TAP_PACKET_DONT_REDRAW; /* i.e. no immediate redraw requested */
228 else {
229 /* Status PDU */
230 int n;
231 segment->ACKNo = rlchdr->ACKNo;
232 segment->noOfNACKs = rlchdr->noOfNACKs;
233 for (n=0; (n < rlchdr->noOfNACKs) && (n < MAX_NACKs); n++) {
234 segment->NACKs[n] = rlchdr->NACKs[n];
238 /* Add segment to end of list */
239 if (graph->segments) {
240 /* Add to end of existing last element */
241 graph->last_segment->next = segment;
242 } else {
243 /* Make this the first (only) segment */
244 graph->segments = segment;
247 /* This one is now the last one */
248 graph->last_segment = segment;
251 return TAP_PACKET_DONT_REDRAW; /* i.e. no immediate redraw requested */
254 /* If don't have a channel, try to get one from current frame, then read all frames looking for data
255 * for that channel. */
256 bool rlc_graph_segment_list_get(capture_file *cf, struct rlc_graph *g, bool stream_known,
257 char **err_string)
259 struct rlc_segment current;
260 GString *error_string;
262 if (!cf || !g) {
263 /* Really shouldn't happen */
264 return false;
267 if (!stream_known) {
268 struct rlc_3gpp_tap_info *header = select_rlc_lte_session(cf, &current, err_string);
269 if (!header) {
270 /* Didn't have a channel, and current frame didn't provide one */
271 return false;
273 g->channelSet = true;
275 g->rat = header->rat;
276 g->ueid = header->ueid;
277 g->channelType = header->channelType;
278 g->channelId = header->channelId;
279 g->rlcMode = header->rlcMode;
280 g->direction = header->direction;
284 /* Rescan all the packets and pick up all interesting RLC headers.
285 * We only filter for RLC frames here for speed and do the actual compare
286 * in the tap listener
289 g->last_segment = NULL;
290 error_string = register_tap_listener("rlc-3gpp", // tap name
292 "rlc-lte or rlc-nr", // filter name
293 0, NULL, rlc_lte_tap_for_graph_data, NULL, NULL);
294 if (error_string) {
295 fprintf(stderr, "wireshark: Couldn't register rlc_graph tap: %s\n",
296 error_string->str);
297 g_string_free(error_string, TRUE);
298 exit(1); /* XXX: fix this */
300 cf_retap_packets(cf);
301 remove_tap_listener(g);
303 if (g->last_segment == NULL) {
304 *err_string = g_strdup("No packets found");
305 return false;
308 return true;
311 /* Free and zero the segments list of an rlc_graph struct */
312 void rlc_graph_segment_list_free(struct rlc_graph * g)
314 struct rlc_segment *segment;
316 /* Free all segments */
317 while (g->segments) {
318 segment = g->segments->next;
319 g_free(g->segments);
320 g->segments = segment;