Esempio n. 1
0
static int get_targets_handler(struct nl_msg *n, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(n);
	struct nlattr *attrs[NFC_ATTR_MAX + 1];
	uint32_t adapter_idx, target_idx, protocols;
	uint16_t sens_res = 0;
	uint8_t sel_res = 0;
	uint8_t nfcid[NFC_MAX_NFCID1_LEN], nfcid_len;
	uint8_t iso15693_dsfid = 0;
	uint8_t iso15693_uid_len, iso15693_uid[NFC_MAX_ISO15693_UID_LEN];

	DBG("");

	genlmsg_parse(nlh, 0, attrs, NFC_ATTR_MAX, NULL);

	adapter_idx = *((uint32_t *)arg);
	target_idx = nla_get_u32(attrs[NFC_ATTR_TARGET_INDEX]);
	protocols = nla_get_u32(attrs[NFC_ATTR_PROTOCOLS]);

	if (attrs[NFC_ATTR_TARGET_SENS_RES])
		sens_res =
			nla_get_u16(attrs[NFC_ATTR_TARGET_SENS_RES]);

	if (attrs[NFC_ATTR_TARGET_SEL_RES])
		sel_res =
			nla_get_u16(attrs[NFC_ATTR_TARGET_SEL_RES]);

	if (attrs[NFC_ATTR_TARGET_NFCID1]) {
		nfcid_len = nla_len(attrs[NFC_ATTR_TARGET_NFCID1]);
		if (nfcid_len <= NFC_MAX_NFCID1_LEN)
			memcpy(nfcid, nla_data(attrs[NFC_ATTR_TARGET_NFCID1]),
								nfcid_len);
	} else {
		nfcid_len = 0;
	}

	if (attrs[NFC_ATTR_TARGET_ISO15693_DSFID])
		iso15693_dsfid =
			nla_get_u8(attrs[NFC_ATTR_TARGET_ISO15693_DSFID]);

	if (attrs[NFC_ATTR_TARGET_ISO15693_UID]) {
		iso15693_uid_len = nla_len(attrs[NFC_ATTR_TARGET_ISO15693_UID]);
		if (iso15693_uid_len == NFC_MAX_ISO15693_UID_LEN)
			memcpy(iso15693_uid,
			       nla_data(attrs[NFC_ATTR_TARGET_ISO15693_UID]),
					NFC_MAX_ISO15693_UID_LEN);
	} else {
		iso15693_uid_len = 0;
	}

	DBG("target idx %d proto 0x%x sens_res 0x%x sel_res 0x%x NFCID len %d",
	    target_idx, protocols, sens_res, sel_res, nfcid_len);
	DBG("\tiso15693_uid_len %d", iso15693_uid_len);

	__near_adapter_add_target(adapter_idx, target_idx, protocols,
				  sens_res, sel_res, nfcid, nfcid_len,
				  iso15693_dsfid,
				  iso15693_uid_len, iso15693_uid);

	return 0;
}
Esempio n. 2
0
struct match_msg *match_nl_alloc_msg(uint8_t type, uint32_t pid,
				   int flags, int size, int family)
{
	struct match_msg *msg;
	static uint32_t seq = 0;

	msg = (struct match_msg *) malloc(sizeof(struct match_msg));
	if (!msg)
		return NULL;

	msg->nlbuf = nlmsg_alloc();

	msg->msg = genlmsg_put(msg->nlbuf, 0, seq, family, (int)size, flags,
			       type, NET_MAT_GENL_VERSION);

	msg->seq = seq++;

	if (pid) {
		struct nl_msg *nl_msg = msg->nlbuf;
		struct sockaddr_nl nladdr = {
			.nl_family = AF_NETLINK,
			.nl_pid = pid,
			.nl_groups = 0,
		};

		nlmsg_set_dst(nl_msg, &nladdr);
	}
	return msg;
}

struct match_msg *match_nl_get_msg(struct nl_sock *nsd, uint8_t cmd, uint32_t pid,
				 unsigned int ifindex, int family)
{
	struct match_msg *msg;
	sigset_t bs;
	int err;

	msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family);
	if (!msg) {
		MAT_LOG(ERR, "Error: Allocation failure\n");
		return NULL;
	}

	nla_put_u32(msg->nlbuf,
		    NET_MAT_IDENTIFIER_TYPE,
		    NET_MAT_IDENTIFIER_IFINDEX);
	nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex);

	nl_send_auto(nsd, msg->nlbuf);
	match_nl_free_msg(msg);

	sigemptyset(&bs);
	sigaddset(&bs, SIGINT);
	sigprocmask(SIG_UNBLOCK, &bs, NULL);

	msg = match_nl_recv_msg(nsd, &err);
	sigprocmask(SIG_BLOCK, &bs, NULL);
	return msg;
}

