- Added TODO instruction comments to the sample protocol

- Implemented ICMP protocol builder
- Added #ifdefs to intcombobox.h to prevent multiple inclusion
This commit is contained in:
Srivats P. 2010-03-17 15:47:56 +00:00
parent f64d901729
commit 4dc3d2d7f9
9 changed files with 689 additions and 12 deletions

View File

@ -123,9 +123,8 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex,
// TODO(MED):
//! \todo Implement then enable these protocols - IPv6, ICMP, IGMP
//! \todo Implement then enable these protocols - IPv6, IGMP
rbL3Ipv6->setHidden(true);
rbL4Icmp->setHidden(true);
rbL4Igmp->setHidden(true);
//! \todo Enable navigation of streams
pbPrev->setDisabled(true);

400
common/icmp.cpp Normal file
View File

@ -0,0 +1,400 @@
#include <qendian.h>
#include "icmp.h"
IcmpConfigForm::IcmpConfigForm(QWidget *parent)
: QWidget(parent)
{
setupUi(this);
typeCombo->setValidator(new QIntValidator(0, 0xFF, this));
typeCombo->addItem(0, "Echo Reply");
typeCombo->addItem(3, "Destination Unreachable");
typeCombo->addItem(4, "Source Quench");
typeCombo->addItem(5, "Redirect");
typeCombo->addItem(8, "Echo Request");
typeCombo->addItem(11, "Time Exceeded");
typeCombo->addItem(12, "Parameter Problem");
typeCombo->addItem(13, "Timestamp Request");
typeCombo->addItem(14, "Timestamp Reply");
typeCombo->addItem(17, "Address Mask Request");
typeCombo->addItem(18, "Address Mask Reply");
idEdit->setValidator(new QIntValidator(0, 0xFFFF, this));
seqEdit->setValidator(new QIntValidator(0, 0xFFFF, this));
}
IcmpProtocol::IcmpProtocol(StreamBase *stream, AbstractProtocol *parent)
: AbstractProtocol(stream, parent)
{
configForm = NULL;
}
IcmpProtocol::~IcmpProtocol()
{
delete configForm;
}
AbstractProtocol* IcmpProtocol::createInstance(StreamBase *stream,
AbstractProtocol *parent)
{
return new IcmpProtocol(stream, parent);
}
quint32 IcmpProtocol::protocolNumber() const
{
return OstProto::Protocol::kIcmpFieldNumber;
}
void IcmpProtocol::protoDataCopyInto(OstProto::Protocol &protocol) const
{
protocol.MutableExtension(OstProto::icmp)->CopyFrom(data);
protocol.mutable_protocol_id()->set_id(protocolNumber());
}
void IcmpProtocol::protoDataCopyFrom(const OstProto::Protocol &protocol)
{
if (protocol.protocol_id().id() == protocolNumber() &&
protocol.HasExtension(OstProto::icmp))
data.MergeFrom(protocol.GetExtension(OstProto::icmp));
}
QString IcmpProtocol::name() const
{
return QString("Internet Control Message Protocol");
}
QString IcmpProtocol::shortName() const
{
return QString("ICMP");
}
quint32 IcmpProtocol::protocolId(ProtocolIdType type) const
{
switch(type)
{
case ProtocolIdIp: return 0x1;
default:break;
}
return AbstractProtocol::protocolId(type);
}
int IcmpProtocol::fieldCount() const
{
return icmp_fieldCount;
}
AbstractProtocol::FieldFlags IcmpProtocol::fieldFlags(int index) const
{
AbstractProtocol::FieldFlags flags;
flags = AbstractProtocol::fieldFlags(index);
switch (index)
{
case icmp_type:
case icmp_code:
break;
case icmp_checksum:
flags |= FieldIsCksum;
break;
case icmp_identifier:
case icmp_sequence:
break;
case icmp_is_override_checksum:
flags |= FieldIsMeta;
break;
default:
qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__,
index);
break;
}
return flags;
}
QVariant IcmpProtocol::fieldData(int index, FieldAttrib attrib,
int streamIndex) const
{
switch (index)
{
case icmp_type:
{
unsigned char type = data.type() & 0xFF;
switch(attrib)
{
case FieldName:
return QString("Type");
case FieldValue:
return type;
case FieldTextValue:
return QString("%1").arg((uint) type);
case FieldFrameValue:
return QByteArray(1, type);
default:
break;
}
break;
}
case icmp_code:
{
unsigned char code = data.code() & 0xFF;
switch(attrib)
{
case FieldName:
return QString("code");
case FieldValue:
return code;
case FieldTextValue:
return QString("%1").arg((uint)code);
case FieldFrameValue:
return QByteArray(1, code);
default:
break;
}
break;
}
case icmp_checksum:
{
quint16 cksum;
switch(attrib)
{
case FieldValue:
case FieldFrameValue:
case FieldTextValue:
if (data.is_override_checksum())
{
cksum = data.checksum();
}
else
{
quint16 cks;
quint32 sum = 0;
cks = protocolFrameCksum(streamIndex, CksumIp);
sum += (quint16) ~cks;
cks = protocolFramePayloadCksum(streamIndex, CksumIp);
sum += (quint16) ~cks;
while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);
cksum = (~sum) & 0xFFFF;
}
break;
default:
cksum = 0; // avoid the 'maybe used unitialized' warning
break;
}
printf("%s: attrib = %d, cksum = %d\n", __FUNCTION__, attrib, cksum);
switch(attrib)
{
case FieldName:
return QString("Checksum");
case FieldValue:
return cksum;
case FieldFrameValue:
{
QByteArray fv;
fv.resize(2);
qToBigEndian(cksum, (uchar*) fv.data());
return fv;
}
case FieldTextValue:
return QString("0x%1").arg(
cksum, 4, BASE_HEX, QChar('0'));;
case FieldBitSize:
return 16;
default:
break;
}
break;
}
case icmp_identifier:
{
switch(attrib)
{
case FieldName:
return QString("Identifier");
case FieldValue:
return data.identifier();
case FieldTextValue:
return QString("%1").arg(data.identifier());
case FieldFrameValue:
{
QByteArray fv;
fv.resize(2);
qToBigEndian((quint16) data.identifier(),
(uchar*) fv.data());
return fv;
}
default:
break;
}
break;
}
case icmp_sequence:
{
switch(attrib)
{
case FieldName:
return QString("Sequence");
case FieldValue:
return data.sequence();
case FieldTextValue:
return QString("%1").arg(data.sequence());
case FieldFrameValue:
{
QByteArray fv;
fv.resize(2);
qToBigEndian((quint16) data.sequence(), (uchar*) fv.data());
return fv;
}
default:
break;
}
break;
}
// Meta fields
case icmp_is_override_checksum:
{
switch(attrib)
{
case FieldValue:
return data.is_override_checksum();
default:
break;
}
break;
}
default:
qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__,
index);
break;
}
return AbstractProtocol::fieldData(index, attrib, streamIndex);
}
bool IcmpProtocol::setFieldData(int index, const QVariant &value,
FieldAttrib attrib)
{
bool isOk = false;
if (attrib != FieldValue)
goto _exit;
switch (index)
{
case icmp_type:
{
uint type = value.toUInt(&isOk);
if (isOk)
data.set_type(type & 0xFF);
break;
}
case icmp_code:
{
uint code = value.toUInt(&isOk);
if (isOk)
data.set_code(code & 0xFF);
break;
}
case icmp_checksum:
{
uint csum = value.toUInt(&isOk);
if (isOk)
data.set_checksum(csum);
break;
}
case icmp_identifier:
{
uint id = value.toUInt(&isOk);
if (isOk)
data.set_identifier(id);
break;
}
case icmp_sequence:
{
uint seq = value.toUInt(&isOk);
if (isOk)
data.set_sequence(seq);
break;
}
case icmp_is_override_checksum:
{
bool ovr = value.toBool();
data.set_is_override_checksum(ovr);
isOk = true;
break;
}
default:
qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__,
index);
break;
}
_exit:
return isOk;
}
QWidget* IcmpProtocol::configWidget()
{
if (configForm == NULL)
{
configForm = new IcmpConfigForm;
loadConfigWidget();
}
return configForm;
}
void IcmpProtocol::loadConfigWidget()
{
configWidget();
configForm->typeCombo->setValue(fieldData(icmp_type, FieldValue).toUInt());
configForm->codeEdit->setText(fieldData(icmp_code, FieldValue).toString());
configForm->overrideCksum->setChecked(
fieldData(icmp_is_override_checksum, FieldValue).toBool());
configForm->cksumEdit->setText(uintToHexStr(
fieldData(icmp_checksum, FieldValue).toUInt(), 2));
configForm->idEdit->setText(
fieldData(icmp_identifier, FieldValue).toString());
configForm->seqEdit->setText(
fieldData(icmp_sequence, FieldValue).toString());
}
void IcmpProtocol::storeConfigWidget()
{
bool isOk;
configWidget();
setFieldData(icmp_type, configForm->typeCombo->currentValue());
setFieldData(icmp_code, configForm->codeEdit->text());
setFieldData(icmp_is_override_checksum,
configForm->overrideCksum->isChecked());
setFieldData(icmp_checksum, configForm->cksumEdit->text().toUInt(&isOk, BASE_HEX));
setFieldData(icmp_identifier, configForm->idEdit->text());
setFieldData(icmp_sequence, configForm->seqEdit->text());
}

