proto_get_frame_protocols(const wmem_list_t *layers, gboolean *is_ip,
gboolean *is_tcp, gboolean *is_udp,
gboolean *is_sctp, gboolean *is_ssl,
- gboolean *is_rtp)
+ gboolean *is_rtp,
+ gboolean *is_lte_rlc)
{
wmem_list_frame_t *protos = wmem_list_head(layers);
int proto_id;
*is_ssl = TRUE;
} else if (is_rtp && !strcmp(proto_name, "rtp")) {
*is_rtp = TRUE;
- }
+ } else if (is_lte_rlc && !strcmp(proto_name, "rlc-lte")) {
+ *is_lte_rlc = TRUE;
+ }
protos = wmem_list_frame_next(protos);
}
* unchanged. May be NULL.
* @param is_ssl Set to TRUE if the layer list contains SSL/TLS, otherwise
* unchanged. May be NULL.
+ * @param is_rtp Set to TRUE if the layer list contains RTP, otherwise
+ * unchanged. May be NULL.
+ * @param is_lte_rlc Set to TRUE if the layer list contains LTE RLC, otherwise
+ * unchanged. May be NULL.
*/
WS_DLL_PUBLIC void proto_get_frame_protocols(const wmem_list_t *layers,
gboolean *is_ip, gboolean *is_tcp, gboolean *is_udp, gboolean *is_sctp,
- gboolean *is_ssl, gboolean *is_rtp);
+ gboolean *is_ssl, gboolean *is_rtp, gboolean *is_lte_rlc);
/** Find a protocol by name in a layer list.
* @param layers Protocol layer list
gboolean properties = FALSE;
const char *abbrev = NULL;
char *prev_abbrev;
- gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_sctp = FALSE, is_ssl = FALSE;
+ gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_sctp = FALSE, is_ssl = FALSE, is_lte_rlc = FALSE;
/* Making the menu context-sensitive allows for easier selection of the
desired item and has the added benefit, with large captures, of
than one time reference frame or the current frame isn't a
time reference frame). (XXX - why check frame_selected?) */
if (cf->edt)
- proto_get_frame_protocols(cf->edt->pi.layers, &is_ip, &is_tcp, &is_udp, &is_sctp, &is_ssl, NULL);
+ proto_get_frame_protocols(cf->edt->pi.layers, &is_ip, &is_tcp, &is_udp, &is_sctp, &is_ssl, NULL, &is_lte_rlc);
if (cf->edt && cf->edt->tree) {
GPtrArray *ga;
frame_selected);
set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/StatisticsMenu/TCPStreamGraphMenu",
is_tcp);
+ set_menu_sensitivity(ui_manager_main_menubar, "/Menubar/TelephonyMenu/LTEmenu/LTE_RLC_Graph",
+ is_lte_rlc);
while (list_entry != NULL) {
dissector_filter_t *filter_entry;
return false;
}
- proto_get_frame_protocols(cap_file_.capFile()->edt->pi.layers, NULL, &is_tcp, &is_udp, NULL, NULL, NULL);
+ proto_get_frame_protocols(cap_file_.capFile()->edt->pi.layers, NULL, &is_tcp, &is_udp, NULL, NULL, NULL, NULL);
switch (follow_type_)
{
#include "qt_ui_utils.h"
#include "wireshark_application.h"
-// To do:
-// - Add missing controls (RACH, SR checkboxes)
// Whole-UE headings.
enum {
setText(col_type_, type_ == C_RNTI ? QObject::tr("C-RNTI") : QObject::tr("SPS-RNTI"));
setText(col_ueid_, QString::number(ueid_));
- // TODO: OK to do this here?
+ // Add UL/DL packet/byte count subitems.
addDetails();
}
// Update this UE according to the tap info
void update(const mac_lte_tap_info *mlt_info) {
- // Update stats for this UE.
// Uplink.
if (mlt_info->direction == DIRECTION_UPLINK) {
ul_raw_bytes_ += mlt_info->raw_length;
ul_padding_bytes_ += mlt_info->padding_bytes;
- // N.B. Not going to support predefined data in Qt version.
+ // N.B. Not going to support predefined data in Qt version..
if (!mlt_info->isPredefinedData) {
for (int n=0; n < 11; n++) {
// Update UL child items
dl_raw_bytes_ += mlt_info->raw_length;
dl_padding_bytes_ += mlt_info->padding_bytes;
- // N.B. Not going to support predefined data in Qt version.
+ // N.B. Not going to support predefined data in Qt version..
if (!mlt_info->isPredefinedData) {
for (int n=0; n < 11; n++) {
// Update DL child items
(((double)stop_time->nsecs - (double)start_time->nsecs) / 1000000);
// Only really meaningful if have a few frames spread over time...
- // For now at least avoid dividing by something very close to 0.0
+ // For now at least avoid dividing by something very close to 0.0
if (elapsed_ms < 2.0) {
return 0.0f;
}
}
}
+ // Draw this UE.
void draw() {
// Fixed fields (rnti, type, ueid) won't change during lifetime of UE entry.
setText(col_dl_crc_failed_, QString::number(dl_crc_failed_));
setText(col_dl_retx_, QString::number(dl_retx_));
- // Draw child items with channel counts.
+ // Draw child items with per-channel counts.
ul_frames_item_->draw();
ul_bytes_item_->draw();
dl_frames_item_->draw();
QCheckBox *showSRFilterCheckBox_;
QCheckBox *showRACHFilterCheckBox_;
- mac_lte_common_stats commonStats_;
- bool commonStatsCurrent_;
-
// Callbacks for register_tap_listener
static void tapReset(void *ws_dlg_ptr);
static gboolean tapPacket(void *ws_dlg_ptr, struct _packet_info *, struct epan_dissect *, const void *mac_lte_tap_info_ptr);
virtual const QString filterExpression();
+ // Common stats.
+ mac_lte_common_stats commonStats_;
+ bool commonStatsCurrent_; // TODO: may not be worth it.
void updateCommonStats(const struct mac_lte_tap_info *mlt_info);
void drawCommonStats();
void clearCommonStats();
#include <ui/tap-rlc-graph.h>
// TODO:
-// - better handling of zooming (select area like TCP and/or Jim's patch for 1 dimension at a time)
-// - how to avoid panning or zooming out to -ve (x or y axis)
const QRgb graph_color_ack = tango_sky_blue_4; // Blue for ACK lines
const QRgb graph_color_nack = tango_scarlet_red_3; // Red for NACKs
if (free_err_string) {
g_free(err_string);
}
+ return;
}
// Reconnect mouse move signal.
sp->graph(i)->setVisible(true);
}
- // NACKs are shown bigger than others.
+ // N.B. ssDisc is really too slow. TODO: work out how to turn off aliasing, or experiment
+ // with ssCustom. Other styles tried didn't look right.
+ // GTK version was speeded up noticibly by turning down aliasing level...
base_graph_->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, pkt_point_size_));
reseg_graph_->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, pkt_point_size_));
acks_graph_->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, pkt_point_size_));
+ // NACKs are shown bigger than others.
nacks_graph_->setScatterStyle(QCPScatterStyle(QCPScatterStyle::ssDisc, pkt_point_size_*2));
// Map timestamps -> segments in first pass.
break;
case Qt::Key_Space:
-// toggleTracerStyle();
+ toggleTracerStyle(false);
break;
case Qt::Key_0:
tracer_->setVisible(true);
packet_num_ = packet_seg->num;
- hint += tr("%1 %2 (%3s seq %4)")
+ hint += tr("%1 %2 (%3s seq %4 len %5)")
.arg(cap_file_.capFile() ? tr("Click to select packet") : tr("Packet"))
.arg(packet_num_)
.arg(QString::number(packet_seg->rel_secs + packet_seg->rel_usecs / 1000000.0, 'g', 4))
- .arg(packet_seg->SN);
+ .arg(packet_seg->SN)
+ .arg(packet_seg->pduLength);
tracer_->setGraphKey(ui->rlcPlot->xAxis->pixelToCoord(event->pos().x()));
+ // Redrawing the whole graph is making the update *very* slow!
+ // TODO: Is there a way just to draw the parts that may have changed?
+ // In the GTK version, we displayed the stored pixbuf and draw temporary items on top...
rp->replot();
} else {
}
}
+void LteRlcGraphDialog::on_actionCrosshairs_triggered()
+{
+ toggleTracerStyle(false);
+}
+
void LteRlcGraphDialog::toggleTracerStyle(bool force_default)
{
- if (!tracer_->visible() && !force_default) return;
+ if (!tracer_->visible() && !force_default) {
+ return;
+ }
QPen sp_pen = ui->rlcPlot->graph(0)->pen();
QCPItemTracer::TracerStyle tstyle = QCPItemTracer::tsCrosshair;
void on_actionDragZoom_triggered();
void on_actionMoveUp100_triggered();
void on_actionMoveDown100_triggered();
-
void on_actionGoToPacket_triggered();
+ void on_actionCrosshairs_triggered();
};
#endif // LTE_RLC_GRAPH_DIALOG_H
#include "ui/recent.h"
+// TODO: have lost the ability to filter on only UL or DL of a channel.
+// - can we override the context menu inherited from TapParameterDialog?
enum {
col_ueid_,
case CHANNEL_TYPE_DRB:
setText(col_ueid_, QObject::tr("DRB-%1").arg(channelId));
break;
+
default:
setText(col_ueid_, QObject::tr("Unknown"));
break;
void update(const rlc_lte_tap_info *tap_info) {
// Copy these fields into UE stats.
- stats_.rlcMode = tap_info->rlcMode;
+ if (tap_info->rlcMode != stats_.rlcMode) {
+ stats_.rlcMode = tap_info->rlcMode;
+ // TODO: update the column string!
+ }
+
+ // TODO: these 2 really shouldn't change!!
stats_.channelType = tap_info->channelType;
stats_.channelId = tap_info->channelId;
+
if (tap_info->priority != 0) {
priority_ = tap_info->priority;
}
if (tap_info->direction == DIRECTION_UPLINK) {
- /* Update time range */
+ // Update time range.
if (stats_.UL_frames == 0) {
stats_.UL_time_start = tap_info->rlc_lte_time;
}
}
}
else {
- /* Update time range */
+ // Update time range.
if (stats_.DL_frames == 0) {
stats_.DL_time_start = tap_info->rlc_lte_time;
}
}
void draw() {
- /* Calculate bandwidth */
+ // Calculate bandwidth.
float UL_bw = calculate_bw(&stats_.UL_time_start,
&stats_.UL_time_stop,
stats_.UL_bytes);
}
// Accessors (queried for launching graph)
- unsigned get_ueid() { return ueid_; }
- unsigned get_channelType() { return channelType_; }
- unsigned get_channelId() { return channelId_; }
- unsigned get_mode() { return mode_; }
+ unsigned get_ueid() const { return ueid_; }
+ unsigned get_channelType() const { return channelType_; }
+ unsigned get_channelId() const { return channelId_; }
+ unsigned get_mode() const { return mode_; }
private:
unsigned ueid_;
{
ueid_ = rlt_info->ueid;
setText(col_ueid_, QString::number(ueid_));
- // We create RlcChannelTreeWidgetItems later
- // update when first data on new channel is seen.
+
+ // We create RlcChannelTreeWidgetItems when first data on new channel is seen.
// Of course, there will be a channel associated with the PDU
// that causes this UE item to be created...
-
memset(&stats_, 0, sizeof(stats_));
CCCH_stats_ = NULL;
for (int srb=0; srb < 2; srb++) {
}
bool isMatch(const rlc_lte_tap_info *rlt_info) {
- return (ueid_ == rlt_info->ueid);
+ return ueid_ == rlt_info->ueid;
}
// Update UE/channels from tap info.
// TODO: update title with number of UEs and frames like MAC does?
- // N.B. not expecting to see common stats - ignoring them.
+ // N.B. not really expecting to see common stats - ignoring them.
switch (tap_info->channelType) {
case CHANNEL_TYPE_BCCH_BCH:
case CHANNEL_TYPE_BCCH_DL_SCH:
return;
default:
+ // Drop through for UE-specific.
break;
}
stats_.UL_total_missing += tap_info->missingSNs;
}
else {
- /* Update time range */
+ // Update time range.
if (stats_.DL_frames == 0) {
stats_.DL_time_start = tap_info->rlc_lte_time;
}
setText(col_dl_nacks_, QString::number(stats_.DL_total_nacks));
setText(col_dl_missing_, QString::number(stats_.DL_total_missing));
- // Call draw() for each channel..
+ // Call draw() for each channel present.
if (CCCH_stats_ != NULL) {
CCCH_stats_->draw();
}
private:
unsigned ueid_;
-
rlc_ue_stats stats_;
+ // Channel counters stored in channel sub-items.
RlcChannelTreeWidgetItem* CCCH_stats_;
RlcChannelTreeWidgetItem* srb_stats_[2];
RlcChannelTreeWidgetItem* drb_stats_[32];
static const QString channel_col_2_title_ = QObject::tr("Priority");
+
+//------------------------------------------------------------------------------------------
+// Dialog
+
// Constructor.
LteRlcStatisticsDialog::LteRlcStatisticsDialog(QWidget &parent, CaptureFile &cf, const char *filter) :
TapParameterDialog(parent, cf, HELP_STATS_LTE_MAC_TRAFFIC_DIALOG),
void LteRlcStatisticsDialog::tapReset(void *ws_dlg_ptr)
{
LteRlcStatisticsDialog *ws_dlg = static_cast<LteRlcStatisticsDialog *>(ws_dlg_ptr);
- if (!ws_dlg) return;
+ if (!ws_dlg) {
+ return;
+ }
// Clears/deletes all UEs.
ws_dlg->statsTreeWidget()->clear();
ws_dlg->packet_count_ = 0;
}
+// Process the tap info from a dissected RLC PDU.
gboolean LteRlcStatisticsDialog::tapPacket(void *ws_dlg_ptr, struct _packet_info *, epan_dissect *, const void *rlc_lte_tap_info_ptr)
{
// Look up dialog.
enableGraphButtons = true;
}
- // Only enable graph buttons for channel entries.
+ // Only enabling graph buttons for channel entries.
launchULGraph_->setEnabled(enableGraphButtons);
launchDLGraph_->setEnabled(enableGraphButtons);
}
void MainWindow::setMenusForSelectedPacket()
{
- gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_sctp = FALSE, is_ssl = FALSE, is_rtp = FALSE;
+ gboolean is_ip = FALSE, is_tcp = FALSE, is_udp = FALSE, is_sctp = FALSE, is_ssl = FALSE, is_rtp = FALSE, is_lte_rlc = FALSE;
/* Making the menu context-sensitive allows for easier selection of the
desired item and has the added benefit, with large captures, of
if (capture_file_.capFile()->edt)
{
- proto_get_frame_protocols(capture_file_.capFile()->edt->pi.layers, &is_ip, &is_tcp, &is_udp, &is_sctp, &is_ssl, &is_rtp);
+ proto_get_frame_protocols(capture_file_.capFile()->edt->pi.layers,
+ &is_ip, &is_tcp, &is_udp, &is_sctp,
+ &is_ssl, &is_rtp, &is_lte_rlc);
}
}
main_ui_->actionSCTPShowAllAssociations->setEnabled(is_sctp);
main_ui_->actionSCTPFilterThisAssociation->setEnabled(is_sctp);
main_ui_->actionTelephonyRTPStreamAnalysis->setEnabled(is_rtp);
+ main_ui_->actionTelephonyLteRlcGraph->setEnabled(is_lte_rlc);
}
void MainWindow::setMenusForSelectedTreeRow(field_info *fi) {
#include <epan/packet.h>
#include <epan/tap.h>
-
+/* Return TRUE if the 2 sets of parameters refer to the same channel. */
int compare_rlc_headers(guint16 ueid1, guint16 channelType1, guint16 channelId1, guint8 rlcMode1, guint8 direction1,
- guint16 ueid2, guint16 channelType2, guint16 channelId2, guint8 rlcMode2, guint8 direction2,
- gboolean frameIsControl)
+ guint16 ueid2, guint16 channelType2, guint16 channelId2, guint8 rlcMode2, guint8 direction2,
+ gboolean frameIsControl)
{
/* Same direction, data - OK. */
if (!frameIsControl) {
}
}
-
+/* This is the tap function used to identify a list of channels found in the current frame. It is only used for the single,
+ currently selected frame. */
static int
tap_lte_rlc_packet(void *pct, packet_info *pinfo _U_, epan_dissect_t *edt _U_, const void *vip)
{
}
/* Return an array of tap_info structs that were found while dissecting the current frame
- in the packet list */
+ * in the packet list. Errors are passed back to the caller, as they will be reported differently
+ * depending upon which GUI toolkit is being used. */
rlc_lte_tap_info *select_rlc_lte_session(capture_file *cf,
struct rlc_segment *hdrs,
gchar **err_msg, gboolean *free_err_msg)
return NULL;
}
- /* Dissect the current record */
+ /* Dissect the data from the current frame. */
if (!cf_read_record(cf, fdata)) {
return NULL; /* error reading the record */
}
remove_tap_listener(&th);
if (th.num_hdrs == 0){
- /* This "shouldn't happen", as our menu items shouldn't
- * even be enabled if the selected packet isn't an RLC PDU
- * as rlc_lte_graph_selected_packet_enabled() is used
- * to determine whether to enable any of our menu items. */
+ /* This "shouldn't happen", as the graph menu items won't
+ * even be enabled if the selected packet isn't an RLC PDU.
+ */
*err_msg = (char*)"Selected packet doesn't have an RLC PDU";
*free_err_msg = FALSE;
return NULL;
}
/* XXX fix this later, we should show a dialog allowing the user
- to select which session he wants here
- */
+ * to select which session he wants here */
if (th.num_hdrs>1){
/* Can only handle a single RLC channel yet */
*err_msg = (char*)"The selected packet has more than one LTE RLC channel in it.";
return th.rlchdrs[0];
}
-
+/* This is the tapping function to update stats when dissecting the whole packet list */
int rlc_lte_tap_for_graph_data(void *pct, packet_info *pinfo, epan_dissect_t *edt _U_, const void *vip)
{
struct rlc_graph *graph = (struct rlc_graph *)pct;
/* Data */
segment->SN = rlchdr->sequenceNumber;
segment->isResegmented = rlchdr->isResegmented;
+ segment->pduLength = rlchdr->pduLength;
}
else {
/* Status PDU */
}
/* If don't have a channel, try to get one from current frame, then read all frames looking for data
- for that channel. */
+ * for that channel. */
gboolean rlc_graph_segment_list_get(capture_file *cf, struct rlc_graph *g, gboolean stream_known,
char **err_string, gboolean *free_err_string)
{
cf_retap_packets(cf);
remove_tap_listener(g);
+ if (g->last_segment == NULL) {
+ *err_string = (char*)"No packets found";
+ *free_err_string = FALSE;
+ return FALSE;
+ }
+
return TRUE;
}
#define MAX_NACKs 128
guint16 noOfNACKs;
guint16 NACKs[MAX_NACKs];
+ guint16 pduLength;
guint16 ueid;
guint16 channelType;