int match_nl_pci_lport(struct nl_sock *nsd, uint32_t pid,
		      unsigned int ifindex, int family,
		      uint8_t bus, uint8_t device, uint8_t function,
		      uint32_t *lport)
{
	struct net_mat_port port = {.pci = {0}, .port_id = 0};
	struct net_mat_port ports[2] = {{0}, {0}};
	uint8_t cmd = NET_MAT_PORT_CMD_GET_LPORT;
	struct net_mat_port *port_query = NULL;
	struct match_msg *msg;
	sigset_t bs;
	int err;

	msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family);
	if (!msg) {
		MAT_LOG(ERR, "Error: Allocation failure\n");
		return -ENOMEM;
	}

	if (nla_put_u32(msg->nlbuf,
			NET_MAT_IDENTIFIER_TYPE,
			NET_MAT_IDENTIFIER_IFINDEX) ||
	    nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) {
		match_nl_free_msg(msg);
		return -EMSGSIZE;
	}
	port.pci.bus = bus;
	port.pci.device = device;
	port.pci.function = function;
	ports[0] = port;

	err = match_put_ports(msg->nlbuf, ports);
	if (err) {
		match_nl_free_msg(msg);
		return -EMSGSIZE;
	}

	nl_send_auto(nsd, msg->nlbuf);
	match_nl_free_msg(msg);

	sigemptyset(&bs);
	sigaddset(&bs, SIGINT);
	sigprocmask(SIG_UNBLOCK, &bs, NULL);

	msg = match_nl_recv_msg(nsd, &err);

	if (msg) {
		struct nlmsghdr *nlh = msg->msg;
		struct nlattr *tb[NET_MAT_MAX+1];
		int err;

		err = genlmsg_parse(nlh, 0, tb,
				    NET_MAT_MAX, match_get_tables_policy);
		if (err < 0) {
			MAT_LOG(ERR, "Warning: unable to parse pci to lport msg\n");
			match_nl_free_msg(msg);
			return -EINVAL;
		}

		if (match_nl_table_cmd_to_type(stdout, true, NET_MAT_PORTS, tb)) {
			match_nl_free_msg(msg);
			return -EINVAL;
		}

		if (tb[NET_MAT_PORTS]) {
			err = match_get_ports(stdout, verbose,
					     tb[NET_MAT_PORTS], &port_query);
			if (err) {
				match_nl_free_msg(msg);
				return -EINVAL;
			}
		}

		if (!port_query) {
			match_nl_free_msg(msg);
			return -EINVAL;
		}

		*lport = port_query[0].port_id;
	}
	match_nl_free_msg(msg);
	free(port_query);
	return 0;
}
Esempio n. 3
0
static int ipvs_services_parse_cb(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1];
	struct nlattr *svc_attrs[IPVS_SVC_ATTR_MAX + 1];
	struct ip_vs_get_services **getp = (struct ip_vs_get_services **)arg;
	struct ip_vs_get_services *get = (struct ip_vs_get_services *)*getp;
	struct ip_vs_flags flags;
	int i = get->num_services;

	if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0)
		return -1;

	if (!attrs[IPVS_CMD_ATTR_SERVICE])
		return -1;

	if (nla_parse_nested(svc_attrs, IPVS_SVC_ATTR_MAX, attrs[IPVS_CMD_ATTR_SERVICE], ipvs_service_policy))
		return -1;

	memset(&(get->entrytable[i]), 0, sizeof(get->entrytable[i]));

	if (!(svc_attrs[IPVS_SVC_ATTR_AF] &&
	      (svc_attrs[IPVS_SVC_ATTR_FWMARK] ||
	       (svc_attrs[IPVS_SVC_ATTR_PROTOCOL] &&
		svc_attrs[IPVS_SVC_ATTR_ADDR] &&
		svc_attrs[IPVS_SVC_ATTR_PORT])) &&
	      svc_attrs[IPVS_SVC_ATTR_SCHED_NAME] &&
	      svc_attrs[IPVS_SVC_ATTR_NETMASK] &&
	      svc_attrs[IPVS_SVC_ATTR_TIMEOUT] &&
	      svc_attrs[IPVS_SVC_ATTR_FLAGS]))
		return -1;

	get->entrytable[i].af = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_AF]);

	if (svc_attrs[IPVS_SVC_ATTR_FWMARK])
		get->entrytable[i].fwmark = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_FWMARK]);
	else {
		get->entrytable[i].protocol = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_PROTOCOL]);
		memcpy(&(get->entrytable[i].addr), nla_data(svc_attrs[IPVS_SVC_ATTR_ADDR]),
		       sizeof(get->entrytable[i].addr));
		get->entrytable[i].port = nla_get_u16(svc_attrs[IPVS_SVC_ATTR_PORT]);
	}

	strncpy(get->entrytable[i].sched_name,
		nla_get_string(svc_attrs[IPVS_SVC_ATTR_SCHED_NAME]),
		IP_VS_SCHEDNAME_MAXLEN);

	get->entrytable[i].netmask = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_NETMASK]);
	get->entrytable[i].timeout = nla_get_u32(svc_attrs[IPVS_SVC_ATTR_TIMEOUT]);
	nla_memcpy(&flags, svc_attrs[IPVS_SVC_ATTR_FLAGS], sizeof(flags));
	get->entrytable[i].flags = flags.flags & flags.mask;

	if (ipvs_parse_stats(&(get->entrytable[i].stats),
			     svc_attrs[IPVS_SVC_ATTR_STATS]) != 0)
		return -1;

	get->entrytable[i].num_dests = 0;

	i++;

	get->num_services = i;
	get = realloc(get, sizeof(*get)
	      + sizeof(ipvs_service_entry_t) * (get->num_services + 1));
	*getp = get;
	return 0;
}
Esempio n. 4
0
struct net_mat_port *match_nl_get_ports(struct nl_sock *nsd, uint32_t pid,
                      unsigned int ifindex, int family, uint32_t min, uint32_t max)
{
	uint8_t cmd = NET_MAT_PORT_CMD_GET_PORTS;
	struct nlattr *tb[NET_MAT_MAX+1];
	struct net_mat_port *port = NULL;
	struct match_msg *msg;
	struct nlmsghdr *nlh;
	struct nlattr *ports;
	sigset_t bs;
	int err = 0;

	msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family);
	if (!msg) {
		MAT_LOG(ERR, "Error: Allocation failure\n");
		return NULL;
	}

	if (nla_put_u32(msg->nlbuf,
                        NET_MAT_IDENTIFIER_TYPE,
                        NET_MAT_IDENTIFIER_IFINDEX) ||
		nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) {
		MAT_LOG(ERR, "Error: Identifier put failed\n");
		goto out;
	}
	err = match_put_rule_error(msg->nlbuf, NET_MAT_RULES_ERROR_CONT_LOG);
	if (err)
		goto out;

	ports = nla_nest_start(msg->nlbuf, NET_MAT_PORTS);
	if (!ports) {
		MAT_LOG(ERR, "Error: get_port attributes failed\n");
		goto out;
	}
	if (min) {
		err = nla_put_u32(msg->nlbuf, NET_MAT_PORT_MIN_INDEX,
                                min);
		if (err)
			goto out;
	}
	if (max) {
		err = nla_put_u32(msg->nlbuf, NET_MAT_PORT_MAX_INDEX,
                                max);
		if (err)
			goto out;
	}
	nla_nest_end(msg->nlbuf, ports);
	nl_send_auto(nsd, msg->nlbuf);
	match_nl_free_msg(msg);

	/* message sent handle recv */
	sigemptyset(&bs);
	sigaddset(&bs, SIGINT);
	sigprocmask(SIG_UNBLOCK, &bs, NULL);

	msg = match_nl_recv_msg(nsd, &err);
	sigprocmask(SIG_BLOCK, &bs, NULL);
	if (msg) {
		nlh = msg->msg;
		err = genlmsg_parse(nlh, 0, tb, NET_MAT_MAX, match_get_tables_policy);
		if (err < 0) {
			MAT_LOG(ERR, "Warning: unable to parse get rules msg\n");
			goto out;
		}

		if (match_nl_table_cmd_to_type(stdout, true,
                                              NET_MAT_PORTS, tb))
                        goto out;

		if (tb[NET_MAT_PORTS]) {
			err = match_get_ports(stdout, verbose, tb[NET_MAT_PORTS], &port);
			if (err)
				goto out;
		}
	}
	match_nl_free_msg(msg);
	return port;