75
common/icmp.h Normal file
View File

@ -0,0 +1,75 @@
#ifndef _ICMP_H
#define _ICMP_H
#include "icmp.pb.h"
#include "ui_icmp.h"
#include "abstractprotocol.h"
/*
Icmp Protocol Frame Format -
+-----+------+------+-----+-----+
| TYP | CODE | CSUM | ID | SEQ |
| (1) | (1) | (2) | (2) | (2) |
+-----+------+------+-----+-----+
Figures in brackets represent field width in bytes
*/
class IcmpConfigForm : public QWidget, public Ui::Icmp
{
Q_OBJECT
public:
IcmpConfigForm(QWidget *parent = 0);
private slots:
};
class IcmpProtocol : public AbstractProtocol
{
private:
OstProto::Icmp data;
IcmpConfigForm *configForm;
enum icmpfield
{
// Frame Fields
icmp_type = 0,
icmp_code,
icmp_checksum,
icmp_identifier,
icmp_sequence,
// Meta Fields
icmp_is_override_checksum,
icmp_fieldCount
};
public:
IcmpProtocol(StreamBase *stream, AbstractProtocol *parent = 0);
virtual ~IcmpProtocol();
static AbstractProtocol* createInstance(StreamBase *stream,
AbstractProtocol *parent = 0);
virtual quint32 protocolNumber() const;
virtual void protoDataCopyInto(OstProto::Protocol &protocol) const;
virtual void protoDataCopyFrom(const OstProto::Protocol &protocol);
virtual quint32 protocolId(ProtocolIdType type) const;
virtual QString name() const;
virtual QString shortName() const;
virtual int fieldCount() const;
virtual AbstractProtocol::FieldFlags fieldFlags(int index) const;
virtual QVariant fieldData(int index, FieldAttrib attrib,
int streamIndex = 0) const;
virtual bool setFieldData(int index, const QVariant &value,
FieldAttrib attrib = FieldValue);
virtual QWidget* configWidget();
virtual void loadConfigWidget();
virtual void storeConfigWidget();
};
#endif

