ostinato/common/ip4.cpp
Srivats P. 4c2df3c5a7 Protocols
---------
	- all protocols on allocation of a configWidget, also populate it before returning from configWidget()
	- VLAN TPID override is now correctly saved and restored from/to its widget (vlan.cpp)
	- Payload protocol returns a minimum frame value of 1 byte size (Hack to avoid crash in stream config dialog when sum of all protocol frame sizes is greater than the frame length
	- small layout changes in mac widget (mac.ui)
	- src/dst ip mask changed from 255.255.255.255 to 255.255.255.0 (ip4.proto)
	- src mac changed from u32 to u64 (mac.proto)
	- "Combo Protocol" protocol container introduced to define newer protocols as a combination of existing protocols e.g. dot2 = dot3 + llc - THIS IS NOT YET COMPLETE (comboprotocol.h)


Client/StreamConfigDialog
-------------------------
	- Advanced Protocol Selection implemented
	- Simple Protocol Selection rewritten to work alongside Advanced
	- Payload Widget is treated like any other protocol - hence it is not placedinto the dialog specially
	- Any protocol selection change (in Simple/Advanced mode) immediately triggers change in the Stream's protocolList
	- Protocol Widgets now are arranged in a toolBox on a top level tab of the dialog instead of a nested tabWidget
	- Vlan selection (Simple Mode) uses Radio buttons instead of checkboxes
	- Double Tagged (SVlan + CVlan) now works via Simple Mode
2009-09-23 14:53:26 +00:00

694 lines
16 KiB
C++

#include <qendian.h>
#include <QHostAddress>
#include "ip4.h"
Ip4ConfigForm::Ip4ConfigForm(QWidget *parent)
: QWidget(parent)
{
setupUi(this);
leIpVersion->setValidator(new QIntValidator(0, 15, this));
connect(cmbIpSrcAddrMode, SIGNAL(currentIndexChanged(int)),
this, SLOT(on_cmbIpSrcAddrMode_currentIndexChanged(int)));
connect(cmbIpDstAddrMode, SIGNAL(currentIndexChanged(int)),
this, SLOT(on_cmbIpDstAddrMode_currentIndexChanged(int)));
}
Ip4ConfigForm::~Ip4ConfigForm()
{
qDebug("IPv4 Config Form destructor called");
}
void Ip4ConfigForm::on_cmbIpSrcAddrMode_currentIndexChanged(int index)
{
if (index == OstProto::Ip4::e_im_fixed)
{
leIpSrcAddrCount->setDisabled(true);
leIpSrcAddrMask->setDisabled(true);
}
else
{
leIpSrcAddrCount->setEnabled(true);
leIpSrcAddrMask->setEnabled(true);
}
}
void Ip4ConfigForm::on_cmbIpDstAddrMode_currentIndexChanged(int index)
{
if (index == OstProto::Ip4::e_im_fixed)
{
leIpDstAddrCount->setDisabled(true);
leIpDstAddrMask->setDisabled(true);
}
else
{
leIpDstAddrCount->setEnabled(true);
leIpDstAddrMask->setEnabled(true);
}
}
Ip4Protocol::Ip4Protocol(StreamBase *stream)
: AbstractProtocol(stream)
{
configForm = NULL;
}
Ip4Protocol::~Ip4Protocol()
{
delete configForm;
}
AbstractProtocol* Ip4Protocol::createInstance(StreamBase *stream)
{
return new Ip4Protocol(stream);
}
quint32 Ip4Protocol::protocolNumber() const
{
return OstProto::Protocol::kIp4FieldNumber;
}
void Ip4Protocol::protoDataCopyInto(OstProto::Protocol &protocol) const
{
protocol.MutableExtension(OstProto::ip4)->CopyFrom(data);
protocol.mutable_protocol_id()->set_id(protocolNumber());
}
void Ip4Protocol::protoDataCopyFrom(const OstProto::Protocol &protocol)
{
if (protocol.protocol_id().id() == protocolNumber() &&
protocol.HasExtension(OstProto::ip4))
data.MergeFrom(protocol.GetExtension(OstProto::ip4));
}
QString Ip4Protocol::name() const
{
return QString("Internet Protocol ver 4");
}
QString Ip4Protocol::shortName() const
{
return QString("IPv4");
}
quint32 Ip4Protocol::protocolId(ProtocolIdType type) const
{
switch(type)
{
case ProtocolIdLlc: return 0x060603;
case ProtocolIdEth: return 0x0800;
case ProtocolIdIp: return 0x04;
default:break;
}
return AbstractProtocol::protocolId(type);
}
int Ip4Protocol::fieldCount() const
{
return ip4_fieldCount;
}
AbstractProtocol::FieldFlags Ip4Protocol::fieldFlags(int index) const
{
AbstractProtocol::FieldFlags flags;
flags = AbstractProtocol::fieldFlags(index);
switch (index)
{
case ip4_ver:
case ip4_hdrLen:
case ip4_tos:
case ip4_totLen:
case ip4_id:
case ip4_flags:
case ip4_fragOfs:
case ip4_ttl:
case ip4_proto:
break;
case ip4_cksum:
flags |= FieldIsCksum;
break;
case ip4_srcAddr:
case ip4_dstAddr:
break;
case ip4_isOverrideVer:
case ip4_isOverrideHdrLen:
case ip4_isOverrideTotLen:
case ip4_isOverrideCksum:
case ip4_srcAddrMode:
case ip4_srcAddrCount:
case ip4_srcAddrMask:
case ip4_dstAddrMode:
case ip4_dstAddrCount:
case ip4_dstAddrMask:
flags |= FieldIsMeta;
break;
default:
break;
}
return flags;
}
QVariant Ip4Protocol::fieldData(int index, FieldAttrib attrib,
int streamIndex) const
{
switch (index)
{
case ip4_ver:
{
int ver;
ver = data.is_override_ver() ? (data.ver_hdrlen() >> 4) & 0x0F : 4;
switch(attrib)
{
case FieldName:
return QString("Version");
case FieldValue:
return ver;
case FieldTextValue:
return QString("%1").arg(ver, 1, BASE_HEX, QChar('0'));
case FieldFrameValue:
return QByteArray(1, (char) ver);
case FieldBitSize:
return 4;
default:
break;
}
break;
}
case ip4_hdrLen:
{
int hdrlen;
hdrlen = data.is_override_hdrlen() ? data.ver_hdrlen() & 0x0F : 5;
switch(attrib)
{
case FieldName:
return QString("Header Length");
case FieldValue:
return hdrlen;
case FieldTextValue:
return QString("%1").arg(hdrlen, 1, BASE_HEX, QChar('0'));
case FieldFrameValue:
return QByteArray(1, (char) hdrlen);
case FieldBitSize:
return 4;
default:
break;
}
break;
}
case ip4_tos:
switch(attrib)
{
case FieldName:
return QString("TOS/DSCP");
case FieldValue:
return data.tos();
case FieldFrameValue:
return QByteArray(1, (char) data.tos());
case FieldTextValue:
return QString("0x%1").
arg(data.tos(), 2, BASE_HEX, QChar('0'));;
default:
break;
}
break;
case ip4_totLen:
{
switch(attrib)
{
case FieldName:
return QString("Total Length");
case FieldValue:
{
int totlen;
totlen = data.is_override_totlen() ? data.totlen() :
(protocolFramePayloadSize() + 20);
return totlen;
}
case FieldFrameValue:
{
QByteArray fv;
int totlen;
totlen = data.is_override_totlen() ? data.totlen() :
(protocolFramePayloadSize() + 20);
fv.resize(2);
qToBigEndian((quint16) totlen, (uchar*) fv.data());
return fv;
}
case FieldTextValue:
{
int totlen;
totlen = data.is_override_totlen() ? data.totlen() :
(protocolFramePayloadSize() + 20);
return QString("%1").arg(totlen);
}
case FieldBitSize:
return 16;
default:
break;
}
break;
}
case ip4_id:
switch(attrib)
{
case FieldName:
return QString("Identification");
case FieldValue:
return data.id();
case FieldFrameValue:
{
QByteArray fv;
fv.resize(2);
qToBigEndian((quint16) data.id(), (uchar*)fv.data());
return fv;
}
case FieldTextValue:
return QString("0x%1").
arg(data.id(), 2, BASE_HEX, QChar('0'));;
default:
break;
}
break;
case ip4_flags:
switch(attrib)
{
case FieldName:
return QString("Flags");
case FieldValue:
return data.flags();
case FieldFrameValue:
return QByteArray(1, (char) data.flags());
case FieldTextValue:
{
QString s;
s.append("Unused:");
s.append(data.flags() & IP_FLAG_UNUSED ? "1" : "0");
s.append(" Don't Fragment:");
s.append(data.flags() & IP_FLAG_DF ? "1" : "0");
s.append(" More Fragments:");
s.append(data.flags() & IP_FLAG_MF ? "1" : "0");
return s;
}
case FieldBitSize:
return 3;
default:
break;
}
break;
case ip4_fragOfs:
switch(attrib)
{
case FieldName:
return QString("Fragment Offset");
case FieldValue:
return data.frag_ofs();
case FieldFrameValue:
{
QByteArray fv;
// FIXME need to shift for 13 bits
fv.resize(2);
qToBigEndian((quint16) (data.frag_ofs()),
(uchar*) fv.data());
return fv;
}
case FieldTextValue:
return QString("%1").arg(data.frag_ofs()*8);
case FieldBitSize:
return 13;
default:
break;
}
break;
case ip4_ttl:
switch(attrib)
{
case FieldName:
return QString("Time to Live");
case FieldValue:
return data.ttl();
case FieldFrameValue:
return QByteArray(1, (char)data.ttl());
case FieldTextValue:
return QString("%1").arg(data.ttl());
default:
break;
}
break;
case ip4_proto:
{
switch(attrib)
{
case FieldName:
return QString("Protocol");
case FieldValue:
{
unsigned char id = payloadProtocolId(ProtocolIdIp);
return id;
}
case FieldFrameValue:
{
unsigned char id = payloadProtocolId(ProtocolIdIp);
return QByteArray(1, (char) id);
}
case FieldTextValue:
{
unsigned char id = payloadProtocolId(ProtocolIdIp);
return QString("0x%1").
arg(id, 2, BASE_HEX, QChar('0'));
}
default:
break;
}
break;
}
case ip4_cksum:
{
switch(attrib)
{
case FieldName:
return QString("Header Checksum");
case FieldValue:
{
quint16 cksum;
if (data.is_override_cksum())
cksum = data.cksum();
else
cksum = protocolFrameCksum(streamIndex, CksumIp);
return cksum;
}
case FieldFrameValue:
{
QByteArray fv;
quint16 cksum;
if (data.is_override_cksum())
cksum = data.cksum();
else
cksum = protocolFrameCksum(streamIndex, CksumIp);
fv.resize(2);
qToBigEndian((quint16) cksum, (uchar*) fv.data());
return fv;
}
case FieldTextValue:
{
quint16 cksum;
if (data.is_override_cksum())
cksum = data.cksum();
else
cksum = protocolFrameCksum(streamIndex, CksumIp);
return QString("0x%1").
arg(cksum, 4, BASE_HEX, QChar('0'));;
}
case FieldBitSize:
return 16;
default:
break;
}
break;
}
case ip4_srcAddr:
{
int u;
quint32 subnet, host, srcIp = 0;
switch(data.src_ip_mode())
{
case OstProto::Ip4::e_im_fixed:
srcIp = data.src_ip();
break;
case OstProto::Ip4::e_im_inc_host:
u = streamIndex % data.src_ip_count();
subnet = data.src_ip() & data.src_ip_mask();
host = (((data.src_ip() & ~data.src_ip_mask()) + u) &
~data.src_ip_mask());
srcIp = subnet | host;
break;
case OstProto::Ip4::e_im_dec_host:
u = streamIndex % data.src_ip_count();
subnet = data.src_ip() & data.src_ip_mask();
host = (((data.src_ip() & ~data.src_ip_mask()) - u) &
~data.src_ip_mask());
srcIp = subnet | host;
break;
case OstProto::Ip4::e_im_random_host:
subnet = data.src_ip() & data.src_ip_mask();
host = (qrand() & ~data.src_ip_mask());
srcIp = subnet | host;
break;
default:
qWarning("Unhandled src_ip_mode = %d", data.src_ip_mode());
}
switch(attrib)
{
case FieldName:
return QString("Source");
case FieldValue:
return srcIp;
case FieldFrameValue:
{
QByteArray fv;
fv.resize(4);
qToBigEndian(srcIp, (uchar*) fv.data());
return fv;
}
case FieldTextValue:
return QHostAddress(srcIp).toString();
default:
break;
}
break;
}
case ip4_dstAddr:
{
int u;
quint32 subnet, host, dstIp = 0;
switch(data.dst_ip_mode())
{
case OstProto::Ip4::e_im_fixed:
dstIp = data.dst_ip();
break;
case OstProto::Ip4::e_im_inc_host:
u = streamIndex % data.dst_ip_count();
subnet = data.dst_ip() & data.dst_ip_mask();
host = (((data.dst_ip() & ~data.dst_ip_mask()) + u) &
~data.dst_ip_mask());
dstIp = subnet | host;
break;
case OstProto::Ip4::e_im_dec_host:
u = streamIndex % data.dst_ip_count();
subnet = data.dst_ip() & data.dst_ip_mask();
host = (((data.dst_ip() & ~data.dst_ip_mask()) - u) &
~data.dst_ip_mask());
dstIp = subnet | host;
break;
case OstProto::Ip4::e_im_random_host:
subnet = data.dst_ip() & data.dst_ip_mask();
host = (qrand() & ~data.dst_ip_mask());
dstIp = subnet | host;
break;
default:
qWarning("Unhandled dst_ip_mode = %d", data.dst_ip_mode());
}
switch(attrib)
{
case FieldName:
return QString("Destination");
case FieldValue:
return dstIp;
case FieldFrameValue:
{
QByteArray fv;
fv.resize(4);
qToBigEndian((quint32) dstIp, (uchar*) fv.data());
return fv;
}
case FieldTextValue:
return QHostAddress(dstIp).toString();
default:
break;
}
break;
}
// Meta fields
case ip4_isOverrideVer:
case ip4_isOverrideHdrLen:
case ip4_isOverrideTotLen:
case ip4_isOverrideCksum:
case ip4_srcAddrMode:
case ip4_srcAddrCount:
case ip4_srcAddrMask:
case ip4_dstAddrMode:
case ip4_dstAddrCount:
case ip4_dstAddrMask:
default:
break;
}
return AbstractProtocol::fieldData(index, attrib, streamIndex);
}
bool Ip4Protocol::setFieldData(int index, const QVariant &value,
FieldAttrib attrib)
{
bool isOk = false;
if (attrib != FieldValue)
return false;
switch (index)
{
case ip4_proto:
{
uint proto = value.toUInt(&isOk);
if (isOk)
data.set_proto(proto);
}
default:
break;
}
return isOk;
}
quint32 Ip4Protocol::protocolFrameCksum(int streamIndex,
CksumType cksumType) const
{
switch (cksumType)
{
case CksumIpPseudo:
{
quint32 sum;
sum = fieldData(ip4_srcAddr, FieldValue, streamIndex).toUInt() >> 16;
sum += fieldData(ip4_srcAddr, FieldValue, streamIndex).toUInt() & 0xFFFF;
sum += fieldData(ip4_dstAddr, FieldValue, streamIndex).toUInt() >> 16;
sum += fieldData(ip4_dstAddr, FieldValue, streamIndex).toUInt() & 0xFFFF;
sum += fieldData(ip4_proto, FieldValue, streamIndex).toUInt() & 0x00FF;
sum += (fieldData(ip4_totLen, FieldValue, streamIndex).toUInt() & 0xFFFF) - 20;
// Above calculation done assuming 'big endian'
// - so convert to host order
//return qFromBigEndian(sum);
return sum;
}
default:
break;
}
return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType);
}
QWidget* Ip4Protocol::configWidget()
{
if (configForm == NULL)
{
configForm = new Ip4ConfigForm;
loadConfigWidget();
}
return configForm;
}
void Ip4Protocol::loadConfigWidget()
{
configWidget();
configForm->cbIpVersionOverride->setChecked(data.is_override_ver());
configForm->leIpVersion->setText(fieldData(ip4_ver, FieldValue).toString());
configForm->cbIpHdrLenOverride->setChecked(data.is_override_hdrlen());
configForm->leIpHdrLen->setText(fieldData(ip4_hdrLen, FieldValue).toString());
configForm->leIpTos->setText(uintToHexStr(data.tos(), 1));
configForm->cbIpLengthOverride->setChecked(data.is_override_totlen());
configForm->leIpLength->setText(fieldData(ip4_totLen, FieldValue).toString());
configForm->leIpId->setText(uintToHexStr(data.id(), 2));
configForm->leIpFragOfs->setText(QString().setNum(data.frag_ofs()));
configForm->cbIpFlagsDf->setChecked((data.flags() & IP_FLAG_DF) > 0);
configForm->cbIpFlagsMf->setChecked((data.flags() & IP_FLAG_MF) > 0);
configForm->leIpTtl->setText(QString().setNum(data.ttl()));
configForm->leIpProto->setText(uintToHexStr(
fieldData(ip4_proto, FieldValue).toUInt(), 1));
configForm->cbIpCksumOverride->setChecked(data.is_override_cksum());
configForm->leIpCksum->setText(uintToHexStr(
fieldData(ip4_cksum, FieldValue).toUInt(), 2));
configForm->leIpSrcAddr->setText(QHostAddress(data.src_ip()).toString());
configForm->cmbIpSrcAddrMode->setCurrentIndex(data.src_ip_mode());
configForm->leIpSrcAddrCount->setText(QString().setNum(data.src_ip_count()));
configForm->leIpSrcAddrMask->setText(QHostAddress(data.src_ip_mask()).toString());
configForm->leIpDstAddr->setText(QHostAddress(data.dst_ip()).toString());
configForm->cmbIpDstAddrMode->setCurrentIndex(data.dst_ip_mode());
configForm->leIpDstAddrCount->setText(QString().setNum(data.dst_ip_count()));
configForm->leIpDstAddrMask->setText(QHostAddress(data.dst_ip_mask()).toString());
}
void Ip4Protocol::storeConfigWidget()
{
uint ff = 0;
bool isOk;
configWidget();
data.set_is_override_ver(configForm->cbIpVersionOverride->isChecked());
data.set_ver_hdrlen(((configForm->leIpVersion->text().toULong(&isOk) & 0x0F) << 4) |
(configForm->leIpHdrLen->text().toULong(&isOk) & 0x0F));
data.set_is_override_hdrlen(configForm->cbIpHdrLenOverride->isChecked());
data.set_tos(configForm->leIpTos->text().toULong(&isOk, 16));
data.set_totlen(configForm->leIpLength->text().toULong(&isOk));
data.set_is_override_totlen(configForm->cbIpLengthOverride->isChecked());
data.set_id(configForm->leIpId->text().remove(QChar(' ')).toULong(&isOk, 16));
data.set_frag_ofs(configForm->leIpFragOfs->text().toULong(&isOk));
if (configForm->cbIpFlagsDf->isChecked()) ff |= IP_FLAG_DF;
if (configForm->cbIpFlagsMf->isChecked()) ff |= IP_FLAG_MF;
data.set_flags(ff);
data.set_ttl(configForm->leIpTtl->text().toULong(&isOk));
data.set_proto(configForm->leIpProto->text().remove(QChar(' ')).toULong(&isOk, 16));
data.set_is_override_cksum(configForm->cbIpCksumOverride->isChecked());
data.set_cksum(configForm->leIpCksum->text().remove(QChar(' ')).toULong(&isOk));
data.set_src_ip(QHostAddress(configForm->leIpSrcAddr->text()).toIPv4Address());
data.set_src_ip_mode((OstProto::Ip4_IpAddrMode)configForm->cmbIpSrcAddrMode->currentIndex());
data.set_src_ip_count(configForm->leIpSrcAddrCount->text().toULong(&isOk));
data.set_src_ip_mask(QHostAddress(configForm->leIpSrcAddrMask->text()).toIPv4Address());
data.set_dst_ip(QHostAddress(configForm->leIpDstAddr->text()).toIPv4Address());
data.set_dst_ip_mode((OstProto::Ip4_IpAddrMode)configForm->cmbIpDstAddrMode->currentIndex());
data.set_dst_ip_count(configForm->leIpDstAddrCount->text().toULong(&isOk));
data.set_dst_ip_mask(QHostAddress(configForm->leIpDstAddrMask->text()).toIPv4Address());
}