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
17 #include "tap-rlc-graph.h"
21 #include <epan/epan_dissect.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
,
34 /* Same direction, data - OK. */
35 if (!frameIsControl
) {
36 return (direction1
== direction2
) &&
38 (channelType1
== channelType2
) &&
39 (channelId1
== channelId2
) &&
40 (rlcMode1
== rlcMode2
);
44 if ((rlcMode1
== RLC_AM_MODE
) && (rlcMode2
== RLC_AM_MODE
)) {
45 return ((direction1
!= direction2
) &&
47 (channelType1
== channelType2
) &&
48 (channelId1
== channelId2
));
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_
)
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
)) {
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
;
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
,
109 GString
*error_string
;
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
) {
118 /* No real filter yet */
119 if (!dfilter_compile("rlc-lte or rlc-nr", &sfcode
, 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
);
136 fprintf(stderr
, "wireshark: Couldn't register rlc_lte_graph tap: %s\n",
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");
158 /* XXX fix this later, we should show a dialog allowing the user
159 * to select which session he wants here */
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.");
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
) {
218 segment
->SN
= rlchdr
->sequenceNumber
;
219 segment
->isResegmented
= rlchdr
->isResegmented
;
220 segment
->pduLength
= rlchdr
->pduLength
;
223 /* No sequence number, so not going to show at all */
225 return TAP_PACKET_DONT_REDRAW
; /* i.e. no immediate redraw requested */
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
;
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
,
259 struct rlc_segment current
;
260 GString
*error_string
;
263 /* Really shouldn't happen */
268 struct rlc_3gpp_tap_info
*header
= select_rlc_lte_session(cf
, ¤t
, err_string
);
270 /* Didn't have a channel, and current frame didn't provide one */
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
);
295 fprintf(stderr
, "wireshark: Couldn't register rlc_graph tap: %s\n",
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");
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
;
320 g
->segments
= segment
;