From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from dpdk.org (dpdk.org [92.243.14.124]) by inbox.dpdk.org (Postfix) with ESMTP id 971CDA04EF; Mon, 25 May 2020 12:26:39 +0200 (CEST) Received: from [92.243.14.124] (localhost [127.0.0.1]) by dpdk.org (Postfix) with ESMTP id 704D91D6C1; Mon, 25 May 2020 12:26:39 +0200 (CEST) Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by dpdk.org (Postfix) with ESMTP id 28E331D63E for ; Mon, 25 May 2020 12:26:36 +0200 (CEST) IronPort-SDR: 8FKpwlrYcQ+G4asA9L4SzIlhzPBPpA7Wy53AjCqSy9Uun5U5du9hldBldl5eQQ6V2uU0DOqvr/ /PS8GpK4irfQ== X-Amp-Result: SKIPPED(no attachment in message) X-Amp-File-Uploaded: False Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 25 May 2020 03:26:36 -0700 IronPort-SDR: gK0+SoNItWt5djRMWQyUqd4HL34ZFpWKhgT7IM0wtJDvdyyz/IqDJQN9XoXV5RDH46SZiJhNF8 oJllrdUaHScg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.73,433,1583222400"; d="scan'208";a="256195658" Received: from root.sh.intel.com ([10.67.119.116]) by fmsmga008.fm.intel.com with ESMTP; 25 May 2020 03:26:35 -0700 From: Nannan Lu To: dts@dpdk.org Cc: Nannan Lu Date: Mon, 25 May 2020 18:09:59 +0000 Message-Id: <20200525181003.25229-1-nannan.lu@intel.com> X-Mailer: git-send-email 2.17.1 Subject: [dts] [PATCH V1 1/5] dep: add igmp.py to dep X-BeenThere: dts@dpdk.org X-Mailman-Version: 2.1.15 Precedence: list List-Id: test suite reviews and discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: dts-bounces@dpdk.org Sender: "dts" Add igmp.py to dep so that dts supports sending igmp packets. Signed-off-by: Nannan Lu --- dep/igmp.py | 164 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) create mode 100644 dep/igmp.py diff --git a/dep/igmp.py b/dep/igmp.py new file mode 100644 index 0000000..5cbf9c0 --- /dev/null +++ b/dep/igmp.py @@ -0,0 +1,164 @@ +#! /usr/bin/env python + +# This file is part of Scapy +# Scapy 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 2 of the License, or +# any later version. +# +# Scapy 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 Scapy. If not, see . + +# flake8: noqa: E501 + +# scapy.contrib.description = Internet Group Management Protocol v1/v2 (IGMP/IGMPv2) +# scapy.contrib.status = loads + +from __future__ import print_function +from scapy.compat import chb, orb +from scapy.error import warning +from scapy.fields import ByteEnumField, ByteField, IPField, XShortField +from scapy.layers.inet import IP, IPOption_Router_Alert +from scapy.layers.l2 import Ether, getmacbyip +from scapy.packet import bind_layers, Packet +from scapy.utils import atol, checksum + + +def isValidMCAddr(ip): + """convert dotted quad string to long and check the first octet""" + FirstOct = atol(ip) >> 24 & 0xFF + return (FirstOct >= 224) and (FirstOct <= 239) + + +class IGMP(Packet): + """IGMP Message Class for v1 and v2. + +This class is derived from class Packet. You need call "igmpize()" +so the packet is transformed according the RFC when sent. +a=Ether(src="00:01:02:03:04:05") +b=IP(src="1.2.3.4") +c=IGMP(type=0x12, gaddr="224.2.3.4") +x = a/b/c +x[IGMP].igmpize() +sendp(a/b/c, iface="en0") + + Parameters: + type IGMP type field, 0x11, 0x12, 0x16 or 0x17 + mrcode Maximum Response time (zero for v1) + gaddr Multicast Group Address 224.x.x.x/4 + +See RFC2236, Section 2. Introduction for definitions of proper +IGMPv2 message format http://www.faqs.org/rfcs/rfc2236.html + + """ + name = "IGMP" + + igmptypes = {0x11: "Group Membership Query", + 0x12: "Version 1 - Membership Report", + 0x16: "Version 2 - Membership Report", + 0x17: "Leave Group"} + + fields_desc = [ByteEnumField("type", 0x11, igmptypes), + ByteField("mrcode", 20), + XShortField("chksum", None), + IPField("gaddr", "0.0.0.0")] + + def post_build(self, p, pay): + """Called implicitly before a packet is sent to compute and place IGMP checksum. + + Parameters: + self The instantiation of an IGMP class + p The IGMP message in hex in network byte order + pay Additional payload for the IGMP message + """ + p += pay + if self.chksum is None: + ck = checksum(p) + p = p[:2] + chb(ck >> 8) + chb(ck & 0xff) + p[4:] + return p + + @classmethod + def dispatch_hook(cls, _pkt=None, *args, **kargs): + if _pkt and len(_pkt) >= 4: + from scapy.contrib.igmpv3 import IGMPv3 + if orb(_pkt[0]) in [0x22, 0x30, 0x31, 0x32]: + return IGMPv3 + if orb(_pkt[0]) == 0x11 and len(_pkt) >= 12: + return IGMPv3 + return IGMP + + def igmpize(self): + """Called to explicitly fixup the packet according to the IGMP RFC + + The rules are: + General: + 1. the Max Response time is meaningful only in Membership Queries and should be zero + IP: + 1. Send General Group Query to 224.0.0.1 (all systems) + 2. Send Leave Group to 224.0.0.2 (all routers) + 3a.Otherwise send the packet to the group address + 3b.Send reports/joins to the group address + 4. ttl = 1 (RFC 2236, section 2) + 5. send the packet with the router alert IP option (RFC 2236, section 2) + Ether: + 1. Recalculate destination + + Returns: + True The tuple ether/ip/self passed all check and represents + a proper IGMP packet. + False One of more validation checks failed and no fields + were adjusted. + + The function will examine the IGMP message to assure proper format. + Corrections will be attempted if possible. The IP header is then properly + adjusted to ensure correct formatting and assignment. The Ethernet header + is then adjusted to the proper IGMP packet format. + """ + gaddr = self.gaddr if hasattr(self, "gaddr") and self.gaddr else "0.0.0.0" # noqa: E501 + underlayer = self.underlayer + if self.type not in [0x11, 0x30]: # General Rule 1 # noqa: E501 + self.mrcode = 0 + if isinstance(underlayer, IP): + if (self.type == 0x11): + if (gaddr == "0.0.0.0"): + underlayer.dst = "224.0.0.1" # IP rule 1 # noqa: E501 + elif isValidMCAddr(gaddr): + underlayer.dst = gaddr # IP rule 3a # noqa: E501 + else: + warning("Invalid IGMP Group Address detected !") + return False + elif ((self.type == 0x17) and isValidMCAddr(gaddr)): + underlayer.dst = "224.0.0.2" # IP rule 2 # noqa: E501 + elif ((self.type == 0x12) or (self.type == 0x16)) and (isValidMCAddr(gaddr)): # noqa: E501 + underlayer.dst = gaddr # IP rule 3b # noqa: E501 + else: + warning("Invalid IGMP Type detected !") + return False + if not any(isinstance(x, IPOption_Router_Alert) for x in underlayer.options): # noqa: E501 + underlayer.options.append(IPOption_Router_Alert()) + underlayer.ttl = 1 # IP rule 4 + _root = self.firstlayer() + if _root.haslayer(Ether): + # Force recalculate Ether dst + _root[Ether].dst = getmacbyip(underlayer.dst) # Ether rule 1 # noqa: E501 + from scapy.contrib.igmpv3 import IGMPv3 + if isinstance(self, IGMPv3): + self.encode_maxrespcode() + return True + + def mysummary(self): + """Display a summary of the IGMP object.""" + if isinstance(self.underlayer, IP): + return self.underlayer.sprintf("IGMP: %IP.src% > %IP.dst% %IGMP.type% %IGMP.gaddr%") # noqa: E501 + else: + return self.sprintf("IGMP %IGMP.type% %IGMP.gaddr%") + + +bind_layers(IP, IGMP, frag=0, + proto=2, + ttl=1) -- 2.17.1