nexmon – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /* tap-rlc-stream.c
2 * LTE RLC stream statistics
3 *
4 * Originally from tcp_graph.c by Pavel Mores <pvl@uh.cz>
5 * Win32 port: rwh@unifiedtech.com
6 *
7 * Wireshark - Network traffic analyzer
8 * By Gerald Combs <gerald@wireshark.org>
9 * Copyright 1998 Gerald Combs
10 *
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU General Public License
13 * as published by the Free Software Foundation; either version 2
14 * of the License, or (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 */
25  
26 #include "config.h"
27  
28 #include <stdlib.h>
29  
30 #include "tap-rlc-graph.h"
31  
32 #include <file.h>
33 #include <frame_tvbuff.h>
34  
35 #include <epan/epan.h>
36 #include <epan/epan_dissect.h>
37 #include <epan/packet.h>
38 #include <epan/tap.h>
39  
40 /* Return TRUE if the 2 sets of parameters refer to the same channel. */
41 int compare_rlc_headers(guint16 ueid1, guint16 channelType1, guint16 channelId1, guint8 rlcMode1, guint8 direction1,
42 guint16 ueid2, guint16 channelType2, guint16 channelId2, guint8 rlcMode2, guint8 direction2,
43 gboolean frameIsControl)
44 {
45 /* Same direction, data - OK. */
46 if (!frameIsControl) {
47 return (direction1 == direction2) &&
48 (ueid1 == ueid2) &&
49 (channelType1 == channelType2) &&
50 (channelId1 == channelId2) &&
51 (rlcMode1 == rlcMode2);
52 }
53 else {
54 if (frameIsControl && (rlcMode1 == RLC_AM_MODE) && (rlcMode2 == RLC_AM_MODE)) {
55 return ((direction1 != direction2) &&
56 (ueid1 == ueid2) &&
57 (channelType1 == channelType2) &&
58 (channelId1 == channelId2));
59 }
60 else {
61 return FALSE;
62 }
63 }
64 }
65  
66 /* This is the tap function used to identify a list of channels found in the current frame. It is only used for the single,
67 currently selected frame. */
68 static int
69 tap_lte_rlc_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip)
70 {
71 int n;
72 gboolean is_unique = TRUE;
73 th_t *th = (th_t *)pct;
74 const rlc_lte_tap_info *header = (const rlc_lte_tap_info*)vip;
75  
76 /* Check new header details against any/all stored ones */
77 for (n=0; n < th->num_hdrs; n++) {
78 rlc_lte_tap_info *stored = th->rlchdrs[n];
79  
80 if (compare_rlc_headers(stored->ueid, stored->channelType, stored->channelId, stored->rlcMode, stored->direction,
81 header->ueid, header->channelType, header->channelId, header->rlcMode, header->direction,
82 header->isControlPDU)) {
83 is_unique = FALSE;
84 break;
85 }
86 }
87  
88 /* Add address if unique and have space for it */
89 if (is_unique && (th->num_hdrs < MAX_SUPPORTED_CHANNELS)) {
90 /* Copy the tap stuct in as next header */
91 /* Need to take a deep copy of the tap struct, it may not be valid
92 to read after this function returns? */
93 th->rlchdrs[th->num_hdrs] = g_new(rlc_lte_tap_info,1);
94 *(th->rlchdrs[th->num_hdrs]) = *header;
95  
96 /* Store in direction of data though... */
97 if (th->rlchdrs[th->num_hdrs]->isControlPDU) {
98 th->rlchdrs[th->num_hdrs]->direction = !th->rlchdrs[th->num_hdrs]->direction;
99 }
100 th->num_hdrs++;
101 }
102  
103 return 0;
104 }
105  
106 /* Return an array of tap_info structs that were found while dissecting the current frame
107 * in the packet list. Errors are passed back to the caller, as they will be reported differently
108 * depending upon which GUI toolkit is being used. */
109 rlc_lte_tap_info *select_rlc_lte_session(capture_file *cf,
110 struct rlc_segment *hdrs,
111 gchar **err_msg)
112 {
113 frame_data *fdata;
114 epan_dissect_t edt;
115 dfilter_t *sfcode;
116  
117 GString *error_string;
118 nstime_t rel_ts;
119 /* Initialised to no known channels */
120 th_t th = {0, {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}};
121  
122 if (cf->state == FILE_CLOSED) {
123 return NULL;
124 }
125  
126 fdata = cf->current_frame;
127  
128 /* No real filter yet */
129 if (!dfilter_compile("rlc-lte", &sfcode, err_msg)) {
130 return NULL;
131 }
132  
133 /* Dissect the data from the current frame. */
134 if (!cf_read_record(cf, fdata)) {
135 return NULL; /* error reading the record */
136 }
137  
138 /* Set tap listener that will populate th. */
139 error_string = register_tap_listener("rlc-lte", &th, NULL, 0, NULL, tap_lte_rlc_packet, NULL);
140 if (error_string){
141 fprintf(stderr, "wireshark: Couldn't register rlc_lte_graph tap: %s\n",
142 error_string->str);
143 g_string_free(error_string, TRUE);
144 exit(1); /* XXX: fix this */
145 }
146  
147 epan_dissect_init(&edt, cf->epan, TRUE, FALSE);
148 epan_dissect_prime_dfilter(&edt, sfcode);
149 epan_dissect_run_with_taps(&edt, cf->cd_t, &cf->phdr, frame_tvbuff_new_buffer(fdata, &cf->buf), fdata, NULL);
150 rel_ts = edt.pi.rel_ts;
151 epan_dissect_cleanup(&edt);
152 remove_tap_listener(&th);
153  
154 if (th.num_hdrs == 0){
155 /* This "shouldn't happen", as the graph menu items won't
156 * even be enabled if the selected packet isn't an RLC PDU.
157 */
158 *err_msg = g_strdup("Selected packet doesn't have an RLC PDU");
159 return NULL;
160 }
161 /* XXX fix this later, we should show a dialog allowing the user
162 * to select which session he wants here */
163 if (th.num_hdrs>1){
164 /* Can only handle a single RLC channel yet */
165 *err_msg = g_strdup("The selected packet has more than one LTE RLC channel in it.");
166 return NULL;
167 }
168  
169 /* For now, still always choose the first/only one */
170 hdrs->num = fdata->num;
171 hdrs->rel_secs = (guint32) rel_ts.secs;
172 hdrs->rel_usecs = rel_ts.nsecs/1000;
173 hdrs->abs_secs = (guint32) fdata->abs_ts.secs;
174 hdrs->abs_usecs = fdata->abs_ts.nsecs/1000;
175  
176 hdrs->ueid = th.rlchdrs[0]->ueid;
177 hdrs->channelType = th.rlchdrs[0]->channelType;
178 hdrs->channelId = th.rlchdrs[0]->channelId;
179 hdrs->rlcMode = th.rlchdrs[0]->rlcMode;
180 hdrs->isControlPDU = th.rlchdrs[0]->isControlPDU;
181 hdrs->direction = !hdrs->isControlPDU ? th.rlchdrs[0]->direction : !th.rlchdrs[0]->direction;
182  
183 return th.rlchdrs[0];
184 }
185  
186 /* This is the tapping function to update stats when dissecting the whole packet list */
187 int rlc_lte_tap_for_graph_data(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
188 {
189 struct rlc_graph *graph = (struct rlc_graph *)pct;
190 const rlc_lte_tap_info *rlchdr = (const rlc_lte_tap_info*)vip;
191  
192 /* See if this one matches current channel */
193 if (compare_rlc_headers(graph->ueid, graph->channelType, graph->channelId, graph->rlcMode, graph->direction,
194 rlchdr->ueid, rlchdr->channelType, rlchdr->channelId, rlchdr->rlcMode, rlchdr->direction,
195 rlchdr->isControlPDU)) {
196  
197 struct rlc_segment *segment = (struct rlc_segment *)g_malloc(sizeof(struct rlc_segment));
198  
199 /* It matches. Add to end of segment list */
200 segment->next = NULL;
201 segment->num = pinfo->num;
202 segment->rel_secs = (guint32) pinfo->rel_ts.secs;
203 segment->rel_usecs = pinfo->rel_ts.nsecs/1000;
204 segment->abs_secs = (guint32) pinfo->abs_ts.secs;
205 segment->abs_usecs = pinfo->abs_ts.nsecs/1000;
206  
207 segment->ueid = rlchdr->ueid;
208 segment->channelType = rlchdr->channelType;
209 segment->channelId = rlchdr->channelId;
210 segment->direction = rlchdr->direction;
211 segment->rlcMode = rlchdr->rlcMode;
212  
213 segment->isControlPDU = rlchdr->isControlPDU;
214  
215 if (!rlchdr->isControlPDU) {
216 /* Data */
217 segment->SN = rlchdr->sequenceNumber;
218 segment->isResegmented = rlchdr->isResegmented;
219 segment->pduLength = rlchdr->pduLength;
220 }
221 else {
222 /* Status PDU */
223 gint n;
224 segment->ACKNo = rlchdr->ACKNo;
225 segment->noOfNACKs = rlchdr->noOfNACKs;
226 for (n=0; n < rlchdr->noOfNACKs; n++) {
227 segment->NACKs[n] = rlchdr->NACKs[n];
228 }
229 }
230  
231 /* Add to list */
232 if (graph->segments) {
233 /* Add to end of existing last element */
234 graph->last_segment->next = segment;
235 } else {
236 /* Make this the first (only) segment */
237 graph->segments = segment;
238 }
239  
240 /* This one is now the last one */
241 graph->last_segment = segment;
242 }
243  
244 return 0;
245 }
246  
247 /* If don't have a channel, try to get one from current frame, then read all frames looking for data
248 * for that channel. */
249 gboolean rlc_graph_segment_list_get(capture_file *cf, struct rlc_graph *g, gboolean stream_known,
250 char **err_string)
251 {
252 struct rlc_segment current;
253 GString *error_string;
254  
255 g_log(NULL, G_LOG_LEVEL_DEBUG, "graph_segment_list_get()");
256  
257 if (!cf || !g) {
258 /* Really shouldn't happen */
259 return FALSE;
260 }
261  
262 if (!stream_known) {
263 struct rlc_lte_tap_info *header = select_rlc_lte_session(cf, &current, err_string);
264 if (!header) {
265 /* Didn't have a channel, and current frame didn't provide one */
266 return FALSE;
267 }
268 g->channelSet = TRUE;
269 g->ueid = header->ueid;
270 g->channelType = header->channelType;
271 g->channelId = header->channelId;
272 g->rlcMode = header->rlcMode;
273 g->direction = header->direction;
274 }
275  
276  
277 /* rescan all the packets and pick up all interesting RLC headers.
278 * we only filter for rlc-lte here for speed and do the actual compare
279 * in the tap listener
280 */
281  
282 g->last_segment = NULL;
283 error_string = register_tap_listener("rlc-lte", g, "rlc-lte", 0, NULL, rlc_lte_tap_for_graph_data, NULL);
284 if (error_string) {
285 fprintf(stderr, "wireshark: Couldn't register rlc_graph tap: %s\n",
286 error_string->str);
287 g_string_free(error_string, TRUE);
288 exit(1); /* XXX: fix this */
289 }
290 cf_retap_packets(cf);
291 remove_tap_listener(g);
292  
293 if (g->last_segment == NULL) {
294 *err_string = g_strdup("No packets found");
295 return FALSE;
296 }
297  
298 return TRUE;
299 }
300  
301 /* Free and zero the segments list of an rlc_graph struct */
302 void rlc_graph_segment_list_free(struct rlc_graph * g)
303 {
304 struct rlc_segment *segment;
305  
306 /* Free all segments */
307 while (g->segments) {
308 segment = g->segments->next;
309 g_free(g->segments);
310 g->segments = segment;
311 }
312 /* Set head of list to NULL too */
313 g->segments = NULL;
314 }