aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tests/hwsim/hwsim.py53
-rw-r--r--tests/hwsim/netlink.py234
2 files changed, 287 insertions, 0 deletions
diff --git a/tests/hwsim/hwsim.py b/tests/hwsim/hwsim.py
new file mode 100644
index 0000000..55fa0c1
--- /dev/null
+++ b/tests/hwsim/hwsim.py
@@ -0,0 +1,53 @@
+#
+# HWSIM generic netlink controller code
+# Copyright (c) 2014 Intel Corporation
+#
+# Author: Johannes Berg <johannes.berg@intel.com>
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import netlink
+
+# constants
+HWSIM_CMD_CREATE_RADIO = 4
+HWSIM_CMD_DESTROY_RADIO = 5
+
+HWSIM_ATTR_CHANNELS = 9
+HWSIM_ATTR_RADIO_ID = 10
+
+# the controller class
+class HWSimController(object):
+ def __init__(self):
+ self._conn = netlink.Connection(netlink.NETLINK_GENERIC)
+ self._fid = netlink.genl_controller.get_family_id('MAC80211_HWSIM')
+
+ def create_radio(self, n_channels=None):
+ attrs = []
+ if n_channels:
+ attrs.append(netlink.U32Attr(HWSIM_ATTR_CHANNELS, n_channels))
+ msg = netlink.GenlMessage(self._fid, HWSIM_CMD_CREATE_RADIO,
+ flags = netlink.NLM_F_REQUEST |
+ netlink.NLM_F_ACK,
+ attrs = attrs)
+ return msg.send_and_recv(self._conn).ret
+
+ def destroy_radio(self, radio_id):
+ attrs = [netlink.U32Attr(HWSIM_ATTR_RADIO_ID, radio_id)]
+ msg = netlink.GenlMessage(self._fid, HWSIM_CMD_DESTROY_RADIO,
+ flags = netlink.NLM_F_REQUEST |
+ netlink.NLM_F_ACK,
+ attrs = attrs)
+ msg.send_and_recv(self._conn)
+
+if __name__ == '__main__':
+ import sys
+ c = HWSimController()
+ if sys.argv[1] == 'create':
+ if len(sys.argv) > 2:
+ n_channels = int(sys.argv[2])
+ else:
+ n_channels = 0
+ print 'Created radio %d' % c.create_radio(n_channels=n_channels)
+ elif sys.argv[1] == 'destroy':
+ print c.destroy_radio(int(sys.argv[2]))
diff --git a/tests/hwsim/netlink.py b/tests/hwsim/netlink.py
new file mode 100644
index 0000000..835c709
--- /dev/null
+++ b/tests/hwsim/netlink.py
@@ -0,0 +1,234 @@
+#
+# (Generic) Netlink message generation/parsing
+# Copyright (c) 2007 Johannes Berg <johannes@sipsolutions.net>
+# Copyright (c) 2014 Intel Corporation
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+
+import struct, socket
+
+# flags
+NLM_F_REQUEST = 1
+NLM_F_MULTI = 2
+NLM_F_ACK = 4
+NLM_F_ECHO = 8
+
+# types
+NLMSG_NOOP = 1
+NLMSG_ERROR = 2
+NLMSG_DONE = 3
+NLMSG_OVERRUN = 4
+NLMSG_MIN_TYPE = 0x10
+
+class Attr(object):
+ def __init__(self, attr_type, data, *values):
+ self._type = attr_type
+ if len(values):
+ self._data = struct.pack(data, *values)
+ else:
+ self._data = data
+
+ def _dump(self):
+ hdr = struct.pack("HH", len(self._data) + 4, self._type)
+ length = len(self._data)
+ pad = ((length + 4 - 1) & ~3 ) - length
+ return hdr + self._data + '\0' * pad
+
+ def __repr__(self):
+ return '<Attr type %d, data "%s">' % (self._type, repr(self._data))
+
+ def u16(self):
+ return struct.unpack('H', self._data)[0]
+ def s16(self):
+ return struct.unpack('h', self._data)[0]
+ def u32(self):
+ return struct.unpack('I', self._data)[0]
+ def s32(self):
+ return struct.unpack('i', self._data)[0]
+ def str(self):
+ return self._data
+ def nulstr(self):
+ return self._data.split('\0')[0]
+ def nested(self):
+ return parse_attributes(self._data)
+
+class StrAttr(Attr):
+ def __init__(self, attr_type, data):
+ Attr.__init__(self, attr_type, "%ds" % len(data), data)
+
+class NulStrAttr(Attr):
+ def __init__(self, attr_type, data):
+ Attr.__init__(self, attr_type, "%dsB" % len(data), data, 0)
+
+class U32Attr(Attr):
+ def __init__(self, attr_type, val):
+ Attr.__init__(self, attr_type, "I", val)
+
+class U8Attr(Attr):
+ def __init__(self, attr_type, val):
+ Attr.__init__(self, attr_type, "B", val)
+
+class Nested(Attr):
+ def __init__(self, attr_type, attrs):
+ self.attrs = attrs
+ self.type = attr_type
+
+ def _dump(self):
+ contents = []
+ for attr in self.attrs:
+ contents.append(attr._dump())
+ contents = ''.join(contents)
+ length = len(contents)
+ hdr = struct.pack("HH", length+4, self.type)
+ return hdr + contents
+
+NETLINK_ROUTE = 0
+NETLINK_UNUSED = 1
+NETLINK_USERSOCK = 2
+NETLINK_FIREWALL = 3
+NETLINK_INET_DIAG = 4
+NETLINK_NFLOG = 5
+NETLINK_XFRM = 6
+NETLINK_SELINUX = 7
+NETLINK_ISCSI = 8
+NETLINK_AUDIT = 9
+NETLINK_FIB_LOOKUP = 10
+NETLINK_CONNECTOR = 11
+NETLINK_NETFILTER = 12
+NETLINK_IP6_FW = 13
+NETLINK_DNRTMSG = 14
+NETLINK_KOBJECT_UEVENT = 15
+NETLINK_GENERIC = 16
+
+class Message(object):
+ def __init__(self, msg_type, flags=0, seq=-1, payload=None):
+ self.type = msg_type
+ self.flags = flags
+ self.seq = seq
+ self.pid = -1
+ payload = payload or []
+ if isinstance(payload, list):
+ contents = []
+ for attr in payload:
+ contents.append(attr._dump())
+ self.payload = ''.join(contents)
+ else:
+ self.payload = payload
+
+ def send(self, conn):
+ if self.seq == -1:
+ self.seq = conn.seq()
+
+ self.pid = conn.pid
+ length = len(self.payload)
+
+ hdr = struct.pack("IHHII", length + 4*4, self.type,
+ self.flags, self.seq, self.pid)
+ conn.send(hdr + self.payload)
+
+ def __repr__(self):
+ return '<netlink.Message type=%d, pid=%d, seq=%d, flags=0x%x "%s">' % (
+ self.type, self.pid, self.seq, self.flags, repr(self.payload))
+
+ @property
+ def ret(self):
+ assert self.type == NLMSG_ERROR
+ return struct.unpack("i", self.payload[:4])[0]
+
+ def send_and_recv(self, conn):
+ self.send(conn)
+ while True:
+ m = conn.recv()
+ if m.seq == self.seq:
+ return m
+
+class Connection(object):
+ def __init__(self, nltype, groups=0, unexpected_msg_handler=None):
+ self.descriptor = socket.socket(socket.AF_NETLINK,
+ socket.SOCK_RAW, nltype)
+ self.descriptor.setsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF, 65536)
+ self.descriptor.setsockopt(socket.SOL_SOCKET, socket.SO_RCVBUF, 65536)
+ self.descriptor.bind((0, groups))
+ self.pid, self.groups = self.descriptor.getsockname()
+ self._seq = 0
+ self.unexpected = unexpected_msg_handler
+ def send(self, msg):
+ self.descriptor.send(msg)
+ def recv(self):
+ contents = self.descriptor.recv(16384)
+ # XXX: python doesn't give us message flags, check
+ # len(contents) vs. msglen for TRUNC
+ msglen, msg_type, flags, seq, pid = struct.unpack("IHHII",
+ contents[:16])
+ msg = Message(msg_type, flags, seq, contents[16:])
+ msg.pid = pid
+ if msg.type == NLMSG_ERROR:
+ import os
+ errno = msg.ret
+ if errno < 0:
+ err = OSError("Netlink error: %s (%d)" % (
+ os.strerror(-errno), -errno))
+ err.errno = -errno
+ raise err
+ return msg
+ def seq(self):
+ self._seq += 1
+ return self._seq
+
+def parse_attributes(data):
+ attrs = {}
+ while len(data):
+ attr_len, attr_type = struct.unpack("HH", data[:4])
+ attrs[attr_type] = Attr(attr_type, data[4:attr_len])
+ attr_len = ((attr_len + 4 - 1) & ~3 )
+ data = data[attr_len:]
+ return attrs
+
+
+
+CTRL_CMD_UNSPEC = 0
+CTRL_CMD_NEWFAMILY = 1
+CTRL_CMD_DELFAMILY = 2
+CTRL_CMD_GETFAMILY = 3
+CTRL_CMD_NEWOPS = 4
+CTRL_CMD_DELOPS = 5
+CTRL_CMD_GETOPS = 6
+
+CTRL_ATTR_UNSPEC = 0
+CTRL_ATTR_FAMILY_ID = 1
+CTRL_ATTR_FAMILY_NAME = 2
+CTRL_ATTR_VERSION = 3
+CTRL_ATTR_HDRSIZE = 4
+CTRL_ATTR_MAXATTR = 5
+CTRL_ATTR_OPS = 6
+
+class GenlHdr(object):
+ def __init__(self, cmd, version = 0):
+ self.cmd = cmd
+ self.version = version
+ def _dump(self):
+ return struct.pack("BBxx", self.cmd, self.version)
+
+def _genl_hdr_parse(data):
+ return GenlHdr(*struct.unpack("BBxx", data))
+
+GENL_ID_CTRL = NLMSG_MIN_TYPE
+
+class GenlMessage(Message):
+ def __init__(self, family, cmd, attrs=[], flags=0):
+ Message.__init__(self, family, flags=flags, payload=[GenlHdr(cmd)] + attrs)
+
+class GenlController(object):
+ def __init__(self, conn):
+ self.conn = conn
+ def get_family_id(self, family):
+ a = NulStrAttr(CTRL_ATTR_FAMILY_NAME, family)
+ m = GenlMessage(GENL_ID_CTRL, CTRL_CMD_GETFAMILY, flags=NLM_F_REQUEST, attrs=[a])
+ m.send(self.conn)
+ m = self.conn.recv()
+ gh = _genl_hdr_parse(m.payload[:4])
+ attrs = parse_attributes(m.payload[4:])
+ return attrs[CTRL_ATTR_FAMILY_ID].u16()
+
+genl_controller = GenlController(Connection(NETLINK_GENERIC))