Skip to content

Interface Combinations #48

@fnoop

Description

@fnoop

There doesn't appear to be any way to extract interface combinations, crucial info to create virtual interfaces.

iw list returns (this is for a raspberry pi 3):

	valid interface combinations:
		 * #{ managed } <= 1, #{ P2P-device } <= 1, #{ P2P-client, P2P-GO } <= 1,
		   total <= 3, #channels <= 2
		 * #{ managed } <= 1, #{ AP } <= 1, #{ P2P-client } <= 1, #{ P2P-device } <= 1,
		   total <= 4, #channels <= 1

phyinfo() doesn't return this info. With a bit of wrangling it's possible like this:

import pyric
import pyric.pyw as pyw

import pyric.net.wireless.nl80211_h as nl80211h # nl80211 definition
import pyric.lib.libnl as nl                    # netlink (library) functions
import pyric.net.netlink_h as nlh               # netlink definition

def parse_combinations(cs):
    _combinations = []
    try:
       for _, combo in nl.nla_parse_nested(cs.encode()):
            _combodata = {'limits': []}
            for combofield, combovalue in nl.nla_parse_nested(combo):
                if combofield == nl80211h.NL80211_IFACE_COMB_MAXNUM:
                    _combodata['max'] = struct.unpack_from('I', combovalue, 0)[0]
                if combofield == nl80211h.NL80211_IFACE_COMB_NUM_CHANNELS:
                    _combodata['channels'] = struct.unpack_from('I', combovalue, 0)[0]
                if combofield == nl80211h.NL80211_IFACE_COMB_LIMITS:
                    for combo_option in nl.nla_parse_nested(combovalue):
                        combo_option_unpacked = nl.nla_parse_nested(combo_option[1])
                        for combo_option_fragment in combo_option_unpacked:
                            if combo_option_fragment[0] == 1:
                                option_max = struct.unpack_from('I', combo_option_fragment[1], 0)[0]
                            if combo_option_fragment[0] == 2:
                                option_types = [nl80211h.NL80211_IFTYPES[x[0]] for x in nl.nla_parse_nested(combo_option_fragment[1])]
                        _combodata['limits'].append((option_max, option_types))
            _combinations.append(_combodata)
    except Exception as e:
        print("Error: {}".format(repr(e)))
    return _combinations

def combinations(interface):
    card = pyw.getcard(interface)
    nlsock = None
    try:
        # Open netlink socket
        nlsock = nl.nl_socket_alloc(timeout=2)
        try:
            # Request physical device info through netlink
            msg = nl.nlmsg_new(nltype=pyw._familyid_(nlsock),
                               cmd=nl80211h.NL80211_CMD_GET_WIPHY,
                               flags=nlh.NLM_F_REQUEST | nlh.NLM_F_ACK)
            nl.nla_put_u32(msg, card.phy, nl80211h.NL80211_ATTR_WIPHY)
            nl.nl_sendmsg(nlsock, msg)
            rmsg = nl.nl_recvmsg(nlsock)
            # Parse the response and extract supported interface combinations
            _, cs, d = nl.nla_find(rmsg, nl80211h.NL80211_ATTR_INTERFACE_COMBINATIONS, False)
            if d != nlh.NLA_ERROR: return parse_combinations(cs)
            else: return None
        except AttributeError:
            raise pyric.error(pyric.EINVAL, "Invalid Card")
        except nl.error as e:
            raise pyric.error(e.errno, e.strerror)
    except nl.error as e:
        raise pyric.error(e.errno, pyric.strerror(e.errno))
    except pyric.error:
        raise
    finally:
        if nlsock: nl.nl_socket_free(nlsock)

PR to come to add this to phyinfo()

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions