Implemented IPv6 protocol; found and fixed a bug in AbstractProtocol::protocolFrameValue() in the process

This commit is contained in:
Srivats P. 2010-05-22 22:02:46 +05:30
parent ed13bba83b
commit 4a70d52e3e
10 changed files with 1691 additions and 7 deletions

View File

@ -147,8 +147,7 @@ StreamConfigDialog::StreamConfigDialog(Port &port, uint streamIndex,
// TODO(MED):
//! \todo Implement then enable these protocols - IPv6, IGMP
rbL3Ipv6->setHidden(true);
//! \todo Implement then enable these protocols - IGMP
rbL4Igmp->setHidden(true);
//! \todo Enable navigation of streams
pbPrev->setDisabled(true);
@ -200,7 +199,7 @@ void StreamConfigDialog::setupUiExtra()
#else
bgProto[ProtoL3]->addButton(rbL3None, ButtonIdNone);
bgProto[ProtoL3]->addButton(rbL3Ipv4, OstProto::Protocol::kIp4FieldNumber);
bgProto[ProtoL3]->addButton(rbL3Ipv6, 0xFFFF);
bgProto[ProtoL3]->addButton(rbL3Ipv6, OstProto::Protocol::kIp6FieldNumber);
bgProto[ProtoL3]->addButton(rbL3Arp, OstProto::Protocol::kArpFieldNumber);
bgProto[ProtoL3]->addButton(rbL3Ip4over4,
OstProto::Protocol::kIp4over4FieldNumber);

View File

@ -249,7 +249,7 @@ AbstractProtocol::FieldFlags AbstractProtocol::fieldFlags(int /*index*/) const
\note If a subclass uses any of the below functions to derive
FieldFrameValue, the subclass should handle and return a value for
FieldBitSize to prevent endless recrusion -
FieldBitSize to prevent endless recursion -
- protocolFrameCksum()
- protocolFramePayloadSize()
*/
@ -454,7 +454,10 @@ QByteArray AbstractProtocol::protocolFrameValue(int streamIndex, bool forCksum)
}
else
field = fieldData(i, FieldFrameValue, streamIndex).toByteArray();
qDebug("<<< %d, %d/%d >>>>", proto.size(), bits, field.size());
qDebug("<<< (%d, %db) %s >>>", proto.size(), lastbitpos,
QString(proto.toHex()).toAscii().constData());
qDebug(" < (%db/%dB) %s >", bits, field.size(),
QString(field.toHex()).toAscii().constData());
if (bits == (uint) field.size() * 8)
{
@ -465,10 +468,12 @@ QByteArray AbstractProtocol::protocolFrameValue(int streamIndex, bool forCksum)
Q_ASSERT(field.size() > 0);
char c = proto[proto.size() - 1];
proto[proto.size() - 1] = c | (field.at(0) >> lastbitpos);
proto[proto.size() - 1] =
c | ((uchar)field.at(0) >> lastbitpos);
for (int j = 0; j < field.size() - 1; j++)
proto.append(field.at(j) << lastbitpos |
field.at(j+1) >> lastbitpos);
(uchar)field.at(j+1) >> lastbitpos);
proto.append(field.at(field.size() - 1) << lastbitpos);
}
}
else if (bits < (uint) field.size() * 8)

939
common/ip6.cpp Normal file
View File