19
common/icmp.proto Normal file
View File

@ -0,0 +1,19 @@
import "protocol.proto";
package OstProto;
// Icmp Protocol
message Icmp {
optional bool is_override_checksum = 1;
optional uint32 type = 2 [default = 0x8]; // echo request
optional uint32 code = 3;
optional uint32 checksum = 4;
optional uint32 identifier = 5 [default = 1234];
optional uint32 sequence = 6;
}
extend Protocol {
optional Icmp icmp = 142;
}

144
common/icmp.ui Normal file
View File

@ -0,0 +1,144 @@
<ui version="4.0" >
<class>Icmp</class>
<widget class="QWidget" name="Icmp" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>258</width>
<height>168</height>
</rect>
</property>
<property name="windowTitle" >
<string>Form</string>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Type</string>
</property>
<property name="buddy" >
<cstring>typeCombo</cstring>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="IntComboBox" name="typeCombo" />
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Code</string>
</property>
<property name="buddy" >
<cstring>codeEdit</cstring>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLineEdit" name="codeEdit" />
</item>
<item row="2" column="0" >
<widget class="QCheckBox" name="overrideCksum" >
<property name="text" >
<string>Checksum</string>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLineEdit" name="cksumEdit" >
<property name="enabled" >
<bool>false</bool>
</property>
</widget>
</item>
<item row="2" column="2" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="0" >
<widget class="QLabel" name="label_4" >
<property name="text" >
<string>Identifier</string>
</property>
<property name="buddy" >
<cstring>idEdit</cstring>
</property>
</widget>
</item>
<item row="3" column="1" >
<widget class="QLineEdit" name="idEdit" />
</item>
<item row="4" column="0" >
<widget class="QLabel" name="label_5" >
<property name="text" >
<string>Sequence</string>
</property>
<property name="buddy" >
<cstring>seqEdit</cstring>
</property>
</widget>
</item>
<item row="4" column="1" >
<widget class="QLineEdit" name="seqEdit" />
</item>
<item row="5" column="1" >
<spacer>
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" >
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>IntComboBox</class>
<extends>QComboBox</extends>
<header>intcombobox.h</header>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>typeCombo</tabstop>
<tabstop>codeEdit</tabstop>
<tabstop>overrideCksum</tabstop>
<tabstop>cksumEdit</tabstop>
<tabstop>idEdit</tabstop>
<tabstop>seqEdit</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>overrideCksum</sender>
<signal>toggled(bool)</signal>
<receiver>cksumEdit</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>33</x>
<y>70</y>
</hint>
<hint type="destinationlabel" >
<x>96</x>
<y>71</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -1,3 +1,6 @@
#ifndef __INT_COMBO_BOX
#define __INT_COMBO_BOX
#include <QComboBox>
class IntComboBox : public QComboBox
@ -29,3 +32,5 @@ public:
setEditText(QString().setNum(value));
}
};
#endif

