diff --git a/common/igmp.h b/common/igmp.h
index a5d50d4..6ee9ad3 100644
--- a/common/igmp.h
+++ b/common/igmp.h
@@ -81,6 +81,7 @@ protected:
virtual bool isSsmQuery() const;
virtual quint16 checksum(int streamIndex) const;
+
private:
int mrc(int value) const;
};
diff --git a/common/iputils.h b/common/iputils.h
index d135f41..466880f 100644
--- a/common/iputils.h
+++ b/common/iputils.h
@@ -28,7 +28,7 @@ enum AddrMode {
kRandom = 3
};
-quint32 ipAddress(quint32 baseIp, int prefix, AddrMode mode, int count,
+quint32 inline ipAddress(quint32 baseIp, int prefix, AddrMode mode, int count,
int index)
{
int u;
@@ -66,5 +66,56 @@ quint32 ipAddress(quint32 baseIp, int prefix, AddrMode mode, int count,
return ip;
}
+void inline ipAddress(quint64 baseIpHi, quint64 baseIpLo, int prefix,
+ AddrMode mode, int count, int index, quint64 &ipHi, quint64 &ipLo)
+{
+ int u, p, q;
+ quint64 maskHi = 0, maskLo = 0;
+ quint64 prefixHi, prefixLo;
+ quint64 hostHi, hostLo;
+
+ switch(mode)
+ {
+ case kFixed:
+ ipHi = baseIpHi;
+ ipLo = baseIpLo;
+ break;
+ case kIncrement:
+ case kDecrement:
+ case kRandom:
+ u = index % count;
+ if (prefix > 64) {
+ p = 64;
+ q = prefix - 64;
+ } else {
+ p = prefix;
+ q = 0;
+ }
+ if (p > 0)
+ maskHi = ~((quint64(1) << p) - 1);
+ if (q > 0)
+ maskLo = ~((quint64(1) << q) - 1);
+ prefixHi = baseIpHi & maskHi;
+ prefixLo = baseIpLo & maskLo;
+ if (mode == kIncrement) {
+ hostHi = ((baseIpHi & ~maskHi) + u) & ~maskHi;
+ hostLo = ((baseIpLo & ~maskLo) + u) & ~maskLo;
+ }
+ else if (mode == kDecrement) {
+ hostHi = ((baseIpHi & ~maskHi) - u) & ~maskHi;
+ hostLo = ((baseIpLo & ~maskLo) - u) & ~maskLo;
+ }
+ else if (mode==kRandom) {
+ hostHi = qrand() & ~maskHi;
+ hostLo = qrand() & ~maskLo;
+ }
+ ipHi = prefixHi | hostHi;
+ ipLo = prefixLo | hostLo;
+ break;
+ default:
+ qWarning("Unhandled mode = %d", mode);
+ }
+}
+
} // namespace ipUtils
#endif
diff --git a/common/ipv6addressdelegate.h b/common/ipv6addressdelegate.h
new file mode 100644
index 0000000..9e3c30e
--- /dev/null
+++ b/common/ipv6addressdelegate.h
@@ -0,0 +1,60 @@
+/*
+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
+*/
+#ifndef _IPV4_ADDRESS_DELEGATE
+#define _IPV4_ADDRESS_DELEGATE
+
+#include "ipv6addressvalidator.h"
+
+#include
+#include
+
+class IPv6AddressDelegate : public QItemDelegate
+{
+ Q_OBJECT
+public:
+ IPv6AddressDelegate(QObject *parent = 0);
+ ~IPv6AddressDelegate();
+
+ QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option,
+ const QModelIndex &index) const;
+};
+
+inline IPv6AddressDelegate::IPv6AddressDelegate(QObject *parent)
+ : QItemDelegate(parent)
+{
+}
+
+inline IPv6AddressDelegate::~IPv6AddressDelegate()
+{
+}
+
+inline QWidget* IPv6AddressDelegate::createEditor(QWidget *parent,
+ const QStyleOptionViewItem &option, const QModelIndex &index) const
+{
+ QLineEdit *ipEdit;
+
+ ipEdit = static_cast(QItemDelegate::createEditor(
+ parent, option, index));
+
+ ipEdit->setValidator(new IPv6AddressValidator(ipEdit));
+
+ return ipEdit;
+}
+#endif
+
diff --git a/common/mld.cpp b/common/mld.cpp
index 7caf77a..9427642 100644
--- a/common/mld.cpp
+++ b/common/mld.cpp
@@ -19,42 +19,33 @@ along with this program. If not, see
#include "mld.h"
+#include "ipv6addressdelegate.h"
#include "ipv6addressvalidator.h"
+#include "iputils.h"
#include
-#include
#include
-class IpAddressDelegate : public QItemDelegate
-{
-public:
- IpAddressDelegate(QObject *parent = 0)
- : QItemDelegate(parent) { }
- ~IpAddressDelegate() {}
- QWidget* createEditor(QWidget *parent,
- const QStyleOptionViewItem &option, const QModelIndex &index) const
- {
- QLineEdit *ipEdit;
-
- ipEdit = static_cast(QItemDelegate::createEditor(
- parent, option, index));
-
- // FIXME: const problem!!!
- //ipEdit->setValidator(new IPv6AddressValidator(this));
-
- return ipEdit;
- }
-};
-
MldConfigForm::MldConfigForm(QWidget *parent)
: GmpConfigForm(parent)
{
connect(msgTypeCombo, SIGNAL(currentIndexChanged(int)),
SLOT(on_msgTypeCombo_currentIndexChanged(int)));
+ msgTypeCombo->setValueMask(0xFF);
+ msgTypeCombo->addItem(kMldV1Query, "MLDv1 Query");
+ msgTypeCombo->addItem(kMldV1Report, "MLDv1 Report");
+ msgTypeCombo->addItem(kMldV1Done, "MLDv1 Done");
+ msgTypeCombo->addItem(kMldV2Query, "MLDv2 Query");
+ msgTypeCombo->addItem(kMldV2Report, "MLDv2 Report");
+
+ _defaultGroupIp = "::";
_defaultSourceIp = "::";
- sourceList->setItemDelegate(new IpAddressDelegate(this));
- groupRecordSourceList->setItemDelegate(new IpAddressDelegate(this));
+
+ groupAddress->setValidator(new IPv6AddressValidator(this));
+ groupRecordAddress->setValidator(new IPv6AddressValidator(this));
+ sourceList->setItemDelegate(new IPv6AddressDelegate(this));
+ groupRecordSourceList->setItemDelegate(new IPv6AddressDelegate(this));
}
void MldConfigForm::on_msgTypeCombo_currentIndexChanged(int /*index*/)
@@ -90,6 +81,8 @@ void MldConfigForm::on_msgTypeCombo_currentIndexChanged(int /*index*/)
MldProtocol::MldProtocol(StreamBase *stream, AbstractProtocol *parent)
: GmpProtocol(stream, parent)
{
+ _hasPayload = false;
+
data.set_type(kMldV1Query);
}
@@ -179,15 +172,15 @@ QVariant MldProtocol::fieldData(int index, FieldAttrib attrib,
case kMldMrt:
{
- quint16 mrt = 0, mrc;
+ quint16 mrt = 0, mrcode = 0;
if (msgType() == kMldV2Query)
{
mrt = data.max_response_time();
- mrc = mrt; // TODO: MR Code
+ mrcode = mrc(mrt);
}
- if (msgType() == kMldV1Query)
- mrc = mrt = data.max_response_time() & 0xFFFF;
+ else if (msgType() == kMldV1Query)
+ mrcode = mrt = data.max_response_time() & 0xFFFF;
switch(attrib)
{
@@ -204,7 +197,32 @@ QVariant MldProtocol::fieldData(int index, FieldAttrib attrib,
QByteArray fv;
fv.resize(2);
- qToBigEndian(mrc, (uchar*) fv.data());
+ qToBigEndian(mrcode, (uchar*) fv.data());
+ return fv;
+ }
+ default:
+ break;
+ }
+ break;
+ }
+ case kMldRsvd:
+ {
+ quint16 rsvd = 0;
+
+ switch(attrib)
+ {
+ case FieldName:
+ return QString("Reserved");
+ case FieldValue:
+ return rsvd;
+ case FieldTextValue:
+ return QString("%1").arg(rsvd);
+ case FieldFrameValue:
+ {
+ QByteArray fv;
+
+ fv.resize(2);
+ qToBigEndian(rsvd, (uchar*) fv.data());
return fv;
}
default:
@@ -215,24 +233,24 @@ QVariant MldProtocol::fieldData(int index, FieldAttrib attrib,
case kGroupAddress:
{
quint64 grpHi, grpLo;
-#if 0
- AbstractProtocol::getip(
+
+ ipUtils::ipAddress(
data.group_address().v6_hi(),
data.group_address().v6_lo(),
- data.group_mode(),
- data.group_count(),
data.group_prefix(),
- &grpHi,
- &grpLo);
-#endif
+ ipUtils::AddrMode(data.group_mode()),
+ data.group_count(),
+ streamIndex,
+ grpHi,
+ grpLo);
switch(attrib)
{
case FieldName:
return QString("Group Address");
case FieldValue:
- case FieldFrameValue:
case FieldTextValue:
+ case FieldFrameValue:
{
QByteArray fv;
fv.resize(16);
@@ -250,22 +268,36 @@ QVariant MldProtocol::fieldData(int index, FieldAttrib attrib,
}
case kSources:
{
- quint64 grpHi, grpLo;
-
switch(attrib)
{
case FieldName:
return QString("Source List");
case FieldValue:
- return QVariant(); // FIXME
+ {
+ QStringList list;
+ QByteArray fv;
+ fv.resize(16);
+ for (int i = 0; i < data.sources_size(); i++)
+ {
+ qToBigEndian(data.group_address().v6_hi(),
+ (uchar*)fv.data());
+ qToBigEndian(data.group_address().v6_hi(),
+ (uchar*)fv.data()+8);
+
+ list << QHostAddress((quint8*)fv.constData()).toString();
+ }
+ return list;
+ }
case FieldFrameValue:
{
QByteArray fv;
fv.resize(16 * data.sources_size());
for (int i = 0; i < data.sources_size(); i++)
{
- qToBigEndian(grpHi, (uchar*)(fv.data() + i*16));
- qToBigEndian(grpLo, (uchar*)(fv.data() + i*16 + 8));
+ qToBigEndian(data.group_address().v6_hi(),
+ (uchar*)(fv.data() + i*16));
+ qToBigEndian(data.group_address().v6_lo(),
+ (uchar*)(fv.data() + i*16 + 8));
}
return fv;
}
@@ -276,8 +308,10 @@ QVariant MldProtocol::fieldData(int index, FieldAttrib attrib,
fv.resize(16);
for (int i = 0; i < data.sources_size(); i++)
{
- qToBigEndian(grpHi, (uchar*)fv.data());
- qToBigEndian(grpLo, (uchar*)fv.data()+8);
+ qToBigEndian(data.group_address().v6_hi(),
+ (uchar*)fv.data());
+ qToBigEndian(data.group_address().v6_hi(),
+ (uchar*)fv.data()+8);
list << QHostAddress((quint8*)fv.constData()).toString();
}
@@ -289,8 +323,117 @@ QVariant MldProtocol::fieldData(int index, FieldAttrib attrib,
break;
}
case kGroupRecords:
- // TODO
+ {
+ switch(attrib)
+ {
+ case FieldValue:
+ {
+ QVariantList grpRecords = GmpProtocol::fieldData(
+ index, attrib, streamIndex).toList();
+ QByteArray ip;
+
+ ip.resize(16);
+
+ for (int i = 0; i < data.group_records_size(); i++)
+ {
+ QVariantMap grpRec = grpRecords.at(i).toMap();
+ OstProto::Gmp::GroupRecord rec = data.group_records(i);
+
+ qToBigEndian(rec.group_address().v6_hi(),
+ (uchar*)(ip.data()));
+ qToBigEndian(rec.group_address().v6_lo(),
+ (uchar*)(ip.data() + 8));
+ grpRec["groupRecordAddress"] = QHostAddress(ip.constData())
+ .toString();
+
+ QStringList sl;
+ for (int j = 0; j < rec.sources_size(); j++)
+ {
+ qToBigEndian(rec.sources(j).v6_hi(),
+ (uchar*)(ip.data()));
+ qToBigEndian(rec.sources(j).v6_lo(),
+ (uchar*)(ip.data() + 8));
+ sl.append(QHostAddress(ip.constData()).toString());
+ }
+ grpRec["groupRecordSourceList"] = sl;
+
+ grpRecords.replace(i, grpRec);
+ }
+ return grpRecords;
+ }
+ case FieldFrameValue:
+ {
+ QVariantList list = GmpProtocol::fieldData(
+ index, attrib, streamIndex).toList();
+ QByteArray fv;
+ QByteArray ip;
+ ip.resize(16);
+
+ for (int i = 0; i < data.group_records_size(); i++)
+ {
+ OstProto::Gmp::GroupRecord rec = data.group_records(i);
+ QByteArray rv = list.at(i).toByteArray();
+
+ rv.insert(4, QByteArray(16+16*rec.sources_size(), char(0)));
+ qToBigEndian(rec.group_address().v6_hi(),
+ (uchar*)(rv.data()+4));
+ qToBigEndian(rec.group_address().v6_hi(),
+ (uchar*)(rv.data()+4+8));
+ for (int j = 0; j < rec.sources_size(); j++)
+ {
+ qToBigEndian(rec.sources(j).v6_hi(),
+ (uchar*)(rv.data()+12+16*j));
+ qToBigEndian(rec.sources(j).v6_lo(),
+ (uchar*)(rv.data()+12+16*j));
+ }
+
+ fv.append(rv);
+ }
+ return fv;
+ }
+ case FieldTextValue:
+ {
+ QStringList list = GmpProtocol::fieldData(
+ index, attrib, streamIndex).toStringList();
+ QByteArray ip;
+
+ ip.resize(16);
+
+ for (int i = 0; i < data.group_records_size(); i++)
+ {
+ OstProto::Gmp::GroupRecord rec = data.group_records(i);
+ QString recStr = list.at(i);
+ QString str;
+
+ qToBigEndian(rec.group_address().v6_hi(),
+ (uchar*)(ip.data()));
+ qToBigEndian(rec.group_address().v6_lo(),
+ (uchar*)(ip.data() + 8));
+ str.append(QString("Group: %1").arg(
+ QHostAddress(ip.constData()).toString()));
+
+ str.append("; Sources: ");
+ QStringList sl;
+ for (int j = 0; j < rec.sources_size(); j++)
+ {
+ qToBigEndian(rec.sources(j).v6_hi(),
+ (uchar*)(ip.data()));
+ qToBigEndian(rec.sources(j).v6_lo(),
+ (uchar*)(ip.data() + 8));
+ sl.append(QHostAddress(ip.constData()).toString());
+ }
+ str.append(sl.join(", "));
+
+ recStr.replace("XXX", str);
+ list.replace(i, recStr);
+ }
+ return list.join("\n").insert(0, "\n");
+ }
+ default:
+ break;
+ }
break;
+ }
default:
break;
}
@@ -336,12 +479,106 @@ bool MldProtocol::setFieldData(int index, const QVariant &value,
}
case kSources:
- //TODO
+ {
+ QStringList list = value.toStringList();
+
+ data.clear_sources();
+ foreach(QString str, list)
+ {
+ OstProto::Gmp::IpAddress *src = data.add_sources();
+ Q_IPV6ADDR addr = QHostAddress(str).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);
+ src->set_v6_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);
+ src->set_v6_lo(x);
+ }
break;
+ }
case kGroupRecords:
- //TODO
+ {
+ GmpProtocol::setFieldData(index, value, attrib);
+ QVariantList list = value.toList();
+
+ for (int i = 0; i < list.count(); i++)
+ {
+ QVariantMap grpRec = list.at(i).toMap();
+ OstProto::Gmp::GroupRecord *rec = data.mutable_group_records(i);
+ Q_IPV6ADDR addr = QHostAddress(
+ grpRec["groupRecordAddress"].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);
+ rec->mutable_group_address()->set_v6_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);
+ rec->mutable_group_address()->set_v6_lo(x);
+
+ QStringList srcList = grpRec["groupRecordSourceList"]
+ .toStringList();
+ rec->clear_sources();
+ foreach (QString str, srcList)
+ {
+ OstProto::Gmp::IpAddress *src = rec->add_sources();
+ Q_IPV6ADDR addr = QHostAddress(str).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);
+ src->set_v6_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);
+ src->set_v6_lo(x);
+ }
+ }
+
break;
+ }
default:
isOk = GmpProtocol::setFieldData(index, value, attrib);
@@ -370,41 +607,13 @@ void MldProtocol::loadConfigWidget()
configForm->maxResponseTime->setText(
fieldData(kMldMrt, FieldValue).toString());
-#if 0
- configForm->mldA->setText(fieldData(mld_a, FieldValue).toString());
- configForm->mldB->setText(fieldData(mld_b, FieldValue).toString());
-
- configForm->mldPayloadLength->setText(
- fieldData(mld_payloadLength, FieldValue).toString());
-
- configForm->isChecksumOverride->setChecked(
- fieldData(mld_is_override_checksum, FieldValue).toBool());
- configForm->mldChecksum->setText(uintToHexStr(
- fieldData(mld_checksum, FieldValue).toUInt(), 2));
-
- configForm->mldX->setText(fieldData(mld_x, FieldValue).toString());
- configForm->mldY->setText(fieldData(mld_y, FieldValue).toString());
-#endif
}
void MldProtocol::storeConfigWidget()
{
- bool isOk;
-
GmpProtocol::storeConfigWidget();
-#if 0
- setFieldData(mld_a, configForm->mldA->text());
- setFieldData(mld_b, configForm->mldB->text());
-
- setFieldData(mld_payloadLength, configForm->mldPayloadLength->text());
- setFieldData(mld_is_override_checksum,
- configForm->isChecksumOverride->isChecked());
- setFieldData(mld_checksum, configForm->mldChecksum->text().toUInt(&isOk, BASE_HEX));
-
- setFieldData(mld_x, configForm->mldX->text());
- setFieldData(mld_y, configForm->mldY->text());
-#endif
+ setFieldData(kMldMrt, configForm->maxResponseTime->text());
}
quint16 MldProtocol::checksum(int streamIndex) const
diff --git a/common/mld.h b/common/mld.h
index a66965f..bc2d95e 100644
--- a/common/mld.h
+++ b/common/mld.h
@@ -16,15 +16,12 @@ 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
*/
-
#ifndef _MLD_H
#define _MLD_H
#include "mld.pb.h"
#include "gmp.h"
-#include "abstractprotocol.h"
-
// MLD uses the same msg type value for 'Query' messages across
// versions despite the fields being different. To distinguish
// Query messages of different versions, we use an additional
@@ -75,12 +72,16 @@ public:
virtual QWidget* configWidget();
virtual void loadConfigWidget();
virtual void storeConfigWidget();
+
protected:
virtual bool isSsmReport() const;
virtual bool isQuery() const;
virtual bool isSsmQuery() const;
virtual quint16 checksum(int streamIndex) const;
+
+private:
+ int mrc(int value) const;
};
inline bool MldProtocol::isSsmReport() const
@@ -99,5 +100,9 @@ inline bool MldProtocol::isSsmQuery() const
return (msgType() == kMldV2Query);
}
+inline int MldProtocol::mrc(int value) const
+{
+ return quint16(value); // TODO: if value > 128, convert to mantissa/exp form
+}
#endif
diff --git a/common/ostproto.pro b/common/ostproto.pro
index c513a31..39bfa5c 100644
--- a/common/ostproto.pro
+++ b/common/ostproto.pro
@@ -74,6 +74,7 @@ HEADERS += \
ip4.h \
ip6.h \
ipv4addressdelegate.h \
+ ipv6addressdelegate.h \
ip6over4.h \
ip4over6.h \
ip4over4.h \