out:
	match_nl_free_msg(msg);
	return NULL;
}
Esempio n. 5
0
int match_nl_set_port(struct nl_sock *nsd, uint32_t pid,
				unsigned int ifindex, int family,
				struct net_mat_port *port)
{
	uint8_t cmd = NET_MAT_PORT_CMD_SET_PORTS;
	struct nlattr *tb[NET_MAT_MAX+1];
	struct nlattr *nest, *nest1;
	struct nlmsghdr *nlh;
	struct match_msg *msg;
	sigset_t bs;
	int err = 0;

	msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family);
	if (!msg) {
		MAT_LOG(ERR, "Error: Allocation failure\n");
		return -ENOMSG;
	}

	if (nla_put_u32(msg->nlbuf,
			NET_MAT_IDENTIFIER_TYPE,
			NET_MAT_IDENTIFIER_IFINDEX) ||
	    nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) {
		MAT_LOG(ERR, "Error: Identifier put failed\n");
		match_nl_free_msg(msg);
		return -EMSGSIZE;
	}

	nest = nla_nest_start(msg->nlbuf, NET_MAT_PORTS);
	if (!nest) {
		match_nl_free_msg(msg);
		return -EMSGSIZE;
	}
	nest1 = nla_nest_start(msg->nlbuf, NET_MAT_PORTS);
	match_put_port(msg->nlbuf, port);
	nla_nest_end(msg->nlbuf, nest1);
	nla_nest_end(msg->nlbuf, nest);
	nl_send_auto(nsd, msg->nlbuf);
	match_nl_free_msg(msg);

	sigemptyset(&bs);
	sigaddset(&bs, SIGINT);
	sigprocmask(SIG_UNBLOCK, &bs, NULL);

	msg = match_nl_recv_msg(nsd, &err);
	sigprocmask(SIG_BLOCK, &bs, NULL);

	if (!msg)
		return -EINVAL;

	nlh = msg->msg;
	err = genlmsg_parse(nlh, 0, tb, NET_MAT_MAX, match_get_tables_policy);
	if (err < 0) {
		MAT_LOG(ERR, "Warning: unable to parse set port msg\n");
		match_nl_free_msg(msg);
		return err;
	}

	err = match_nl_table_cmd_to_type(stdout, true, 0, tb);
	if (err) {
		match_nl_free_msg(msg);
		return err;
	}

	if (tb[NET_MAT_PORTS]) {
		MAT_LOG(ERR, "Failed to set:\n");
		match_get_ports(stdout, verbose, tb[NET_MAT_PORTS], NULL);
		match_nl_free_msg(msg);
		return -EINVAL;
	}
	match_nl_free_msg(msg);
	return 0;
}
Esempio n. 6
0
int match_nl_set_del_rules(struct nl_sock *nsd, uint32_t pid,
		      unsigned int ifindex, int family,
		      struct net_mat_rule *rule, uint8_t cmd)
{
	struct nlattr *tb[NET_MAT_MAX+1];
	struct match_msg *msg;
	struct nlmsghdr *nlh;
	struct nlattr *rules;
	sigset_t bs;
	int err = 0;