View File

@ -13,6 +13,7 @@ FORMS += \
vlan.ui \
arp.ui \
ip4.ui \
icmp.ui \
tcp.ui \
udp.ui \
userscript.ui \
@ -32,6 +33,7 @@ PROTOS += \
vlanstack.proto \
arp.proto \
ip4.proto \
icmp.proto \
tcp.proto \
udp.proto \
userscript.proto \
@ -56,6 +58,7 @@ HEADERS += \
vlanstack.h \
arp.h \
ip4.h \
icmp.h \
tcp.h \
udp.h \
userscript.h \
@ -76,6 +79,7 @@ SOURCES += \
svlan.cpp \
arp.cpp \
ip4.cpp \
icmp.cpp \
tcp.cpp \
udp.cpp \
userscript.cpp \

View File

@ -14,6 +14,7 @@
#include "vlanstack.h"
#include "arp.h"
#include "ip4.h"
#include "icmp.h"
#include "tcp.h"
#include "udp.h"
#include "userscript.h"
@ -52,6 +53,8 @@ ProtocolManager::ProtocolManager()
(void*) ArpProtocol::createInstance);
registerProtocol(OstProto::Protocol::kIp4FieldNumber,
(void*) Ip4Protocol::createInstance);
registerProtocol(OstProto::Protocol::kIcmpFieldNumber,
(void*) IcmpProtocol::createInstance);
registerProtocol(OstProto::Protocol::kTcpFieldNumber,
(void*) TcpProtocol::createInstance);
registerProtocol(OstProto::Protocol::kUdpFieldNumber,

View File

@ -54,7 +54,7 @@ QString SampleProtocol::shortName() const
}
/*!
Return the ProtocolIdType for your protocol \n
TODO Return the ProtocolIdType for your protocol \n
If your protocol doesn't have a protocolId field, you don't need to
reimplement this method - the base class implementation will do the
@ -66,7 +66,7 @@ AbstractProtocol::ProtocolIdType SampleProtocol::protocolIdType() const
}
/*!
Return the protocolId for your protoocol based on the 'type' requested \n
TODO Return the protocolId for your protoocol based on the 'type' requested \n
If not all types are valid for your protocol, handle the valid type(s)
and for the remaining fallback to the base class implementation; if your
@ -89,6 +89,11 @@ int SampleProtocol::fieldCount() const
return sample_fieldCount;
}
/*!
TODO Edit this function to return the appropriate flags for each field \n
See AbstractProtocol::FieldFlags for more info
*/
AbstractProtocol::FieldFlags SampleProtocol::fieldFlags(int index) const
{
AbstractProtocol::FieldFlags flags;
@ -123,6 +128,11 @@ AbstractProtocol::FieldFlags SampleProtocol::fieldFlags(int index) const
return flags;
}
/*!
TODO: Edit this function to return the data for each field
See AbstractProtocol::fieldData() for more info
*/
QVariant SampleProtocol::fieldData(int index, FieldAttrib attrib,
int streamIndex) const
{
@ -213,12 +223,11 @@ QVariant SampleProtocol::fieldData(int index, FieldAttrib attrib,
case FieldValue:
case FieldFrameValue:
case FieldTextValue:
{
if (data.is_override_checksum())
cksum = data.checksum();
else
cksum = protocolFrameCksum(streamIndex, CksumIp);
}
break;
default:
cksum = 0; // avoid the 'maybe used unitialized' warning
break;
@ -257,7 +266,9 @@ QVariant SampleProtocol::fieldData(int index, FieldAttrib attrib,
case FieldValue:
return data.x();
case FieldTextValue:
// Use the following line for display in decimal
return QString("%1").arg(data.x());
// Use the following line for display in hexa-decimal
//return QString("%1").arg(data.x(), 8, BASE_HEX, QChar('0'));
case FieldFrameValue:
{
@ -280,13 +291,15 @@ QVariant SampleProtocol::fieldData(int index, FieldAttrib attrib,
case FieldValue:
return data.y();
case FieldTextValue:
// Use the following line for display in decimal
//return QString("%1").arg(data.y());
return QString("%1").arg(data.y(), 8, BASE_HEX, QChar('0'));
// Use the following line for display in hexa-decimal
return QString("%1").arg(data.y(), 4, BASE_HEX, QChar('0'));
case FieldFrameValue:
{
QByteArray fv;
fv.resize(4);
qToBigEndian((quint32) data.y(), (uchar*) fv.data());
fv.resize(2);
qToBigEndian((quint16) data.y(), (uchar*) fv.data());
return fv;
}
default:
@ -317,6 +330,11 @@ QVariant SampleProtocol::fieldData(int index, FieldAttrib attrib,
return AbstractProtocol::fieldData(index, attrib, streamIndex);
}
/*!
TODO: Edit this function to set the data for each field
See AbstractProtocol::setFieldData() for more info
*/
bool SampleProtocol::setFieldData(int index, const QVariant &value,
FieldAttrib attrib)
{
@ -387,7 +405,7 @@ _exit:
}
/*!
Return the protocol frame size in bytes\n
TODO: Return the protocol frame size in bytes\n
If your protocol has a fixed size - you don't need to reimplement this; the
base class implementation is good enough
@ -398,7 +416,7 @@ int SampleProtocol::protocolFrameSize(int streamIndex) const
}
/*!
If your protocol has any variable fields, return true \n
TODO: If your protocol has any variable fields, return true \n
Otherwise you don't need to reimplement this method - the base class always
returns false
@ -409,7 +427,7 @@ bool SampleProtocol::isProtocolFrameValueVariable() const
}
/*!
If your protocol frame size can vary across pkts of the same stream,
TODO: If your protocol frame size can vary across pkts of the same stream,
return true \n
Otherwise you don't need to reimplement this method - the base class always
@ -431,6 +449,11 @@ QWidget* SampleProtocol::configWidget()
return configForm;
}
/*!
TODO: Edit this function to load each field's data into the config Widget
See AbstractProtocol::loadConfigWidget() for more info
*/
void SampleProtocol::loadConfigWidget()
{
configWidget();
@ -451,6 +474,11 @@ void SampleProtocol::loadConfigWidget()
}
/*!
TODO: Edit this function to store each field's data from the config Widget
See AbstractProtocol::storeConfigWidget() for more info
*/
void SampleProtocol::storeConfigWidget()
{
bool isOk;