From 1d1e6479c384ddb75c689a51fa9f635ca2d488c1 Mon Sep 17 00:00:00 2001 From: "Srivats P." Date: Sun, 7 Nov 2010 18:10:09 +0530 Subject: [PATCH] MLD review and rework --- common/igmp.h | 1 + common/iputils.h | 53 ++++- common/ipv6addressdelegate.h | 60 ++++++ common/mld.cpp | 361 +++++++++++++++++++++++++++-------- common/mld.h | 11 +- common/ostproto.pro | 1 + 6 files changed, 407 insertions(+), 80 deletions(-) create mode 100644 common/ipv6addressdelegate.h 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 \