	pp_rule(stdout, true, rule);

	msg = match_nl_alloc_msg(cmd, pid, NLM_F_REQUEST|NLM_F_ACK, 0, family);
	if (!msg) {
		MAT_LOG(ERR, "Error: Allocation failure\n");
		return -ENOMSG;
	}

	if (nla_put_u32(msg->nlbuf,
			NET_MAT_IDENTIFIER_TYPE,
			NET_MAT_IDENTIFIER_IFINDEX) ||
	    nla_put_u32(msg->nlbuf, NET_MAT_IDENTIFIER, ifindex)) {
		MAT_LOG(ERR, "Error: Identifier put failed\n");
		match_nl_free_msg(msg);
		return -EMSGSIZE;
	}

	err = match_put_rule_error(msg->nlbuf, NET_MAT_RULES_ERROR_CONT_LOG);
	if (err) {
		match_nl_free_msg(msg);
		return err;
	}

	rules = nla_nest_start(msg->nlbuf, NET_MAT_RULES);
	if (!rules) {
		match_nl_free_msg(msg);
		return -EMSGSIZE;
	}
	match_put_rule(msg->nlbuf, rule);
	nla_nest_end(msg->nlbuf, rules);

	nl_send_auto(nsd, msg->nlbuf);
	match_nl_free_msg(msg);