@ -0,0 +1,939 @@
/*
Copyright (C) 2010 Srivats P.
This file is part of "Ostinato"
This is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#include "ip6.h"
#include "ipv6addressvalidator.h"
#include <QHostAddress>
#include <qendian.h>
Ip6ConfigForm::Ip6ConfigForm(QWidget *parent)
: QWidget(parent)
{
setupUi(this);
version->setValidator(new QIntValidator(0, 0xF, this));
payloadLength->setValidator(new QIntValidator(0, 0xFFFF, this));
hopLimit->setValidator(new QIntValidator(0, 0xFF, this));
srcAddr->setValidator(new IPv6AddressValidator(this));
srcAddrCount->setValidator(new QIntValidator(this));
//srcAddrPrefix->setValidator(new QIntValidator(0, 128, this));
dstAddr->setValidator(new IPv6AddressValidator(this));
dstAddrCount->setValidator(new QIntValidator(this));
//dstAddrPrefix->setValidator(new QIntValidator(0, 128, this));
}
void Ip6ConfigForm::on_srcAddr_editingFinished()
{
srcAddr->setText(QHostAddress(srcAddr->text()).toString());
}
void Ip6ConfigForm::on_dstAddr_editingFinished()
{
dstAddr->setText(QHostAddress(dstAddr->text()).toString());
}
void Ip6ConfigForm::on_srcAddrModeCombo_currentIndexChanged(int index)
{
bool enabled = (index > 0);
srcAddrCount->setEnabled(enabled);
srcAddrPrefix->setEnabled(enabled);
}
void Ip6ConfigForm::on_dstAddrModeCombo_currentIndexChanged(int index)
{
bool enabled = (index > 0);
dstAddrCount->setEnabled(enabled);
dstAddrPrefix->setEnabled(enabled);
}
Ip6Protocol::Ip6Protocol(StreamBase *stream, AbstractProtocol *parent)
: AbstractProtocol(stream, parent)
{
/* The configWidget is created lazily */
configForm = NULL;
}
Ip6Protocol::~Ip6Protocol()
{
delete configForm;
}
AbstractProtocol* Ip6Protocol::createInstance(StreamBase *stream,
AbstractProtocol *parent)
{
return new Ip6Protocol(stream, parent);
}
quint32 Ip6Protocol::protocolNumber() const
{
return OstProto::Protocol::kIp6FieldNumber;
}
void Ip6Protocol::protoDataCopyInto(OstProto::Protocol &protocol) const
{
protocol.MutableExtension(OstProto::ip6)->CopyFrom(data);
protocol.mutable_protocol_id()->set_id(protocolNumber());
}
void Ip6Protocol::protoDataCopyFrom(const OstProto::Protocol &protocol)
{
if (protocol.protocol_id().id() == protocolNumber() &&
protocol.HasExtension(OstProto::ip6))
data.MergeFrom(protocol.GetExtension(OstProto::ip6));
}
QString Ip6Protocol::name() const
{
return QString("Internet Protocol ver 6");
}
QString Ip6Protocol::shortName() const
{
return QString("IPv6");
}
AbstractProtocol::ProtocolIdType Ip6Protocol::protocolIdType() const
{
return ProtocolIdIp;
}
quint32 Ip6Protocol::protocolId(ProtocolIdType type) const
{
switch(type)
{
case ProtocolIdEth: return 0x86dd;
case ProtocolIdIp: return 0x29;
default:break;
}
return AbstractProtocol::protocolId(type);
}
int Ip6Protocol::fieldCount() const
{
return ip6_fieldCount;
}
AbstractProtocol::FieldFlags Ip6Protocol::fieldFlags(int index) const
{
AbstractProtocol::FieldFlags flags;
flags = AbstractProtocol::fieldFlags(index);
switch (index)
{
case ip6_version:
case ip6_trafficClass:
case ip6_flowLabel:
case ip6_payloadLength:
case ip6_nextHeader:
case ip6_hopLimit:
case ip6_srcAddress:
case ip6_dstAddress:
break;
case ip6_isOverrideVersion:
case ip6_isOverridePayloadLength:
case ip6_isOverrideNextHeader:
case ip6_srcAddrMode:
case ip6_srcAddrCount:
case ip6_srcAddrPrefix:
case ip6_dstAddrMode:
case ip6_dstAddrCount:
case ip6_dstAddrPrefix:
flags |= FieldIsMeta;
break;
default:
qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__,
index);
break;
}
return flags;
}
QVariant Ip6Protocol::fieldData(int index, FieldAttrib attrib,
int streamIndex) const
{
switch (index)
{
case ip6_version:
{
quint8 ver;
switch(attrib)
{
case FieldValue:
case FieldFrameValue:
case FieldTextValue:
if (data.is_override_version())
ver = data.version() & 0xF;
else
ver = 0x6;
break;
default:
ver = 0; // avoid the 'maybe used unitialized' warning
break;
}
switch(attrib)
{
case FieldName:
return QString("Version");
case FieldValue:
return ver;
case FieldTextValue:
return QString("%1").arg(ver);
case FieldFrameValue:
return QByteArray(1, char(ver));
case FieldBitSize:
return 4;
default:
break;
}
break;
}
case ip6_trafficClass:
{
switch(attrib)
{
case FieldName:
return QString("Traffic Class");
case FieldValue:
return data.traffic_class() & 0xFF;
case FieldTextValue:
return QString("%1").arg(data.traffic_class() & 0xFF,
2, BASE_HEX, QChar('0'));
case FieldFrameValue:
return QByteArray(1, char(data.traffic_class() & 0xFF));
default:
break;
}
break;
}
case ip6_flowLabel:
{
switch(attrib)
{
case FieldName:
return QString("Flow Label");
case FieldValue:
return data.flow_label() & 0xFFFFF;
case FieldTextValue:
return QString("%1").arg(data.flow_label() & 0xFFFFF,
5, BASE_HEX, QChar('0'));
case FieldFrameValue:
{
QByteArray fv;
fv.resize(4);
qToBigEndian((quint32) data.flow_label() & 0xFFFFF,
(uchar*) fv.data());
fv = fv.right(3);
return fv;
}
case FieldBitSize:
return 20;
default:
break;
}
break;
}
case ip6_payloadLength:
{
quint16 len;
switch(attrib)
{
case FieldValue:
case FieldFrameValue:
case FieldTextValue:
if (data.is_override_payload_length())
len = data.payload_length();
else
len = protocolFramePayloadSize(streamIndex);
break;
default:
len = 0; // avoid the 'maybe used unitialized' warning
break;
}
switch(attrib)
{
case FieldName:
return QString("Payload Length");
case FieldValue:
return len;
case FieldFrameValue:
{
QByteArray fv;
fv.resize(2);
qToBigEndian(len, (uchar*) fv.data());
return fv;
}
case FieldTextValue:
return QString("%1").arg(len);
case FieldBitSize:
return 16;
default:
break;
}
break;
}
case ip6_nextHeader:
{
quint8 nextHdr;
switch(attrib)
{
case FieldValue:
case FieldFrameValue:
case FieldTextValue:
if (data.is_override_next_header())
nextHdr = data.next_header();
else
nextHdr = payloadProtocolId(ProtocolIdIp);
break;
default:
nextHdr = 0; // avoid the 'maybe used unitialized' warning
break;
}
switch(attrib)
{
case FieldName:
return QString("Next Header");
case FieldValue:
return nextHdr;
case FieldTextValue:
return QString("%1").arg(nextHdr, 2, BASE_HEX, QChar('0'));
case FieldFrameValue:
return QByteArray(1, char(nextHdr));
default:
break;
}
break;
}
case ip6_hopLimit:
{
switch(attrib)
{
case FieldName:
return QString("Hop Limit");
case FieldValue:
return data.hop_limit() & 0xFF;
case FieldTextValue:
return QString("%1").arg(data.hop_limit() & 0xFF);
case FieldFrameValue:
return QByteArray(1, char(data.hop_limit() & 0xFF));
default:
break;
}
break;
}
case ip6_srcAddress:
{
int u, p, q;
quint64 maskHi = 0, maskLo = 0;
quint64 prefixHi, prefixLo;
quint64 hostHi, hostLo;
quint64 srcHi = 0, srcLo = 0;
switch(data.src_addr_mode())
{
case OstProto::Ip6::kFixed:
srcHi = data.src_addr_hi();
srcLo = data.src_addr_lo();
break;
case OstProto::Ip6::kIncHost:
case OstProto::Ip6::kDecHost:
case OstProto::Ip6::kRandomHost:
u = streamIndex % data.src_addr_count();
if (data.src_addr_prefix() > 64) {
p = 64;
q = data.src_addr_prefix() - 64;
} else {
p = data.src_addr_prefix();
q = 0;
}
if (p > 0)
maskHi = ~((quint64(1) << p) - 1);
if (q > 0)
maskLo = ~((quint64(1) << q) - 1);
prefixHi = data.src_addr_hi() & maskHi;
prefixLo = data.src_addr_lo() & maskLo;
if (data.src_addr_mode() == OstProto::Ip6::kIncHost) {
hostHi = ((data.src_addr_hi() & ~maskHi) + u) & ~maskHi;
hostLo = ((data.src_addr_lo() & ~maskLo) + u) & ~maskLo;
}
else if (data.src_addr_mode() == OstProto::Ip6::kDecHost) {
hostHi = ((data.src_addr_hi() & ~maskHi) - u) & ~maskHi;
hostLo = ((data.src_addr_lo() & ~maskLo) - u) & ~maskLo;
}
else if (data.src_addr_mode()==OstProto::Ip6::kRandomHost) {
hostHi = qrand() & ~maskHi;
hostLo = qrand() & ~maskLo;
}
srcHi = prefixHi | hostHi;
srcLo = prefixLo | hostLo;
break;
default:
qWarning("Unhandled src_addr_mode = %d",
data.src_addr_mode());
}
switch(attrib)
{
case FieldName:
return QString("Source");
case FieldValue:
case FieldFrameValue:
case FieldTextValue:
{
QByteArray fv;
fv.resize(16);
qToBigEndian(srcHi, (uchar*) fv.data());
qToBigEndian(srcLo, (uchar*) (fv.data() + 8));
if (attrib == FieldTextValue)
return QHostAddress((quint8*)fv.constData()).toString();
else
return fv;
}
default:
break;
}
break;
}
case ip6_dstAddress:
{
int u, p, q;
quint64 maskHi = 0, maskLo = 0;
quint64 prefixHi, prefixLo;
quint64 hostHi, hostLo;
quint64 dstHi = 0, dstLo = 0;
switch(data.dst_addr_mode())
{
case OstProto::Ip6::kFixed:
dstHi = data.dst_addr_hi();
dstLo = data.dst_addr_lo();
break;
case OstProto::Ip6::kIncHost:
case OstProto::Ip6::kDecHost:
case OstProto::Ip6::kRandomHost:
u = streamIndex % data.dst_addr_count();
if (data.dst_addr_prefix() > 64) {
p = 64;
q = data.dst_addr_prefix() - 64;
} else {
p = data.dst_addr_prefix();
q = 0;
}
if (p > 0)
maskHi = ~((quint64(1) << p) - 1);
if (q > 0)
maskLo = ~((quint64(1) << q) - 1);
prefixHi = data.dst_addr_hi() & maskHi;
prefixLo = data.dst_addr_lo() & maskLo;
if (data.dst_addr_mode() == OstProto::Ip6::kIncHost) {
hostHi = ((data.dst_addr_hi() & ~maskHi) + u) & ~maskHi;
hostLo = ((data.dst_addr_lo() & ~maskLo) + u) & ~maskLo;
}
else if (data.dst_addr_mode() == OstProto::Ip6::kDecHost) {
hostHi = ((data.dst_addr_hi() & ~maskHi) - u) & ~maskHi;
hostLo = ((data.dst_addr_lo() & ~maskLo) - u) & ~maskLo;
}
else if (data.dst_addr_mode()==OstProto::Ip6::kRandomHost) {
hostHi = qrand() & ~maskHi;
hostLo = qrand() & ~maskLo;
}
dstHi = prefixHi | hostHi;
dstLo = prefixLo | hostLo;
break;
default:
qWarning("Unhandled dst_addr_mode = %d",
data.dst_addr_mode());
}
switch(attrib)
{
case FieldName:
return QString("Destination");
case FieldValue:
case FieldFrameValue:
case FieldTextValue:
{
QByteArray fv;
fv.resize(16);
qToBigEndian(dstHi, (uchar*) fv.data());
qToBigEndian(dstLo, (uchar*) (fv.data() + 8));
if (attrib == FieldTextValue)
return QHostAddress((quint8*)fv.constData()).toString();
else
return fv;
}
default:
break;
}
break;
}
// Meta-Fields
case ip6_isOverrideVersion:
{
switch(attrib)
{
case FieldValue:
return data.is_override_version();
default:
break;
}
break;
}
case ip6_isOverridePayloadLength:
{
switch(attrib)
{
case FieldValue:
return data.is_override_payload_length();
default:
break;
}
break;
}
case ip6_isOverrideNextHeader:
{
switch(attrib)
{
case FieldValue:
return data.is_override_next_header();
default:
break;
}
break;
}
case ip6_srcAddrMode:
{
switch(attrib)
{
case FieldValue:
return data.src_addr_mode();
default:
break;
}
break;
}
case ip6_srcAddrCount:
{
switch(attrib)
{
case FieldValue:
return data.src_addr_count();
default:
break;
}
break;
}
case ip6_srcAddrPrefix:
{
switch(attrib)
{
case FieldValue:
return data.src_addr_prefix();
default:
break;
}
break;
}
case ip6_dstAddrMode:
{
switch(attrib)
{
case FieldValue:
return data.dst_addr_mode();
default:
break;
}
break;
}
case ip6_dstAddrCount:
{
switch(attrib)
{
case FieldValue:
return data.dst_addr_count();
default:
break;
}
break;
}
case ip6_dstAddrPrefix:
{
switch(attrib)
{
case FieldValue:
return data.dst_addr_prefix();
default:
break;
}
break;
}
default:
qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__,
index);
break;
}
return AbstractProtocol::fieldData(index, attrib, streamIndex);
}
bool Ip6Protocol::setFieldData(int index, const QVariant &value,
FieldAttrib attrib)
{
bool isOk = false;
if (attrib != FieldValue)
goto _exit;
switch (index)
{
case ip6_version:
{
uint ver = value.toUInt(&isOk);
if (isOk)
data.set_version(ver & 0xF);
break;
}
case ip6_trafficClass:
{
uint trfClass = value.toUInt(&isOk);
if (isOk)
data.set_traffic_class(trfClass & 0xFF);
break;
}
case ip6_flowLabel:
{
uint fl = value.toUInt(&isOk);
if (isOk)
data.set_flow_label(fl & 0xFFFFF);
break;
}
case ip6_payloadLength:
{
uint len = value.toUInt(&isOk);
if (isOk)
data.set_payload_length(len & 0xFFFF);
break;
}
case ip6_nextHeader:
{
uint ver = value.toUInt(&isOk);
if (isOk)
data.set_next_header(ver & 0xFF);
break;
}
case ip6_hopLimit:
{
uint hl = value.toUInt(&isOk);
if (isOk)
data.set_hop_limit(hl & 0xFF);
break;
}
case ip6_srcAddress:
{
Q_IPV6ADDR addr = QHostAddress(value.toString()).toIPv6Address();
quint64 x;
x = (quint64(addr[0]) << 56)
| (quint64(addr[1]) << 48)
| (quint64(addr[2]) << 40)
| (quint64(addr[3]) << 32)
| (quint64(addr[4]) << 24)
| (quint64(addr[5]) << 16)
| (quint64(addr[6]) << 8)
| (quint64(addr[7]) << 0);
data.set_src_addr_hi(x);
x = (quint64(addr[ 8]) << 56)
| (quint64(addr[ 9]) << 48)
| (quint64(addr[10]) << 40)
| (quint64(addr[11]) << 32)
| (quint64(addr[12]) << 24)
| (quint64(addr[13]) << 16)
| (quint64(addr[14]) << 8)
| (quint64(addr[15]) << 0);
data.set_src_addr_lo(x);
break;
}
case ip6_dstAddress:
{
Q_IPV6ADDR addr = QHostAddress(value.toString()).toIPv6Address();
quint64 x;
x = (quint64(addr[0]) << 56)
| (quint64(addr[1]) << 48)
| (quint64(addr[2]) << 40)
| (quint64(addr[3]) << 32)
| (quint64(addr[4]) << 24)
| (quint64(addr[5]) << 16)
| (quint64(addr[6]) << 8)
| (quint64(addr[7]) << 0);
data.set_dst_addr_hi(x);
x = (quint64(addr[ 8]) << 56)
| (quint64(addr[ 9]) << 48)
| (quint64(addr[10]) << 40)
| (quint64(addr[11]) << 32)
| (quint64(addr[12]) << 24)
| (quint64(addr[13]) << 16)
| (quint64(addr[14]) << 8)
| (quint64(addr[15]) << 0);
data.set_dst_addr_lo(x);
break;
}
// Meta-Fields
case ip6_isOverrideVersion:
{
bool ovr = value.toBool();
data.set_is_override_version(ovr);
isOk = true;
break;
}
case ip6_isOverridePayloadLength:
{
bool ovr = value.toBool();
data.set_is_override_payload_length(ovr);
isOk = true;
break;
}
case ip6_isOverrideNextHeader:
{
bool ovr = value.toBool();
data.set_is_override_next_header(ovr);
isOk = true;
break;
}
case ip6_srcAddrMode:
{
uint mode = value.toUInt(&isOk);
if (isOk && data.AddrMode_IsValid(mode))
data.set_src_addr_mode((OstProto::Ip6::AddrMode) mode);
else
isOk = false;
break;
}
case ip6_srcAddrCount:
{
uint count = value.toUInt(&isOk);
if (isOk)
data.set_src_addr_count(count);
break;
}
case ip6_srcAddrPrefix:
{
uint prefix = value.toUInt(&isOk);
if (isOk)
data.set_src_addr_prefix(prefix);
break;
}
case ip6_dstAddrMode:
{
uint mode = value.toUInt(&isOk);
if (isOk && data.AddrMode_IsValid(mode))
data.set_dst_addr_mode((OstProto::Ip6::AddrMode) mode);
else
isOk = false;
break;
}
case ip6_dstAddrCount:
{
uint count = value.toUInt(&isOk);
if (isOk)
data.set_dst_addr_count(count);
break;
}
case ip6_dstAddrPrefix:
{
uint prefix = value.toUInt(&isOk);
if (isOk)
data.set_dst_addr_prefix(prefix);
break;
}
default:
qFatal("%s: unimplemented case %d in switch", __PRETTY_FUNCTION__,
index);
break;
}
_exit:
return isOk;
}
bool Ip6Protocol::isProtocolFrameValueVariable() const
{
if ((data.src_addr_mode() != OstProto::Ip6::kFixed)
|| (data.dst_addr_mode() != OstProto::Ip6::kFixed))
return true;
else
return false;
}
quint32 Ip6Protocol::protocolFrameCksum(int streamIndex,
CksumType cksumType) const
{
if (cksumType == CksumIpPseudo)
{
QByteArray addr;
quint32 sum = 0;
addr = fieldData(ip6_srcAddress, FieldFrameValue, streamIndex)
.toByteArray();
Q_ASSERT(addr.size() == 16);
for (int i = 0; i < addr.size(); i+=2)
sum += (addr.at(i) << 8) + addr.at(i+1);
addr = fieldData(ip6_dstAddress, FieldFrameValue, streamIndex)
.toByteArray();
Q_ASSERT(addr.size() == 16);
for (int i = 0; i < addr.size(); i+=2)
sum += (addr.at(i) << 8) + addr.at(i+1);
sum += fieldData(ip6_payloadLength, FieldValue, streamIndex)
.toUInt() & 0xFFFF;
sum += fieldData(ip6_nextHeader, FieldValue, streamIndex)
.toUInt() & 0xFF;
while(sum>>16)
sum = (sum & 0xFFFF) + (sum >> 16);
return ~sum;
}
return AbstractProtocol::protocolFrameCksum(streamIndex, cksumType);
}
QWidget* Ip6Protocol::configWidget()
{
/* Lazy creation of the configWidget */
if (configForm == NULL)
{
configForm = new Ip6ConfigForm;
loadConfigWidget();
}
return configForm;
}
void Ip6Protocol::loadConfigWidget()
{
configWidget();
configForm->isVersionOverride->setChecked(
fieldData(ip6_isOverrideVersion, FieldValue).toBool());
configForm->version->setText(
fieldData(ip6_version, FieldValue).toString());
configForm->trafficClass->setText(uintToHexStr(
fieldData(ip6_trafficClass, FieldValue).toUInt(), 1));
configForm->flowLabel->setText(QString("%1").arg(
fieldData(ip6_flowLabel, FieldValue).toUInt(),5, BASE_HEX, QChar('0')));
configForm->isPayloadLengthOverride->setChecked(
fieldData(ip6_isOverridePayloadLength, FieldValue).toBool());
configForm->payloadLength->setText(
fieldData(ip6_payloadLength, FieldValue).toString());
configForm->isNextHeaderOverride->setChecked(
fieldData(ip6_isOverrideNextHeader, FieldValue).toBool());
configForm->nextHeader->setText(uintToHexStr(
fieldData(ip6_nextHeader, FieldValue).toUInt(), 1));
configForm->hopLimit->setText(
fieldData(ip6_hopLimit, FieldValue).toString());
configForm->srcAddr->setText(
fieldData(ip6_srcAddress, FieldTextValue).toString());
configForm->srcAddrModeCombo->setCurrentIndex(
fieldData(ip6_srcAddrMode, FieldValue).toUInt());
configForm->srcAddrCount->setText(
fieldData(ip6_srcAddrCount, FieldValue).toString());
configForm->srcAddrPrefix->setText(
fieldData(ip6_srcAddrPrefix, FieldValue).toString());
configForm->dstAddr->setText(
fieldData(ip6_dstAddress, FieldTextValue).toString());
configForm->dstAddrModeCombo->setCurrentIndex(
fieldData(ip6_dstAddrMode, FieldValue).toUInt());
configForm->dstAddrCount->setText(
fieldData(ip6_dstAddrCount, FieldValue).toString());
configForm->dstAddrPrefix->setText(
fieldData(ip6_dstAddrPrefix, FieldValue).toString());
}
void Ip6Protocol::storeConfigWidget()
{
bool isOk;
configWidget();
setFieldData(ip6_isOverrideVersion,
configForm->isVersionOverride->isChecked());
setFieldData(ip6_version, configForm->version->text());
setFieldData(ip6_trafficClass,
configForm->trafficClass->text().remove(QChar(' ')).toUInt(&isOk, BASE_HEX));
setFieldData(ip6_flowLabel,
configForm->flowLabel->text().remove(QChar(' ')).toUInt(&isOk, BASE_HEX));
setFieldData(ip6_isOverridePayloadLength,
configForm->isPayloadLengthOverride->isChecked());
setFieldData(ip6_payloadLength, configForm->payloadLength->text());
setFieldData(ip6_isOverrideNextHeader,
configForm->isNextHeaderOverride->isChecked());
setFieldData(ip6_nextHeader,
configForm->nextHeader->text().remove(QChar(' ')).toUInt(&isOk, BASE_HEX));
setFieldData(ip6_hopLimit, configForm->hopLimit->text());
setFieldData(ip6_srcAddress, configForm->srcAddr->text());
setFieldData(ip6_srcAddrMode, configForm->srcAddrModeCombo->currentIndex());
setFieldData(ip6_srcAddrCount, configForm->srcAddrCount->text());
setFieldData(ip6_srcAddrPrefix, configForm->srcAddrPrefix->text());
setFieldData(ip6_dstAddress, configForm->dstAddr->text());
setFieldData(ip6_dstAddrMode, configForm->dstAddrModeCombo->currentIndex());
setFieldData(ip6_dstAddrCount, configForm->dstAddrCount->text());
setFieldData(ip6_dstAddrPrefix, configForm->dstAddrPrefix->text());
}

