Review and rework of GMP and IGMP

This commit is contained in:
Srivats P. 2010-11-06 23:29:44 +05:30
parent d4408f0fc1
commit dbc7409616
10 changed files with 339 additions and 223 deletions

View File

@ -5,7 +5,6 @@ win32:RC_FILE = ostinato.rc
macx:ICON = icons/logo.icns
QT += network script
INCLUDEPATH += "../rpc/" "../common/"
LIBS += -lprotobuf
win32 {
CONFIG(debug, debug|release) {
LIBS += -L"../common/debug" -lostproto
@ -25,6 +24,7 @@ win32 {
LIBS += -L"../rpc" -lpbrpc
POST_TARGETDEPS += "../common/libostproto.a" "../rpc/libpbrpc.a"
}
LIBS += -lprotobuf
RESOURCES += ostinato.qrc
HEADERS += \
dumpview.h \

View File

@ -22,11 +22,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include <QHeaderView>
#include <qendian.h>
QHash<int, int> GmpProtocol::frameFieldCountMap;
GmpConfigForm::GmpConfigForm(QWidget *parent)
: QWidget(parent)
{
setupUi(this);
// TODO: this should be in subclass
msgTypeCombo->setValueMask(0xFF);
msgTypeCombo->addItem(kIgmpV1Query, "IGMPv1 Query");
msgTypeCombo->addItem(kIgmpV1Report, "IGMPv1 Report");
@ -70,14 +73,14 @@ void GmpConfigForm::on_msgTypeCombo_currentIndexChanged(int /*index*/)
case kIgmpV3Query:
case kMldV2Query:
asmGroup->hide();
ssmWidget->setCurrentIndex(0);
ssmWidget->setCurrentIndex(kSsmQueryPage);
ssmWidget->show();
break;
case kIgmpV3Report:
case kMldV2Report:
asmGroup->hide();
ssmWidget->setCurrentIndex(1);
ssmWidget->setCurrentIndex(kSsmReportPage);
ssmWidget->show();
break;
@ -88,6 +91,14 @@ void GmpConfigForm::on_msgTypeCombo_currentIndexChanged(int /*index*/)
}
}
void GmpConfigForm::on_groupMode_currentIndexChanged(int index)
{
bool disabled = (index == 0);
groupCount->setDisabled(disabled);
groupPrefix->setDisabled(disabled);
}
void GmpConfigForm::on_addSource_clicked()
{
QListWidgetItem *item=new QListWidgetItem(_defaultSourceIp);
@ -113,13 +124,14 @@ void GmpConfigForm::on_addGroupRecord_clicked()
QListWidgetItem *item = new QListWidgetItem;
grpRec["groupRecordType"] = defRec.type()-1;
grpRec["groupRecordAddress"] = _defaultSourceIp;
grpRec["overrideGroupRecordSourceCount"] = defRec.is_override_source_count();
grpRec["groupRecordAddress"] = _defaultGroupIp;
grpRec["overrideGroupRecordSourceCount"] =defRec.is_override_source_count();
grpRec["groupRecordSourceCount"] = defRec.source_count();
grpRec["groupRecordSourceList"] = QStringList();
grpRec["overrideAuxDataLength"] = defRec.is_override_aux_data_length();
grpRec["auxDataLength"] = defRec.aux_data_length();
grpRec["auxData"] = QString().fromStdString(defRec.aux_data());
grpRec["auxData"] = QByteArray().append(
QString().fromStdString(defRec.aux_data()));
item->setData(Qt::UserRole, grpRec);
item->setText(QString("%1: %2")
@ -167,7 +179,7 @@ void GmpConfigForm::on_groupList_currentItemChanged(QListWidgetItem *current,
rec["groupRecordSourceCount"] = groupRecordSourceCount->text().toUInt();
rec["overrideAuxDataLength"] = overrideAuxDataLength->isChecked();
rec["auxDataLength"] = auxDataLength->text().toUInt();
rec["auxData"] = auxData->text();
rec["auxData"] = QByteArray().fromHex(QByteArray().append(auxData->text()));
previous->setData(Qt::UserRole, rec);
previous->setText(QString("%1: %2")
@ -196,7 +208,7 @@ _load_current_record:
rec["groupRecordSourceCount"].toUInt()));
overrideAuxDataLength->setChecked(rec["overrideAuxDataLength"].toBool());
auxDataLength->setText(QString().setNum(rec["auxDataLength"].toUInt()));
auxData->setText(rec["auxData"].toString());
auxData->setText(QString(rec["auxData"].toByteArray().toHex()));
_exit:
groupRecord->setEnabled(current != NULL);
@ -254,46 +266,24 @@ int GmpProtocol::fieldCount() const
int GmpProtocol::frameFieldCount() const
{
int count = 0;
int type = msgType();
// TODO: optimize!!!!!
// frameFieldCountMap contains the frameFieldCounts for each
// msgType - this is built on demand and cached for subsequent use
// lookup if we have already cached ...
if (frameFieldCountMap.contains(type))
return frameFieldCountMap.value(type);
// ... otherwise calculate and cache
int count = 0;
for (int i = 0; i < FIELD_COUNT; i++)
{
if (fieldFlags(i).testFlag(AbstractProtocol::FrameField))
count++;
}
frameFieldCountMap.insert(type, count);
return count;
#if 0
switch(msgType())
{
// IGMP
case kIgmpV1Query:
case kIgmpV1Report:
case kIgmpV2Query:
case kIgmpV2Report:
case kIgmpV2Leave:
return FIELD_COUNT_ASM_ALL;
case kIgmpV3Query:
return FIELD_COUNT_SSM_QUERY;
case kIgmpV3Report:
return FIELD_COUNT_SSM_REPORT;
// MLD
case kMldV1Query:
case kMldV1Report:
case kMldV1Done:
return FIELD_COUNT_ASM_ALL;
case kMldV2Query:
return FIELD_COUNT_SSM_QUERY;
case kMldV2Report:
return FIELD_COUNT_SSM_REPORT;
default:
return FIELD_COUNT_ASM_ALL;
}
#endif
}
AbstractProtocol::FieldFlags GmpProtocol::fieldFlags(int index) const
@ -316,6 +306,7 @@ AbstractProtocol::FieldFlags GmpProtocol::fieldFlags(int index) const
break;
case kMldMrt:
case kMldRsvd:
// MLD subclass should handle suitably
break;
case kGroupAddress:
@ -404,13 +395,21 @@ QVariant GmpProtocol::fieldData(int index, FieldAttrib attrib,
}
case kChecksum:
{
switch(attrib)
{
case FieldName:
return QString("Checksum");
case FieldBitSize:
return 16;
default:
break;
}
quint16 cksum = data.is_override_checksum() ?
data.checksum() : checksum(streamIndex);
switch(attrib)
{
case FieldName:
return QString("Checksum");
case FieldValue:
return cksum;
case FieldFrameValue:
@ -423,14 +422,13 @@ QVariant GmpProtocol::fieldData(int index, FieldAttrib attrib,
}
case FieldTextValue:
return QString("0x%1").arg(cksum, 4, BASE_HEX, QChar('0'));
case FieldBitSize:
return 16;
default:
break;
}
break;
}
case kMldMrt:
case kMldRsvd:
// XXX: Present only in MLD - hence handled by the mld subclass
break;
@ -440,7 +438,7 @@ QVariant GmpProtocol::fieldData(int index, FieldAttrib attrib,
case kRsvd1:
{
int rsvd = 0;
quint8 rsvd = 0;
switch(attrib)
{
@ -513,8 +511,8 @@ QVariant GmpProtocol::fieldData(int index, FieldAttrib attrib,
return QString("%1").arg(qqi);
case FieldFrameValue:
{
quint8 qqic = qqi; // TODO: derive code from qqi
return QByteArray(1, char(qqic));
char qqicode = char(qqic(qqi));
return QByteArray(1, qqicode);
}
default:
break;
@ -628,7 +626,7 @@ QVariant GmpProtocol::fieldData(int index, FieldAttrib attrib,
rec.is_override_aux_data_length();
grpRec["auxDataLength"] = rec.aux_data_length();
grpRec["auxData"] = QByteArray().append(
QString::fromStdString(rec.aux_data())).toHex();
QString::fromStdString(rec.aux_data()));
grpRecords.append(grpRec);
}
@ -641,26 +639,23 @@ QVariant GmpProtocol::fieldData(int index, FieldAttrib attrib,
{
OstProto::Gmp::GroupRecord rec = data.group_records(i);
QByteArray rv;
quint16 srcCount;
rv.resize(4);
rv[0] = rec.type();
rv[1] = rec.is_override_aux_data_length() ?
rec.aux_data_length() : rec.aux_data().size()/4;
if (rec.is_override_source_count())
{
qToBigEndian(quint16(rec.source_count()),
(uchar*)(rv.data()+2));
}
srcCount = rec.source_count();
else
{
qToBigEndian(quint16(rec.sources_size()),
(uchar*)(rv.data()+2));
}
srcCount = rec.sources_size();
qToBigEndian(srcCount, (uchar*)(rv.data()+2));
// group_address => subclass responsibility
// source list => subclass responsibility
rv.append(QString().fromStdString(rec.aux_data()).toUtf8());
rv.append(QString().fromStdString(rec.aux_data()));
fv.append(rv);
}
@ -823,6 +818,7 @@ bool GmpProtocol::setFieldData(int index, const QVariant &value,
}
case kGroupAddress:
// XXX: Handled by subclass
isOk = false;
break;
case kRsvd1:
isOk = false;
@ -843,7 +839,7 @@ bool GmpProtocol::setFieldData(int index, const QVariant &value,
}
case kQqic:
{
uint qqi = value.toUInt(&isOk); // TODO: QQIC or QQI??
uint qqi = value.toUInt(&isOk);
if (isOk)
data.set_qqi(qqi);
break;
@ -857,6 +853,7 @@ bool GmpProtocol::setFieldData(int index, const QVariant &value,
}
case kSources:
// XXX: Handled by subclass
isOk = false;
break;
case kRsvd2:
isOk = false;
@ -889,8 +886,7 @@ bool GmpProtocol::setFieldData(int index, const QVariant &value,
rec->set_is_override_aux_data_length(
grpRec["overrideAuxDataLength"].toBool());
rec->set_aux_data_length(grpRec["auxDataLength"].toUInt());
QByteArray ba = QByteArray::fromHex(
grpRec["auxData"].toByteArray());
QByteArray ba = grpRec["auxData"].toByteArray();
// pad to word boundary
if (ba.size() % 4)
ba.append(QByteArray(4 - (ba.size() % 4), char(0)));
@ -956,12 +952,6 @@ _exit:
return isOk;
}
/*!
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
*/
int GmpProtocol::protocolFrameSize(int streamIndex) const
{
// TODO: Calculate to reduce processing cost
@ -987,8 +977,7 @@ void GmpProtocol::loadConfigWidget()
configWidget();
configForm->msgTypeCombo->setValue(fieldData(kType, FieldValue).toUInt());
configForm->maxResponseTime->setText(QString("%1").arg(
data.max_response_time()));
// XXX: configForm->maxResponseTime set by subclass
configForm->overrideChecksum->setChecked(
fieldData(kIsOverrideChecksum, FieldValue).toBool());
configForm->checksum->setText(uintToHexStr(
@ -1049,7 +1038,7 @@ void GmpProtocol::storeConfigWidget()
configForm->update();
setFieldData(kType, configForm->msgTypeCombo->currentValue());
setFieldData(kMldMrt, configForm->maxResponseTime->text());
// XXX: configForm->maxResponseTime handled by subclass
setFieldData(kIsOverrideChecksum,
configForm->overrideChecksum->isChecked());
setFieldData(kChecksum,
@ -1077,8 +1066,8 @@ void GmpProtocol::storeConfigWidget()
QVariantList grpList;
for (int i = 0; i < configForm->groupList->count(); i++)
{
grpList.append(configForm->groupList->item(i)->data(Qt::UserRole)
.toMap());
QVariant grp = configForm->groupList->item(i)->data(Qt::UserRole);
grpList.append(grp.toMap());
}
setFieldData(kGroupRecords, grpList);

View File

@ -25,34 +25,35 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include "abstractprotocol.h"
enum GmpMsgType
{
kIgmpV1Query = 0x11,
kIgmpV1Report = 0x12,
#include <QHash>
kIgmpV2Query = 0xFF11,
kIgmpV2Report = 0x16,
kIgmpV2Leave = 0x17,
// Both IGMP and MLD use the same msg type value for 'Query' message
// across versions despite the fields being different. To distinguish
// Query messages of different versions, we use an additional upper byte
enum GmpMsgType
{
// IGMP
kIgmpV1Query = 0x11,
kIgmpV1Report = 0x12,
kIgmpV3Query = 0xFE11,
kIgmpV3Report = 0x22,
kIgmpV2Query = 0xFF11,
kIgmpV2Report = 0x16,
kIgmpV2Leave = 0x17,
kMldV1Query = 0x82,
kMldV1Report = 0x83,
kMldV1Done = 0x84,
kIgmpV3Query = 0xFE11,
kIgmpV3Report = 0x22,
kMldV2Query = 0xFF82,
kMldV2Report = 0x8F
};
// MLD
kMldV1Query = 0x82,
kMldV1Report = 0x83,
kMldV1Done = 0x84,
kMldV2Query = 0xFF82,
kMldV2Report = 0x8F
};
/*
TODO:FIXME
Gmp Protocol Frame Format -
+-----+------+------+------+------+------+
| A | B | LEN | CSUM | X | Y |
| (3) | (13) | (16) | (16) | (32) | (32) |
+-----+------+------+------+------+------+
Figures in brackets represent field width in bits
Gmp Protocol Frame Format - TODO: for now see the respective RFCs
*/
class GmpProtocol;
@ -64,9 +65,16 @@ public:
~GmpConfigForm();
void update();
protected:
QString _defaultGroupIp;
QString _defaultSourceIp;
private:
enum {
kSsmQueryPage = 0,
kSsmReportPage = 1
};
private slots:
void on_msgTypeCombo_currentIndexChanged(int index);
void on_groupMode_currentIndexChanged(int index);
void on_addSource_clicked();
void on_deleteSource_clicked();
@ -109,24 +117,18 @@ protected:
// ------------
// Frame Fields
// ------------
// Fields used in all ASM and SSM messages, unless otherwise specified
kType = 0,
kRsvdMrtCode,
kChecksum,
kMldMrt, // MLD Only (except MLDv2 Report)
kMldRsvd, // MLD Only (except MLDv2 Report)
// Used ONLY in -
// IGMPv1: Query, Report
// IGMPv2: Report, Leave (v2 uses v1 Query only)
// IGMPv3: Query
// MLDv1: Query, Report, Done
// MLDv2: Query
// Field used in ASM messages
kGroupAddress,
FIELD_COUNT_ASM_ALL,
// Used ONLY in -
// IGMPv3: Query
// MLDv2: Query
// Fields used in SSM Query
kRsvd1 = FIELD_COUNT_ASM_ALL,
kSFlag,
kQrv,
@ -135,9 +137,7 @@ protected:
kSources,
FIELD_COUNT_SSM_QUERY,
// Used ONLY in -
// IGMPv3: Report
// MLDv2: Report
// Fields used in SSM Report
kRsvd2 = FIELD_COUNT_SSM_QUERY,
kGroupRecordCount,
kGroupRecords,
@ -163,30 +163,48 @@ protected:
OstProto::Gmp data;
GmpConfigForm *configForm;
GmpMsgType msgType() const
{
return GmpMsgType(fieldData(kType, FieldValue).toUInt());
}
bool isSsmReport() const
{
return ((msgType() == kIgmpV3Report)
|| (msgType() == kMldV2Report ));
}
bool isQuery() const
{
return ((msgType() == kIgmpV1Query)
|| (msgType() == kIgmpV2Query)
|| (msgType() == kIgmpV3Query)
|| (msgType() == kMldV1Query )
|| (msgType() == kMldV2Query ));
}
bool isSsmQuery() const
{
return ((msgType() == kIgmpV3Query)
|| (msgType() == kMldV2Query ));
}
GmpMsgType msgType() const;
virtual bool isSsmReport() const;
virtual bool isQuery() const;
virtual bool isSsmQuery() const;
int qqic(int value) const;
virtual quint16 checksum(int streamIndex) const = 0;
private:
static QHash<int, int> frameFieldCountMap;
};
inline GmpMsgType GmpProtocol::msgType() const
{
return GmpMsgType(fieldData(kType, FieldValue).toUInt());
}
inline bool GmpProtocol::isSsmReport() const
{
return ((msgType() == kIgmpV3Report)
|| (msgType() == kMldV2Report ));
}
inline bool GmpProtocol::isQuery() const
{
return ((msgType() == kIgmpV1Query)
|| (msgType() == kIgmpV2Query)
|| (msgType() == kIgmpV3Query)
|| (msgType() == kMldV1Query )
|| (msgType() == kMldV2Query ));
}
inline bool GmpProtocol::isSsmQuery() const
{
return ((msgType() == kIgmpV3Query)
|| (msgType() == kMldV2Query ));
}
inline int GmpProtocol::qqic(int value) const
{
return quint8(value); // TODO: if value > 128 convert to mantissa/exp form
}
#endif

View File

@ -23,13 +23,14 @@ package OstProto;
// Group Management Protocol (i.e. IGMP and MLD)
message Gmp {
// TODO: field numbers and default values
optional uint32 type = 1; // TODO: default value
//
// Common fields for both ASM and SSM messages
//
optional uint32 type = 1;
optional bool is_override_rsvd_code = 2;
optional uint32 rsvd_code = 3 [default = 0];
optional uint32 rsvd_code = 3;
// MaxRespTime is in milliseconds - MaxRespCode will be derived
optional uint32 max_response_time = 4[default = 100];
optional uint32 max_response_time = 4 [default = 100];
optional bool is_override_checksum = 5;
optional uint32 checksum = 6;
@ -39,35 +40,34 @@ message Gmp {
optional fixed64 v6_lo = 3;
}
// used by
// IGMPv1: Query, Report
// IGMPv2: Report, Leave (v2 uses v1 Query only)
// MLDv1: Query, Report, Done
//
// Fields used in ASM messages
//
enum GroupMode {
kFixed = 0;
kIncrementGroup = 1;
kDecrementGroup = 2;
kRandomGroup = 3;
}
optional IpAddress group_address = 10; // TODO: default value
optional IpAddress group_address = 10;
optional GroupMode group_mode = 11 [default = kFixed];
optional uint32 group_count = 12 [default = 16];
optional uint32 group_prefix = 13 [default = 24]; // TODO: verify mcast ip range
optional uint32 group_prefix = 13 [default = 24];
// used by
// IGMPv3: Query
// MLDv2: Query
//
// Fields used in SSM Query
//
optional bool s_flag = 20;
optional uint32 qrv = 21 [default = 2];
// QuerierQueryInterval is in seconds - QQIC will be derived
optional uint32 qqi = 22;
optional uint32 qqi = 22 [default = 125];
repeated IpAddress sources = 23;
optional bool is_override_source_count = 24;
optional uint32 source_count = 25;
// used by
// IGMPv3: Report
// MLDv2: Report
//
// Fields used in SSM Reports
//
message GroupRecord {
enum RecordType {
kIsInclude = 1;
@ -79,7 +79,7 @@ message Gmp {
}
optional RecordType type = 1 [default = kIsInclude];
optional IpAddress group_address = 2; // TODO: default
optional IpAddress group_address = 2;
repeated IpAddress sources = 3;
optional bool is_override_source_count = 4;
optional uint32 source_count = 5;

View File

@ -5,7 +5,7 @@
<rect>
<x>0</x>
<y>0</y>
<width>497</width>
<width>509</width>
<height>355</height>
</rect>
</property>
@ -31,7 +31,7 @@
<item row="1" column="0" >
<widget class="QLabel" name="label_2" >
<property name="text" >
<string>Max Response Time</string>
<string>Max Response Time (1/10s)</string>
</property>
<property name="buddy" >
<cstring>maxResponseTime</cstring>
@ -155,6 +155,9 @@
</item>
<item row="1" column="2" >
<widget class="QLineEdit" name="groupCount" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
@ -165,6 +168,9 @@
</item>
<item row="1" column="3" >
<widget class="QLineEdit" name="groupPrefix" >
<property name="enabled" >
<bool>false</bool>
</property>
<property name="sizePolicy" >
<sizepolicy vsizetype="Fixed" hsizetype="Fixed" >
<horstretch>0</horstretch>
@ -304,7 +310,7 @@
<item>
<widget class="QToolButton" name="deleteSource" >
<property name="text" >
<string>--</string>
<string></string>
</property>
</widget>
</item>
@ -428,7 +434,7 @@
<item>
<widget class="QToolButton" name="deleteGroupRecord" >
<property name="text" >
<string>--</string>
<string></string>
</property>
</widget>
</item>
@ -580,7 +586,7 @@
<item>
<widget class="QToolButton" name="deleteGroupRecordSource" >
<property name="text" >
<string>--</string>
<string></string>
</property>
</widget>
</item>

View File

@ -19,37 +19,22 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
#include "igmp.h"
#include "ipv4addressdelegate.h"
#include "iputils.h"
#include <QHostAddress>
#include <QItemDelegate>
#include <qendian.h>
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<QLineEdit*>(QItemDelegate::createEditor(
parent, option, index));
ipEdit->setInputMask("009.009.009.009;"); // FIXME: use validator
return ipEdit;
}
};
IgmpConfigForm::IgmpConfigForm(QWidget *parent)
: GmpConfigForm(parent)
{
_defaultGroupIp = "0.0.0.0";
_defaultSourceIp = "0.0.0.0";
sourceList->setItemDelegate(new IpAddressDelegate(this));
groupRecordSourceList->setItemDelegate(new IpAddressDelegate(this));
groupAddress->setInputMask("009.009.009.009;"); // FIXME: use validator
groupRecordAddress->setInputMask("009.009.009.009;"); // FIXME:use validator
sourceList->setItemDelegate(new IPv4AddressDelegate(this));
groupRecordSourceList->setItemDelegate(new IPv4AddressDelegate(this));
}
IgmpProtocol::IgmpProtocol(StreamBase *stream, AbstractProtocol *parent)
@ -114,15 +99,19 @@ QVariant IgmpProtocol::fieldData(int index, FieldAttrib attrib,
{
case kRsvdMrtCode:
{
quint8 mrt = 0, mrc = 0;
uint mrt = 0;
quint8 mrcode = 0;
if (msgType() == kIgmpV3Query)
{
mrt = data.max_response_time();
mrc = mrt; // TODO: MR Code
mrcode = quint8(mrc(mrt));
}
else if (msgType() == kIgmpV2Query)
mrc = mrt = data.max_response_time() & 0xFF;
{
mrt = data.max_response_time();
mrcode = mrt & 0xFF;
}
switch(attrib)
@ -137,7 +126,7 @@ QVariant IgmpProtocol::fieldData(int index, FieldAttrib attrib,
case FieldTextValue:
return QString("%1").arg(mrt);
case FieldFrameValue:
return QByteArray(1, mrc);
return QByteArray(1, mrcode);
default:
break;
}
@ -145,14 +134,12 @@ QVariant IgmpProtocol::fieldData(int index, FieldAttrib attrib,
}
case kGroupAddress:
{
quint32 grpIp = data.group_address().v4(); // FIXME
#if 0 // TODO
getip(
data.group_address().v4(),
data.group_mode(),
data.group_count(),
data.group_prefix());
#endif
quint32 grpIp = ipUtils::ipAddress(
data.group_address().v4(),
data.group_prefix(),
ipUtils::AddrMode(data.group_mode()),
data.group_count(),
streamIndex);
switch(attrib)
{
@ -225,10 +212,10 @@ QVariant IgmpProtocol::fieldData(int index, FieldAttrib attrib,
grpRec["groupRecordAddress"] = QHostAddress(
rec.group_address().v4()).toString();
QStringList l;
QStringList sl;
for (int j = 0; j < rec.sources_size(); j++)
l.append(QHostAddress(rec.sources(j).v4()).toString());
grpRec["groupRecordSourceList"] = l;
sl.append(QHostAddress(rec.sources(j).v4()).toString());
grpRec["groupRecordSourceList"] = sl;
grpRecords.replace(i, grpRec);
}
@ -273,10 +260,10 @@ QVariant IgmpProtocol::fieldData(int index, FieldAttrib attrib,
QHostAddress(rec.group_address().v4()).toString()));
str.append("; Sources: ");
QStringList l;
QStringList sl;
for (int j = 0; j < rec.sources_size(); j++)
l.append(QHostAddress(rec.sources(j).v4()).toString());
str.append(l.join(", "));
sl.append(QHostAddress(rec.sources(j).v4()).toString());
str.append(sl.join(", "));
recStr.replace("XXX", str);
list.replace(i, recStr);
@ -305,6 +292,13 @@ bool IgmpProtocol::setFieldData(int index, const QVariant &value,
switch (index)
{
case kRsvdMrtCode:
{
uint mrt = value.toUInt(&isOk);
if (isOk)
data.set_max_response_time(mrt);
break;
}
case kGroupAddress:
{
QHostAddress addr(value.toString());
@ -343,6 +337,7 @@ bool IgmpProtocol::setFieldData(int index, const QVariant &value,
QStringList srcList = grpRec["groupRecordSourceList"]
.toStringList();
rec->clear_sources();
foreach (QString src, srcList)
{
rec->add_sources()->set_v4(
@ -380,48 +375,20 @@ void IgmpProtocol::loadConfigWidget()
configForm->maxResponseTime->setText(
fieldData(kRsvdMrtCode, FieldValue).toString());
#if 0
configForm->igmpA->setText(fieldData(igmp_a, FieldValue).toString());
configForm->igmpB->setText(fieldData(igmp_b, FieldValue).toString());
configForm->igmpPayloadLength->setText(
fieldData(igmp_payloadLength, FieldValue).toString());
configForm->isChecksumOverride->setChecked(
fieldData(igmp_is_override_checksum, FieldValue).toBool());
configForm->igmpChecksum->setText(uintToHexStr(
fieldData(igmp_checksum, FieldValue).toUInt(), 2));
configForm->igmpX->setText(fieldData(igmp_x, FieldValue).toString());
configForm->igmpY->setText(fieldData(igmp_y, FieldValue).toString());
#endif
}
void IgmpProtocol::storeConfigWidget()
{
bool isOk;
GmpProtocol::storeConfigWidget();
#if 0
setFieldData(igmp_a, configForm->igmpA->text());
setFieldData(igmp_b, configForm->igmpB->text());
setFieldData(igmp_payloadLength, configForm->igmpPayloadLength->text());
setFieldData(igmp_is_override_checksum,
configForm->isChecksumOverride->isChecked());
setFieldData(igmp_checksum, configForm->igmpChecksum->text().toUInt(&isOk, BASE_HEX));
setFieldData(igmp_x, configForm->igmpX->text());
setFieldData(igmp_y, configForm->igmpY->text());
#endif
setFieldData(kRsvdMrtCode, configForm->maxResponseTime->text());
}
quint16 IgmpProtocol::checksum(int streamIndex) const
{
quint16 cks;
quint32 sum = 0;
#if 0 // FIXME
#if 1 // FIXME
// TODO: add as a new CksumType (CksumIgmp?) and implement in AbsProto
cks = protocolFrameCksum(streamIndex, CksumIp);
sum += (quint16) ~cks;

View File

@ -58,6 +58,13 @@ public:
protected:
virtual quint16 checksum(int streamIndex) const;
private:
int mrc(int value) const;
};
inline int IgmpProtocol::mrc(int value) const
{
return quint8(value); // TODO: if value > 128, convert to mantissa/exp form
}
#endif

70
common/iputils.h Normal file
View File

@ -0,0 +1,70 @@
/*
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 _IP_UTILS_H
#define _IP_UTILS_H
namespace ipUtils {
enum AddrMode {
kFixed = 0,
kIncrement = 1,
kDecrement = 2,
kRandom = 3
};
quint32 ipAddress(quint32 baseIp, int prefix, AddrMode mode, int count,
int index)
{
int u;
quint32 mask = ((1<<prefix) - 1) << (32 - prefix);
quint32 subnet, host, ip;
switch(mode)
{
case kFixed:
ip = baseIp;
break;
case kIncrement:
u = index % count;
subnet = baseIp & mask;
host = (((baseIp & ~mask) + u) &
~mask);
ip = subnet | host;
break;
case kDecrement:
u = index % count;
subnet = baseIp & mask;
host = (((baseIp & ~mask) - u) &
~mask);
ip = subnet | host;
break;
case kRandom:
subnet = baseIp & mask;
host = (qrand() & ~mask);
ip = subnet | host;
break;
default:
qWarning("Unhandled mode = %d", mode);
}
return ip;
}
} // namespace ipUtils
#endif

View File

@ -0,0 +1,58 @@
/*
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 _IPV4_ADDRESS_DELEGATE
#define _IPV4_ADDRESS_DELEGATE
#include <QItemDelegate>
#include <QLineEdit>
class IPv4AddressDelegate : public QItemDelegate
{
Q_OBJECT
public:
IPv4AddressDelegate(QObject *parent = 0);
~IPv4AddressDelegate();
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option,
const QModelIndex &index) const;
};
inline IPv4AddressDelegate::IPv4AddressDelegate(QObject *parent)
: QItemDelegate(parent)
{
}
inline IPv4AddressDelegate::~IPv4AddressDelegate()
{
}
inline QWidget* IPv4AddressDelegate::createEditor(QWidget *parent,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QLineEdit *ipEdit;
ipEdit = static_cast<QLineEdit*>(QItemDelegate::createEditor(
parent, option, index));
ipEdit->setInputMask("009.009.009.009;"); // FIXME: use validator
return ipEdit;
}
#endif

View File

@ -73,6 +73,7 @@ HEADERS += \
arp.h \
ip4.h \
ip6.h \
ipv4addressdelegate.h \
ip6over4.h \
ip4over6.h \
ip4over4.h \