	/* message sent handle recv */
	sigemptyset(&bs);
	sigaddset(&bs, SIGINT);
	sigprocmask(SIG_UNBLOCK, &bs, NULL);

	msg = match_nl_recv_msg(nsd, &err);
	sigprocmask(SIG_BLOCK, &bs, NULL);

	if (!msg)
		return -EINVAL;

	nlh = msg->msg;
	err = genlmsg_parse(nlh, 0, tb, NET_MAT_MAX, match_get_tables_policy);
	if (err < 0) {
		MAT_LOG(ERR, "Warning: unable to parse set rules msg\n");
		match_nl_free_msg(msg);
		return err;
	}

	err = match_nl_table_cmd_to_type(stdout, true, 0, tb);
	if (err) {
		match_nl_free_msg(msg);
		return err;
	}

	if (tb[NET_MAT_RULES]) {
		MAT_LOG(ERR, "Failed to set:\n");
		match_get_rules(stdout, verbose, tb[NET_MAT_RULES], NULL);
		match_nl_free_msg(msg);
		return -EINVAL;
	}
	match_nl_free_msg(msg);
	return 0;
}
Esempio n. 7
0
static int ipvs_dests_parse_cb(struct nl_msg *msg, void *arg)
{
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct nlattr *attrs[IPVS_CMD_ATTR_MAX + 1];
	struct nlattr *dest_attrs[IPVS_DEST_ATTR_MAX + 1];
	struct nlattr *attr_addr_family = NULL;
	struct ip_vs_get_dests **dp = (struct ip_vs_get_dests **)arg;
	struct ip_vs_get_dests *d = (struct ip_vs_get_dests *)*dp;
	int i = d->num_dests;

	if (genlmsg_parse(nlh, 0, attrs, IPVS_CMD_ATTR_MAX, ipvs_cmd_policy) != 0)
		return -1;

	if (!attrs[IPVS_CMD_ATTR_DEST])
		return -1;

	if (nla_parse_nested(dest_attrs, IPVS_DEST_ATTR_MAX, attrs[IPVS_CMD_ATTR_DEST], ipvs_dest_policy))
		return -1;

	memset(&(d->entrytable[i]), 0, sizeof(d->entrytable[i]));

	if (!(dest_attrs[IPVS_DEST_ATTR_ADDR] &&
	      dest_attrs[IPVS_DEST_ATTR_PORT] &&
	      dest_attrs[IPVS_DEST_ATTR_FWD_METHOD] &&
	      dest_attrs[IPVS_DEST_ATTR_WEIGHT] &&
	      dest_attrs[IPVS_DEST_ATTR_U_THRESH] &&
	      dest_attrs[IPVS_DEST_ATTR_L_THRESH] &&
	      dest_attrs[IPVS_DEST_ATTR_ACTIVE_CONNS] &&
	      dest_attrs[IPVS_DEST_ATTR_INACT_CONNS] &&
	      dest_attrs[IPVS_DEST_ATTR_PERSIST_CONNS]))
		return -1;

	memcpy(&(d->entrytable[i].addr),
	       nla_data(dest_attrs[IPVS_DEST_ATTR_ADDR]),
	       sizeof(d->entrytable[i].addr));
	d->entrytable[i].port = nla_get_u16(dest_attrs[IPVS_DEST_ATTR_PORT]);
	d->entrytable[i].conn_flags = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_FWD_METHOD]);
	d->entrytable[i].weight = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_WEIGHT]);
	d->entrytable[i].u_threshold = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_U_THRESH]);
	d->entrytable[i].l_threshold = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_L_THRESH]);
	d->entrytable[i].activeconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_ACTIVE_CONNS]);
	d->entrytable[i].inactconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_INACT_CONNS]);
	d->entrytable[i].persistconns = nla_get_u32(dest_attrs[IPVS_DEST_ATTR_PERSIST_CONNS]);
	attr_addr_family = dest_attrs[IPVS_DEST_ATTR_ADDR_FAMILY];
	if (attr_addr_family)
		d->entrytable[i].af = nla_get_u16(attr_addr_family);
	else
		d->entrytable[i].af = d->af;

	if (dest_attrs[IPVS_DEST_ATTR_STATS64]) {
		if (ipvs_parse_stats(&d->entrytable[i].stats64,
				     dest_attrs[IPVS_DEST_ATTR_STATS64]) != 0)
			return -1;
	} else if (dest_attrs[IPVS_DEST_ATTR_STATS]) {
		if (ipvs_parse_stats(&d->entrytable[i].stats64,
				     dest_attrs[IPVS_DEST_ATTR_STATS]) != 0)
			return -1;
	}

	i++;

	d->num_dests = i;
	d = realloc(d, sizeof(*d) + sizeof(ipvs_dest_entry_t) * (d->num_dests + 1));
	*dp = d;
	return 0;
}
Esempio n. 8
0
/**
 * Callback to process an WIMAX_GNL_RE_STATE_CHANGE from the kernel
 *
 * \internal
 *
 * \param wmx WiMAX device handle
 * \param mch WiMAX multicast group handle
 * \param msg Pointer to netlink message
 * \return \c enum nl_cb_action
 *
 * wimaxll_mc_rx_read() calls libnl's nl_recvmsgs() to receive messages;
 * when a valid message is received, it goes into a loop that selects
 * a callback to run for each type of message and it will call this
 * function.
 *
 * This just expects a _RE_STATE_CHANGE message, whose payload is what
 * has to be passed to the caller. We just extract the data and call
 * the callback defined in the handle.
 */