130
common/ip6.h Normal file
View File

@ -0,0 +1,130 @@
/*
Copyright (C) 2010 Srivats P.
This file is part of "Ostinato"
This is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#ifndef _IP6_H
#define _IP6_H
#include "ip6.pb.h"
#include "ui_ip6.h"
#include "abstractprotocol.h"
/*
IPv6 Protocol Frame Format -
+-----+----------+-----------------------+
| Ver | TrfClass | FlowLabel |
| (4) | (8) | (20) |
+-----+-------------+---------+----------+
| Payload Length | NextHdr | HopLimit |
| (16) | (8) | (8) |
+-------------------+---------+----------+
| |
| Source Address |
| (128) |
| |
+-----+------+------+------+------+------+
| |
| Destination Address |
| (128) |
| |
+-----+------+------+------+------+------+
Figures in brackets represent field width in bits
*/
class Ip6ConfigForm : public QWidget, public Ui::Ip6
{
Q_OBJECT
public:
Ip6ConfigForm(QWidget *parent = 0);
private slots:
void on_srcAddr_editingFinished();
void on_dstAddr_editingFinished();
void on_srcAddrModeCombo_currentIndexChanged(int index);
void on_dstAddrModeCombo_currentIndexChanged(int index);
};
class Ip6Protocol : public AbstractProtocol
{
private:
OstProto::Ip6 data;
Ip6ConfigForm *configForm;
enum ip6field
{
// Frame Fields
ip6_version = 0,
ip6_trafficClass,
ip6_flowLabel,
ip6_payloadLength,
ip6_nextHeader,
ip6_hopLimit,
ip6_srcAddress,
ip6_dstAddress,
// Meta Fields
ip6_isOverrideVersion,
ip6_isOverridePayloadLength,
ip6_isOverrideNextHeader,
ip6_srcAddrMode,
ip6_srcAddrCount,
ip6_srcAddrPrefix,
ip6_dstAddrMode,
ip6_dstAddrCount,
ip6_dstAddrPrefix,
ip6_fieldCount
};
public:
Ip6Protocol(StreamBase *stream, AbstractProtocol *parent = 0);
virtual ~Ip6Protocol();
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 ProtocolIdType protocolIdType() const;
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 bool isProtocolFrameValueVariable() const;
virtual quint32 protocolFrameCksum(int streamIndex = 0,
CksumType cksumType = CksumIp) const;
virtual QWidget* configWidget();
virtual void loadConfigWidget();
virtual void storeConfigWidget();
};
#endif

