Review and rework of GMP and IGMP
This commit is contained in:
parent
d4408f0fc1
commit
dbc7409616
@ -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 \
|
||||
|
129
common/gmp.cpp
129
common/gmp.cpp
@ -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["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);
|
||||
|
||||
|
68
common/gmp.h
68
common/gmp.h
@ -25,8 +25,14 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
|
||||
#include "abstractprotocol.h"
|
||||
|
||||
#include <QHash>
|
||||
|
||||
// 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,
|
||||
|
||||
@ -37,6 +43,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
kIgmpV3Query = 0xFE11,
|
||||
kIgmpV3Report = 0x22,
|
||||
|
||||
// MLD
|
||||
kMldV1Query = 0x82,
|
||||
kMldV1Report = 0x83,
|
||||
kMldV1Done = 0x84,
|
||||
@ -46,13 +53,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
};
|
||||
|
||||
/*
|
||||
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,16 +163,31 @@ protected:
|
||||
OstProto::Gmp data;
|
||||
GmpConfigForm *configForm;
|
||||
|
||||
GmpMsgType msgType() const
|
||||
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());
|
||||
}
|
||||
bool isSsmReport() const
|
||||
|
||||
inline bool GmpProtocol::isSsmReport() const
|
||||
{
|
||||
return ((msgType() == kIgmpV3Report)
|
||||
|| (msgType() == kMldV2Report ));
|
||||
}
|
||||
bool isQuery() const
|
||||
|
||||
inline bool GmpProtocol::isQuery() const
|
||||
{
|
||||
return ((msgType() == kIgmpV1Query)
|
||||
|| (msgType() == kIgmpV2Query)
|
||||
@ -180,13 +195,16 @@ protected:
|
||||
|| (msgType() == kMldV1Query )
|
||||
|| (msgType() == kMldV2Query ));
|
||||
}
|
||||
bool isSsmQuery() const
|
||||
|
||||
inline bool GmpProtocol::isSsmQuery() const
|
||||
{
|
||||
return ((msgType() == kIgmpV3Query)
|
||||
|| (msgType() == kMldV2Query ));
|
||||
}
|
||||
|
||||
virtual quint16 checksum(int streamIndex) const = 0;
|
||||
};
|
||||
inline int GmpProtocol::qqic(int value) const
|
||||
{
|
||||
return quint8(value); // TODO: if value > 128 convert to mantissa/exp form
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -23,11 +23,12 @@ 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 bool is_override_checksum = 5;
|
||||
@ -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;
|
||||
|
@ -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>
|
||||
|
105
common/igmp.cpp
105
common/igmp.cpp
@ -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(
|
||||
quint32 grpIp = ipUtils::ipAddress(
|
||||
data.group_address().v4(),
|
||||
data.group_mode(),
|
||||
data.group_prefix(),
|
||||
ipUtils::AddrMode(data.group_mode()),
|
||||
data.group_count(),
|
||||
data.group_prefix());
|
||||
#endif
|
||||
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;
|
||||
|
@ -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
70
common/iputils.h
Normal 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
|
58
common/ipv4addressdelegate.h
Normal file
58
common/ipv4addressdelegate.h
Normal 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
|
||||
|
@ -73,6 +73,7 @@ HEADERS += \
|
||||
arp.h \
|
||||
ip4.h \
|
||||
ip6.h \
|
||||
ipv4addressdelegate.h \
|
||||
ip6over4.h \
|
||||
ip4over6.h \
|
||||
ip4over4.h \
|
||||
|
Loading…
Reference in New Issue
Block a user