int wimaxll_gnl_handle_state_change(struct wimaxll_handle *wmx,
				    struct nl_msg *msg)
{
	ssize_t result;
	struct nlmsghdr *nl_hdr;
	struct genlmsghdr *gnl_hdr;
	struct nlattr *tb[WIMAX_GNL_ATTR_MAX+1];
	enum wimax_st old_state, new_state;
	unsigned dest_ifidx;
	
	d_fnstart(7, wmx, "(wmx %p msg %p)\n", wmx, msg);
	nl_hdr = nlmsg_hdr(msg);
	gnl_hdr = nlmsg_data(nl_hdr);

	assert(gnl_hdr->cmd == WIMAX_GNL_RE_STATE_CHANGE);

	/* Parse the attributes */
	result = genlmsg_parse(nl_hdr, 0, tb, WIMAX_GNL_ATTR_MAX,
			       wimaxll_gnl_re_state_change_policy);
	if (result < 0) {
		wimaxll_msg(wmx, "E: %s: genlmsg_parse() failed: %zd\n",
			  __func__, result);
		goto error_parse;
	}
	/* Find if the message is for the interface wmx represents */
	dest_ifidx = nla_get_u32(tb[WIMAX_GNL_STCH_IFIDX]);
	if (wmx->ifidx > 0 && wmx->ifidx != dest_ifidx) {
		wimaxll_msg(wmx, "E: %s: cannot find IFIDX attribute\n",
			    __func__);
		result = -ENODEV;
		goto error_no_attrs;
	}

	if (tb[WIMAX_GNL_STCH_STATE_OLD] == NULL) {
		wimaxll_msg(wmx, "E: %s: cannot find STCH_STATE_OLD "
			    "attribute\n", __func__);
		result = -ENXIO;
		goto error_no_attrs;

	}
	old_state = nla_get_u8(tb[WIMAX_GNL_STCH_STATE_OLD]);

	if (tb[WIMAX_GNL_STCH_STATE_NEW] == NULL) {
		wimaxll_msg(wmx, "E: %s: cannot find STCH_STATE_NEW "
			    "attribute\n", __func__);
		result = -EINVAL;
		goto error_no_attrs;

	}
	new_state = nla_get_u8(tb[WIMAX_GNL_STCH_STATE_NEW]);

	d_printf(1, wmx, "D: CRX re_state_change old %u new %u\n",
		 old_state, new_state);

	/* If this is an "any" handle, set the wmx->ifidx to the
	 * received one so the callback can now where did the thing
	 * come from. Will be restored.
	 */
	if (wmx->ifidx == 0) {
		wmx->ifidx = dest_ifidx;
		dest_ifidx = 0;
	}
	/* Now execute the callback for handling re-state-change; if
	 * it doesn't update the context's result code, we'll do. */
	result = wmx->state_change_cb(wmx, wmx->state_change_priv,
				      old_state, new_state);
	wmx->ifidx = dest_ifidx;
error_no_attrs:
error_parse:
	d_fnend(7, wmx, "(wmx %p msg %p) = %zd\n", wmx, msg, result);
	return result;
}