61
common/ip6.proto Normal file
View File

@ -0,0 +1,61 @@
/*
Copyright (C) 2010 Srivats P.
This file is part of "Ostinato"
This is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
import "protocol.proto";
package OstProto;
// Ip6 Protocol
message Ip6 {
enum AddrMode {
kFixed = 0;
kIncHost = 1;
kDecHost = 2;
kRandomHost = 3;
}
optional bool is_override_version = 1;
optional bool is_override_payload_length = 2;
optional bool is_override_next_header = 3;
optional uint32 version = 4 [default = 0x6];
optional uint32 traffic_class = 5;
optional uint32 flow_label = 6;
optional uint32 payload_length = 7;
optional uint32 next_header = 8;
optional uint32 hop_limit = 9 [default = 127];
optional uint64 src_addr_hi = 10;
optional uint64 src_addr_lo = 11;
optional AddrMode src_addr_mode = 12 [default = kFixed];
optional uint32 src_addr_count = 13 [default = 16];
optional uint32 src_addr_prefix = 14 [default = 64];
optional uint64 dst_addr_hi = 15;
optional uint64 dst_addr_lo = 16;
optional AddrMode dst_addr_mode = 17 [default = kFixed];
optional uint32 dst_addr_count = 18 [default = 16];
optional uint32 dst_addr_prefix = 19 [default = 64];
}
extend Protocol {
optional Ip6 ip6 = 133;
}

467
common/ip6.ui Normal file
View File

@ -0,0 +1,467 @@
<ui version="4.0" >
<class>Ip6</class>
<widget class="QWidget" name="Ip6" >
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>506</width>
<height>233</height>
</rect>
</property>
<property name="windowTitle" >
<string>Form</string>
</property>
<layout class="QVBoxLayout" >
<item>
<layout class="QGridLayout" >
<item row="0" column="0" >
<widget class="QCheckBox" name="isVersionOverride" >
<property name="text" >
<string>Version</string>
</property>
</widget>
</item>
<item row="0" column="1" >
<widget class="QLineEdit" name="version" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="inputMask" >
<string/>
</property>
<property name="text" >
<string/>
</property>
</widget>
</item>
<item rowspan="3" row="0" column="2" >
<widget class="Line" name="line" >
<property name="orientation" >
<enum>Qt::Vertical</enum>
</property>
</widget>
</item>
<item row="0" column="3" >
<widget class="QCheckBox" name="isPayloadLengthOverride" >
<property name="text" >
<string>Payload Length</string>
</property>
</widget>
</item>
<item row="0" column="4" >
<widget class="QLineEdit" name="payloadLength" >
<property name="enabled" >
<bool>false</bool>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_22" >
<property name="text" >
<string>Traffic Class</string>
</property>
<property name="buddy" >
<cstring>trafficClass</cstring>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLineEdit" name="trafficClass" >
<property name="inputMask" >
<string>>HH; </string>
</property>
<property name="text" >
<string/>
</property>
</widget>
</item>
<item row="1" column="3" >
<widget class="QCheckBox" name="isNextHeaderOverride" >
<property name="text" >
<string>Next Header</string>
</property>
</widget>
</item>
<item row="1" column="4" >
<widget class="QLineEdit" name="nextHeader" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="inputMask" >
<string>HH; </string>
</property>
<property name="text" >
<string/>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_24" >
<property name="text" >
<string>Flow Label</string>
</property>
<property name="buddy" >
<cstring>flowLabel</cstring>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLineEdit" name="flowLabel" >
<property name="inputMask" >
<string>>H HH HH; </string>
</property>
</widget>
</item>
<item row="2" column="3" >
<widget class="QLabel" name="label_26" >
<property name="text" >
<string>Hop Limit</string>
</property>
<property name="buddy" >
<cstring>hopLimit</cstring>
</property>
</widget>
</item>
<item row="2" column="4" >
<widget class="QLineEdit" name="hopLimit" >
<property name="text" >
<string/>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="groupBox_7" >
<property name="title" >
<string/>
</property>
<property name="flat" >
<bool>false</bool>
</property>
<layout class="QGridLayout" >
<item row="0" column="0" >
<spacer>
<property name="orientation" >
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" >
<size>
<width>51</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1" >
<widget class="QLabel" name="label" >
<property name="text" >
<string>Address</string>
</property>
</widget>
</item>
<item row="0" column="2" >
<widget class="QLabel" name="label_31" >
<property name="text" >
<string>Mode</string>
</property>
</widget>
</item>
<item row="0" column="3" >
<widget class="QLabel" name="label_23" >
<property name="text" >
<string>Count</string>
</property>
</widget>
</item>
<item row="0" column="4" >
<widget class="QLabel" name="label_30" >
<property name="text" >
<string>Prefix</string>
</property>
</widget>
</item>
<item row="1" column="0" >
<widget class="QLabel" name="label_20" >
<property name="text" >
<string>Source</string>
</property>
</widget>
</item>
<item row="1" column="1" >
<widget class="QLineEdit" name="srcAddr" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string/>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="1" column="2" >
<widget class="QComboBox" name="srcAddrModeCombo" >
<item>
<property name="text" >
<string>Fixed</string>
</property>
</item>
<item>
<property name="text" >
<string>Increment Host</string>
</property>
</item>
<item>
<property name="text" >
<string>Decrement Host</string>
</property>
</item>
<item>
<property name="text" >
<string>Random Host</string>
</property>
</item>
</widget>
</item>
<item row="1" column="3" >
<widget class="QLineEdit" name="srcAddrCount" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize" >
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="text" >
<string/>
</property>
<property name="maxLength" >
<number>10</number>
</property>
</widget>
</item>
<item row="1" column="4" >
<widget class="QLineEdit" name="srcAddrPrefix" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize" >
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="inputMask" >
<string>/009; </string>
</property>
<property name="text" >
<string>/64</string>
</property>
</widget>
</item>
<item row="2" column="0" >
<widget class="QLabel" name="label_21" >
<property name="text" >
<string>Destination</string>
</property>
</widget>
</item>
<item row="2" column="1" >
<widget class="QLineEdit" name="dstAddr" >
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
<horstretch>1</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text" >
<string/>
</property>
<property name="alignment" >
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
</item>
<item row="2" column="2" >
<widget class="QComboBox" name="dstAddrModeCombo" >
<item>
<property name="text" >
<string>Fixed</string>
</property>
</item>
<item>
<property name="text" >
<string>Increment Host</string>
</property>
</item>
<item>
<property name="text" >
<string>Decrement Host</string>
</property>
</item>
<item>
<property name="text" >
<string>Random Host</string>
</property>
</item>
</widget>
</item>
<item row="2" column="3" >
<widget class="QLineEdit" name="dstAddrCount" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize" >
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="text" >
<string/>
</property>
<property name="maxLength" >
<number>10</number>
</property>
</widget>
</item>
<item row="2" column="4" >
<widget class="QLineEdit" name="dstAddrPrefix" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Preferred" >
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="maximumSize" >
<size>
<width>50</width>
<height>16777215</height>
</size>
</property>
<property name="inputMask" >
<string>/009; </string>
</property>
<property name="text" >
<string>/64</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<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>
<tabstops>
<tabstop>isVersionOverride</tabstop>
<tabstop>version</tabstop>
<tabstop>trafficClass</tabstop>
<tabstop>flowLabel</tabstop>
<tabstop>isPayloadLengthOverride</tabstop>
<tabstop>payloadLength</tabstop>
<tabstop>isNextHeaderOverride</tabstop>
<tabstop>nextHeader</tabstop>
<tabstop>hopLimit</tabstop>
<tabstop>srcAddr</tabstop>
<tabstop>srcAddrModeCombo</tabstop>
<tabstop>srcAddrCount</tabstop>
<tabstop>srcAddrPrefix</tabstop>
<tabstop>dstAddr</tabstop>
<tabstop>dstAddrModeCombo</tabstop>
<tabstop>dstAddrCount</tabstop>
<tabstop>dstAddrPrefix</tabstop>
</tabstops>
<resources/>
<connections>
<connection>
<sender>isVersionOverride</sender>
<signal>toggled(bool)</signal>
<receiver>version</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>67</x>
<y>22</y>
</hint>
<hint type="destinationlabel" >
<x>195</x>
<y>11</y>
</hint>
</hints>
</connection>
<connection>
<sender>isPayloadLengthOverride</sender>
<signal>toggled(bool)</signal>
<receiver>payloadLength</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>319</x>
<y>28</y>
</hint>
<hint type="destinationlabel" >
<x>493</x>
<y>29</y>
</hint>
</hints>
</connection>
<connection>
<sender>isNextHeaderOverride</sender>
<signal>toggled(bool)</signal>
<receiver>nextHeader</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel" >
<x>316</x>
<y>41</y>
</hint>
<hint type="destinationlabel" >
<x>348</x>
<y>46</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -0,0 +1,75 @@
/*
Copyright (C) 2010 Srivats P.
This file is part of "Ostinato"
This is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#ifndef _IPV6_ADDRESS_VALIDATOR_H
#define _IPV6_ADDRESS_VALIDATOR_H
#include <QValidator>
#include <QHostAddress>
class IPv6AddressValidator : public QValidator
{
public:
IPv6AddressValidator(QObject *parent = 0)
: QValidator(parent)
{
_ip6ValidChars.setPattern("[0-9a-fA-F]{0,4}(:[0-9a-fA-F]{0,4}){0,7}");
}
~IPv6AddressValidator() {}
virtual QValidator::State validate(QString &input, int &pos) const
{
QValidator::State state;
QHostAddress addr(input);
//qDebug("%s: %s (%d)", __FUNCTION__, input.toAscii().constData(), pos);
if (addr.protocol() == QAbstractSocket::IPv6Protocol)
state = Acceptable;
else
if (_ip6ValidChars.exactMatch(input))
state = Intermediate;
else
state = Invalid;
//qDebug("%s(%d): %s (%d), ", __FUNCTION__, state,
//input.toAscii().constData(), pos);
return state;
}
virtual void fixup(QString &input) const
{
input.append("::");
QHostAddress addr(input);
int len = input.size();
//qDebug("%s: %s", __FUNCTION__, input.toAscii().constData());
while (addr.protocol() != QAbstractSocket::IPv6Protocol)
{
len--;
Q_ASSERT(len >= 0);
addr.setAddress(input.left(len));
}
input = addr.toString();
}
private:
QRegExp _ip6ValidChars;
};
#endif

View File

@ -13,6 +13,7 @@ FORMS += \
vlan.ui \
arp.ui \
ip4.ui \
ip6.ui \
icmp.ui \
tcp.ui \
udp.ui \
@ -34,6 +35,7 @@ PROTOS += \
vlanstack.proto \
arp.proto \
ip4.proto \
ip6.proto \
ip4over4.proto \
icmp.proto \
tcp.proto \
@ -61,6 +63,7 @@ HEADERS += \
vlanstack.h \
arp.h \
ip4.h \
ip6.h \
ip4over4.h \
icmp.h \
tcp.h \
@ -84,6 +87,7 @@ SOURCES += \
svlan.cpp \
arp.cpp \
ip4.cpp \
ip6.cpp \
icmp.cpp \
tcp.cpp \
udp.cpp \

View File

@ -102,6 +102,7 @@ message Protocol {
kIp4FieldNumber = 130;
kArpFieldNumber = 131;
kIp4over4FieldNumber = 132;
kIp6FieldNumber = 133;
kTcpFieldNumber = 140;
kUdpFieldNumber = 141;

View File

@ -33,6 +33,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include "vlanstack.h"
#include "arp.h"
#include "ip4.h"
#include "ip6.h"
#include "ip4over4.h"
#include "icmp.h"
#include "tcp.h"
@ -75,6 +76,8 @@ ProtocolManager::ProtocolManager()
(void*) ArpProtocol::createInstance);
registerProtocol(OstProto::Protocol::kIp4FieldNumber,
(void*) Ip4Protocol::createInstance);
registerProtocol(OstProto::Protocol::kIp6FieldNumber,
(void*) Ip6Protocol::createInstance);
registerProtocol(OstProto::Protocol::kIp4over4FieldNumber,
(void*) Ip4over4Protocol::createInstance);