Exemple #1
0
static int deth_netlink_do_broadcast_addresses(struct sock* nl_sk, u32 index)
{
    struct sk_buff* skb = nlmsg_new(sizeof(u32), 0);
    struct nlmsghdr* nlh;

    if (!skb)
    {
        printk(KERN_ERR "Failed to allocate new skb\n");

        return -ENOBUFS;
    }

    nlh = nlmsg_put(skb, 0, 0, MULTICAST_ADDRESS_CHANGE, sizeof(u32), 0);

    if (nlh == NULL)
    {
        nlmsg_free(skb);
        
        return -EMSGSIZE;
    }

    memcpy(nlmsg_data(nlh), &index, sizeof(u32));

#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,7,0)
	NETLINK_CB(skb).portid = 0;
#else
    NETLINK_CB(skb).pid = 0;
#endif

    NETLINK_CB(skb).dst_group = NETLINK_DETH_GROUP;

    return netlink_broadcast(nl_sk, skb, 0, NETLINK_DETH_GROUP, GFP_KERNEL);
}
Exemple #2
0
static struct nl_msg *build_rule_msg(struct rtnl_rule *tmpl, int cmd, int flags)
{
	struct nl_msg *msg;
	struct rtmsg rtm = {
		.rtm_type = RTN_UNSPEC
	};

	if (cmd == RTM_NEWRULE)
		rtm.rtm_type = RTN_UNICAST;
		
	if (tmpl->ce_mask & RULE_ATTR_FAMILY)
		rtm.rtm_family = tmpl->r_family;

	if (tmpl->ce_mask & RULE_ATTR_TABLE)
		rtm.rtm_table = tmpl->r_table;

	if (tmpl->ce_mask & RULE_ATTR_DSFIELD)
		rtm.rtm_tos = tmpl->r_dsfield;

	if (tmpl->ce_mask & RULE_ATTR_TYPE)
		rtm.rtm_type = tmpl->r_type;

	if (tmpl->ce_mask & RULE_ATTR_SRC_LEN)
		rtm.rtm_src_len = tmpl->r_src_len;

	if (tmpl->ce_mask & RULE_ATTR_DST_LEN)
		rtm.rtm_dst_len = tmpl->r_dst_len;

	msg = nlmsg_alloc_simple(cmd, flags);
	if (!msg)
		goto nla_put_failure;

	if (nlmsg_append(msg, &rtm, sizeof(rtm), NLMSG_ALIGNTO) < 0)
		goto nla_put_failure;

	if (tmpl->ce_mask & RULE_ATTR_SRC)
		NLA_PUT_ADDR(msg, RTA_SRC, tmpl->r_src);

	if (tmpl->ce_mask & RULE_ATTR_DST)
		NLA_PUT_ADDR(msg, RTA_DST, tmpl->r_dst);

	if (tmpl->ce_mask & RULE_ATTR_PRIO)
		NLA_PUT_U32(msg, RTA_PRIORITY, tmpl->r_prio);

	if (tmpl->ce_mask & RULE_ATTR_MARK)
		NLA_PUT_U32(msg, RTA_PROTOINFO, tmpl->r_mark);

	if (tmpl->ce_mask & RULE_ATTR_REALMS)
		NLA_PUT_U32(msg, RTA_FLOW, tmpl->r_realms);

	if (tmpl->ce_mask & RULE_ATTR_IIF)
		NLA_PUT_STRING(msg, RTA_IIF, tmpl->r_iif);

	return msg;

nla_put_failure:
	nlmsg_free(msg);
	return NULL;
}
Exemple #3
0
static int nfnl_log_build_request(const struct nfnl_log *log,
				  struct nl_msg **result)
{
	struct nl_msg *msg;

	if (!nfnl_log_test_group(log))
		return -NLE_MISSING_ATTR;

	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_ULOG, NFULNL_MSG_CONFIG, 0,
				   0, nfnl_log_get_group(log));
	if (msg == NULL)
		return -NLE_NOMEM;

	/* This sucks. The nfnetlink_log interface always expects both
	 * parameters to be present. Needs to be done properly.
	 */
	if (nfnl_log_test_copy_mode(log)) {
		struct nfulnl_msg_config_mode mode;

		switch (nfnl_log_get_copy_mode(log)) {
		case NFNL_LOG_COPY_NONE:
			mode.copy_mode = NFULNL_COPY_NONE;
			break;
		case NFNL_LOG_COPY_META:
			mode.copy_mode = NFULNL_COPY_META;
			break;
		case NFNL_LOG_COPY_PACKET:
			mode.copy_mode = NFULNL_COPY_PACKET;
			break;
		}
		mode.copy_range = htonl(nfnl_log_get_copy_range(log));
		mode._pad = 0;

		if (nla_put(msg, NFULA_CFG_MODE, sizeof(mode), &mode) < 0)
			goto nla_put_failure;
	}

	if (nfnl_log_test_flush_timeout(log) &&
	    nla_put_u32(msg, NFULA_CFG_TIMEOUT,
			htonl(nfnl_log_get_flush_timeout(log))) < 0)
		goto nla_put_failure;

	if (nfnl_log_test_alloc_size(log) &&
	    nla_put_u32(msg, NFULA_CFG_NLBUFSIZ,
			htonl(nfnl_log_get_alloc_size(log))) < 0)
		goto nla_put_failure;

	if (nfnl_log_test_queue_threshold(log) &&
	    nla_put_u32(msg, NFULA_CFG_QTHRESH,
			htonl(nfnl_log_get_queue_threshold(log))) < 0)
		goto nla_put_failure;

	*result = msg;
	return 0;

nla_put_failure:
	nlmsg_free(msg);
	return -NLE_MSGSIZE;
}
Exemple #4
0
/* return after DAD finishes for all known IPv6 addresses or an error */
int
virNetDevIPWaitDadFinish(virSocketAddrPtr *addrs, size_t count)
{
    struct nl_msg *nlmsg = NULL;
    struct ifaddrmsg ifa;
    struct nlmsghdr *resp = NULL;
    unsigned int recvbuflen;
    int ret = -1;
    bool dad = true;
    time_t max_time = time(NULL) + VIR_DAD_WAIT_TIMEOUT;

    if (!(nlmsg = nlmsg_alloc_simple(RTM_GETADDR,
                                     NLM_F_REQUEST | NLM_F_DUMP))) {
        virReportOOMError();
        return -1;
    }

    memset(&ifa, 0, sizeof(ifa));
    /* DAD is for IPv6 adresses only. */
    ifa.ifa_family = AF_INET6;
    if (nlmsg_append(nlmsg, &ifa, sizeof(ifa), NLMSG_ALIGNTO) < 0) {
        virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                       _("allocated netlink buffer is too small"));
        goto cleanup;
    }

    /* Periodically query netlink until DAD finishes on all known addresses. */
    while (dad && time(NULL) < max_time) {
        if (virNetlinkCommand(nlmsg, &resp, &recvbuflen, 0, 0,
                              NETLINK_ROUTE, 0) < 0)
            goto cleanup;

        if (virNetlinkGetErrorCode(resp, recvbuflen) < 0) {
            virReportError(VIR_ERR_SYSTEM_ERROR, "%s",
                           _("error reading DAD state information"));
            goto cleanup;
        }

        /* Parse response. */
        dad = virNetDevIPParseDadStatus(resp, recvbuflen, addrs, count);
        if (dad)
            usleep(1000 * 10);

        VIR_FREE(resp);
    }
    /* Check timeout. */
    if (dad) {
        virReportError(VIR_ERR_SYSTEM_ERROR,
                       _("Duplicate Address Detection "
                         "not finished in %d seconds"), VIR_DAD_WAIT_TIMEOUT);
    } else {
        ret = 0;
    }

 cleanup:
    VIR_FREE(resp);
    nlmsg_free(nlmsg);
    return ret;
}
Exemple #5
0
static int netdev_set_flag(const char *name, int flag)
{
	struct nl_handler nlh;
	struct nlmsg *nlmsg = NULL, *answer = NULL;
	struct link_req *link_req;
	int index, len, err;

	err = netlink_open(&nlh, NETLINK_ROUTE);
	if (err)
		return err;

	err = -EINVAL;
	len = strlen(name);
	if (len == 1 || len >= IFNAMSIZ)
		goto out;

	err = -ENOMEM;
	nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE);
	if (!nlmsg)
		goto out;

	answer = nlmsg_alloc(NLMSG_GOOD_SIZE);
	if (!answer)
		goto out;

	err = -EINVAL;
	index = if_nametoindex(name);
	if (!index)
		goto out;

	link_req = (struct link_req *)nlmsg;
	link_req->ifinfomsg.ifi_family = AF_UNSPEC;
	link_req->ifinfomsg.ifi_index = index;
	link_req->ifinfomsg.ifi_change |= IFF_UP;
	link_req->ifinfomsg.ifi_flags |= flag;
	nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
	nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
	nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK;

	err = netlink_transaction(&nlh, nlmsg, answer);
out:
	netlink_close(&nlh);
	nlmsg_free(nlmsg);
	nlmsg_free(answer);
	return err;
}
Exemple #6
0
int nf10_reg_wr(uint32_t addr, uint32_t val)
{
    struct nl_msg   *msg;
    int             err;

    err = driver_connect();
    if(err)
        return err;

    msg = nlmsg_alloc();
    if(msg == NULL) {
        driver_disconnect();
        return -NLE_NOMEM;
    }

    /* genlmsg_put will fill in the fields of the nlmsghdr and the genlmsghdr. */
    genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, nf10_genl_family, 0, 0,
            NF10_GENL_C_REG_WR, NF10_GENL_FAMILY_VERSION);

    nla_put_u32(msg, NF10_GENL_A_ADDR32, addr);
    nla_put_u32(msg, NF10_GENL_A_REGVAL32, val);

    /* nl_send_auto will automatically fill in the PID and the sequence number,
     * and also add an NLM_F_REQUEST flag. It will also add an NLM_F_ACK
     * flag unless the netlink socket has the NL_NO_AUTO_ACK flag set. */
    err = nl_send_auto(nf10_genl_sock, msg);
    if(err < 0) {
        nlmsg_free(msg);
        driver_disconnect();
        return err;
    }

    nlmsg_free(msg);

    nl_socket_modify_cb(nf10_genl_sock, NL_CB_ACK, NL_CB_CUSTOM, nf10_reg_wr_recv_ack_cb, NULL);

    /* FIXME: this function will return even if there's no ACK in the buffer. I.E. it doesn't
     * seem to wait for the ACK to be received... Ideally we'd have the behavior that getting an
     * ACK tells us everything is OK, otherwise we time out on waiting for an ACK and tell this
     * to the user. */
    err = nl_recvmsgs_default(nf10_genl_sock);

    driver_disconnect();

    return err;
}
Exemple #7
0
int ipvs_nl_send_message(struct nl_msg *msg, nl_recvmsg_msg_cb_t func, void *arg)
{
	int err = EINVAL;

	sock = nl_socket_alloc();
	if (!sock) {
		nlmsg_free(msg);
		return -1;
	}

	if (genl_connect(sock) < 0)
		goto fail_genl;

	family = genl_ctrl_resolve(sock, IPVS_GENL_NAME);
	if (family < 0)
		goto fail_genl;

	/* To test connections and set the family */
	if (msg == NULL) {
		nl_socket_free(sock);
		sock = NULL;
		return 0;
	}

	if (nl_socket_modify_cb(sock, NL_CB_VALID, NL_CB_CUSTOM, func, arg) != 0)
		goto fail_genl;

	if (nl_send_auto_complete(sock, msg) < 0)
		goto fail_genl;

	if ((err = -nl_recvmsgs_default(sock)) > 0)
		goto fail_genl;

	nlmsg_free(msg);

	nl_socket_free(sock);

	return 0;

fail_genl:
	nl_socket_free(sock);
	sock = NULL;
	nlmsg_free(msg);
	errno = err;
	return -1;
}
int SoftapController::executeScanLinkCmd(const char *iface, int *iface_freq)
{
    struct nl_cb *cb;
    struct nl_msg *msg;
    int devidx = 0;
    int err;

    // initialize to non-valid freq
    *iface_freq = 0;

    devidx = if_nametoindex(iface);
    if (devidx == 0) {
        LOGE("failed to translate ifname to idx");
        return -errno;
    }

    msg = nlmsg_alloc();
    if (!msg) {
        LOGE("failed to allocate netlink message");
        return 2;
    }

    cb = nl_cb_alloc(NL_CB_DEFAULT);
    if (!cb) {
        LOGE("failed to allocate netlink callbacks");
        err = 2;
        goto out_free_msg;
    }

    genlmsg_put(msg, 0, 0, genl_family_get_id(nl80211), 0,
                NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0);

    NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);

    // iface_freq will be filled out by the callback
    nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, linkDumpCbHandler, iface_freq);

    err = nl_send_auto_complete(nl_soc, msg);
    if (err < 0)
        goto out;

    err = 1;
    nl_cb_err(cb, NL_CB_CUSTOM, NlErrorHandler, &err);
    nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, NlFinishHandler, &err);
    nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, NlAckHandler, &err);

    while (err > 0)
        nl_recvmsgs(nl_soc, cb);

out:
    nl_cb_put(cb);
out_free_msg:
    nlmsg_free(msg);
    return err;
nla_put_failure:
    LOGW("building message failed");
    return 2;
}
Exemple #9
0
void ptp_work_send_rtc_change(struct work_struct *work) {
  struct ptp_device *ptp = container_of(work, struct ptp_device, work_send_rtc_change);
  struct sk_buff *skb;
  uint8_t commandByte;
  void *msgHead;
  int returnValue = 0;

  skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
  if(skb == NULL) return;

  /* Decide which command byte to send with the message based upon the lock state */
  if(ptp->rtcLockState == PTP_RTC_LOCKED) {
    commandByte = PTP_EVENTS_C_RTC_LOCK;
  } else {
    commandByte = PTP_EVENTS_C_RTC_UNLOCK;
  }

  /* Create the message headers */
  msgHead = genlmsg_put(skb, 
                        0, 
                        ptp->netlinkSequence++, 
                        &ptp_events_genl_family, 
                        0, 
                        commandByte);
  if(msgHead == NULL) {
    returnValue = -ENOMEM;
    goto rtc_change_fail;
  }

  /* Write the PTP domain identifier to the message */
  returnValue = nla_put_u8(skb, PTP_EVENTS_A_DOMAIN, ptp->properties.domainNumber);
  if(returnValue != 0) goto rtc_change_fail;

  /* Finalize the message and multicast it */
  genlmsg_end(skb, msgHead);
  returnValue = genlmsg_multicast(skb, 0, rtc_mcast.id, GFP_ATOMIC);
  skb = NULL;

  switch(returnValue) {
  case 0:
  case -ESRCH:
    // Success or no process was listening, simply break
    break;

  default:
    // This is an actual error, print the return code
    printk(KERN_INFO DRIVER_NAME ": Failure delivering multicast Netlink message: %d\n",
           returnValue);
    goto rtc_change_fail;
  }

 rtc_change_fail: 
  if (NULL != skb) {
    nlmsg_free(skb);
    skb = NULL;
  }
}
/* NOTE: this function consumes 'msg' */
static int
_nl80211_send_and_recv (struct nl_sock *nl_sock,
                        struct nl_cb *nl_cb,
                        struct nl_msg *msg,
                        int (*valid_handler) (struct nl_msg *, void *),
                        void *valid_data)
{
	struct nl_cb *cb;
	int err, done;

	g_return_val_if_fail (msg != NULL, -ENOMEM);

	cb = nl_cb_clone (nl_cb);
	if (!cb) {
		err = -ENOMEM;
		goto out;
	}

	err = nl_send_auto_complete (nl_sock, msg);
	if (err < 0)
		goto out;

	done = 0;
	nl_cb_err (cb, NL_CB_CUSTOM, error_handler, &done);
	nl_cb_set (cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &done);
	nl_cb_set (cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &done);
	if (valid_handler)
		nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, valid_handler, valid_data);

	/* Loop until one of our NL callbacks says we're done; on success
	 * done will be 1, on error it will be < 0.
	 */
	while (!done) {
		err = nl_recvmsgs (nl_sock, cb);
		if (err && err != -NLE_AGAIN) {
			/* Kernel scan list can change while we are dumping it, as new scan
			 * results from H/W can arrive. BSS info is assured to be consistent
			 * and we don't need consistent view of whole scan list. Hence do
			 * not warn on DUMP_INTR error for get scan command.
			 */
			if (err == -NLE_DUMP_INTR &&
			    genlmsg_hdr(nlmsg_hdr(msg))->cmd == NL80211_CMD_GET_SCAN)
				break;

			nm_log_warn (LOGD_WIFI, "nl_recvmsgs() error: (%d) %s",
			             err, nl_geterror (err));
			break;
		}
	}
	if (err == 0 && done < 0)
		err = done;

 out:
	nl_cb_put (cb);
	nlmsg_free (msg);
	return err;
}
Exemple #11
0
static int nl80211_add_mon_if(struct nl80211_state *state, const char *device,
			      const char *mondevice)
{
	int ifindex, ret;
	struct nl_msg *msg;

	ifindex = device_ifindex(device);

	msg = nl80211_nlmsg_xalloc();

	genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
		    0, NL80211_CMD_NEW_INTERFACE, 0);

	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
	NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, mondevice);
	NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR);

	ret = nl_send_auto_complete(state->nl_sock, msg);
	if (ret < 0) {
		if (ret == -ENFILE) {
			nlmsg_free(msg);
			return -EBUSY;
		}

		panic("Cannot send_auto_complete!\n");
	}

	ret = nl_wait_for_ack(state->nl_sock);
	if (ret < 0) {
		if (ret == -ENFILE) {
			nlmsg_free(msg);
			return -EBUSY;
		}

		panic("Waiting for netlink ack failed!\n");
	}

	nlmsg_free(msg);
	return 0;

nla_put_failure:
	panic("nla put failure!\n");
	return -EIO; /* dummy */
}
Exemple #12
0
static int ipvs_nl_fill_service_attr(struct nl_msg *msg, ipvs_service_t *svc)
{
	struct nlattr *nl_service;
	struct ip_vs_flags flags = { .flags = svc->flags,
				     .mask = ~0 };

	nl_service = nla_nest_start(msg, IPVS_CMD_ATTR_SERVICE);
	if (!nl_service)
		return -1;

	NLA_PUT_U16(msg, IPVS_SVC_ATTR_AF, svc->af);

	if (svc->fwmark) {
		NLA_PUT_U32(msg, IPVS_SVC_ATTR_FWMARK, svc->fwmark);
	} else {
		NLA_PUT_U16(msg, IPVS_SVC_ATTR_PROTOCOL, svc->protocol);
		NLA_PUT(msg, IPVS_SVC_ATTR_ADDR, sizeof(svc->addr), &(svc->addr));
		NLA_PUT_U16(msg, IPVS_SVC_ATTR_PORT, svc->port);
	}

	NLA_PUT_STRING(msg, IPVS_SVC_ATTR_SCHED_NAME, svc->sched_name);
	if (svc->pe_name[0])
		NLA_PUT_STRING(msg, IPVS_SVC_ATTR_PE_NAME, svc->pe_name);
	NLA_PUT(msg, IPVS_SVC_ATTR_FLAGS, sizeof(flags), &flags);
	NLA_PUT_U32(msg, IPVS_SVC_ATTR_TIMEOUT, svc->timeout);
	NLA_PUT_U32(msg, IPVS_SVC_ATTR_NETMASK, svc->netmask);

	nla_nest_end(msg, nl_service);
	return 0;

nla_put_failure:
	return -1;
}
#endif

int ipvs_add_service(ipvs_service_t *svc)
{
	ipvs_func = ipvs_add_service;
#ifdef LIBIPVS_USE_NL
	if (try_nl) {
		struct nl_msg *msg = ipvs_nl_message(IPVS_CMD_NEW_SERVICE, 0);
		if (!msg) return -1;
		if (ipvs_nl_fill_service_attr(msg, svc)) {
			nlmsg_free(msg);
			return -1;
		}
		return ipvs_nl_send_message(msg, ipvs_nl_noop_cb, NULL);
	}
#endif

	CHECK_COMPAT_SVC(svc, -1);
	return setsockopt(sockfd, IPPROTO_IP, IP_VS_SO_SET_ADD, (char *)svc,
			  sizeof(struct ip_vs_service_kern));
out_err:
	return -1;
}
Exemple #13
0
/** Sends a user message to remote node via associated kernel connection. */
int send_user_message(int target_slot_type, int target_slot_index, int data_length, char* data) {
	struct nl_msg* msg = NULL;
	struct nl_msg *ans_msg = NULL;
	struct nlmsghdr *nl_hdr;
	struct genlmsghdr* genl_hdr;
	struct nlattr *nla;

	int ret_val = 0;

	if ( (ret_val=prepare_request_message(state.handle, DIRECTOR_SEND_GENERIC_USER_MESSAGE, state.gnl_fid, &msg) ) != 0 ) {
		goto done;
  	}

  	ret_val = nla_put_u32(msg,
			   DIRECTOR_A_SLOT_TYPE,
			   target_slot_type);
	if (ret_val != 0)
    		goto done;
    	
  	ret_val = nla_put_u32(msg,
			   DIRECTOR_A_SLOT_INDEX,
			   target_slot_index);
	if (ret_val != 0)
    		goto done;

  	ret_val = nla_put_u32(msg,
			   DIRECTOR_A_LENGTH,
			   data_length);
	if (ret_val != 0)
    		goto done;

	ret_val = nla_put(msg, DIRECTOR_A_USER_DATA, data_length, data);
	if (ret_val != 0)
    		goto done;

  	if ( (ret_val = send_request_message(state.handle, msg, 1) ) != 0 )
    		goto done;

	if ( (ret_val = read_message(state.handle, &ans_msg) ) != 0 ) {
	      goto done;
	}

	// TODO: We are not checking, the ack is for this request. Check it!
	while ( !is_ack_message(ans_msg) ) {
	    // We can get different than ack messega here.. in this case we have to process it
	    handle_incoming_message(ans_msg);
	    
	    if ( (ret_val = read_message(state.handle, &ans_msg) ) != 0 ) {
		  goto done;
	    }	  
	}

done:
	nlmsg_free(ans_msg);
	return ret_val;
}
void match_nl_free_msg(struct match_msg *msg)
{
	if(msg) {
		if (msg->nlbuf)
			nlmsg_free(msg->nlbuf);
		else
			free(msg->msg);
		free(msg);
	}
}
static struct nl80211_msg_conveyor * nl80211_msg(const char *ifname, int cmd, int flags)
{
	static struct nl80211_msg_conveyor cv;

	int ifidx = -1, phyidx = -1;
	struct nl_msg *req = NULL;
	struct nl_cb *cb = NULL;

	if (nl80211_init() < 0)
		goto err;

	if (!strncmp(ifname, "phy", 3))
		phyidx = atoi(&ifname[3]);
	else if (!strncmp(ifname, "radio", 5))
		phyidx = atoi(&ifname[5]);
	else if (!strncmp(ifname, "mon.", 4))
		ifidx = if_nametoindex(&ifname[4]);
	else
		ifidx = if_nametoindex(ifname);

	if ((ifidx < 0) && (phyidx < 0))
		return NULL;

	req = nlmsg_alloc();
	if (!req)
		goto err;

	cb = nl_cb_alloc(NL_CB_DEFAULT);
	if (!cb)
		goto err;

	genlmsg_put(req, 0, 0, genl_family_get_id(nls->nl80211), 0,
		flags, cmd, 0);

	if (ifidx > -1)
		NLA_PUT_U32(req, NL80211_ATTR_IFINDEX, ifidx);

	if (phyidx > -1)
		NLA_PUT_U32(req, NL80211_ATTR_WIPHY, phyidx);

	cv.msg = req;
	cv.cb  = cb;

	return &cv;

err:
nla_put_failure:
	if (cb)
		nl_cb_put(cb);

	if (req)
		nlmsg_free(req);

	return NULL;
}
Exemple #16
0
/*
 * Allocate a Report State Change message
 *
 * @header: save it, you need it for _send()
 *
 * Creates and fills a basic state change message; different code
 * paths can then add more attributes to the message as needed.
 *
 * Use wimax_gnl_re_state_change_send() to send the returned skb.
 *
 * Returns: skb with the genl message if ok, IS_ERR() ptr on error
 *     with an errno code.
 */
static
struct sk_buff *wimax_gnl_re_state_change_alloc(
	struct wimax_dev *wimax_dev,
	enum wimax_st new_state, enum wimax_st old_state,
	void **header)
{
	int result;
	struct device *dev = wimax_dev_to_dev(wimax_dev);
	void *data;
	struct sk_buff *report_skb;

	d_fnstart(3, dev, "(wimax_dev %p new_state %u old_state %u)\n",
		  wimax_dev, new_state, old_state);
	result = -ENOMEM;
	report_skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (report_skb == NULL) {
		dev_err(dev, "RE_STCH: can't create message\n");
		goto error_new;
	}
	/* FIXME: sending a group ID as the seq is wrong */
	data = genlmsg_put(report_skb, 0, wimax_gnl_family.mcgrp_offset,
			   &wimax_gnl_family, 0, WIMAX_GNL_RE_STATE_CHANGE);
	if (data == NULL) {
		dev_err(dev, "RE_STCH: can't put data into message\n");
		goto error_put;
	}
	*header = data;

	result = nla_put_u8(report_skb, WIMAX_GNL_STCH_STATE_OLD, old_state);
	if (result < 0) {
		dev_err(dev, "RE_STCH: Error adding OLD attr: %d\n", result);
		goto error_put;
	}
	result = nla_put_u8(report_skb, WIMAX_GNL_STCH_STATE_NEW, new_state);
	if (result < 0) {
		dev_err(dev, "RE_STCH: Error adding NEW attr: %d\n", result);
		goto error_put;
	}
	result = nla_put_u32(report_skb, WIMAX_GNL_STCH_IFIDX,
			     wimax_dev->net_dev->ifindex);
	if (result < 0) {
		dev_err(dev, "RE_STCH: Error adding IFINDEX attribute\n");
		goto error_put;
	}
	d_fnend(3, dev, "(wimax_dev %p new_state %u old_state %u) = %p\n",
		wimax_dev, new_state, old_state, report_skb);
	return report_skb;

error_put:
	nlmsg_free(report_skb);
error_new:
	d_fnend(3, dev, "(wimax_dev %p new_state %u old_state %u) = %d\n",
		wimax_dev, new_state, old_state, result);
	return ERR_PTR(result);
}
int handle_immigration_request(struct nl_msg *req_msg) {
	struct nl_msg *msg = NULL;
	struct nlattr *nla;
	int ret = 0;
	int seq;
	struct internal_state* state = get_current_state();

	// In params	
	int uid;
	int slot_index;
	char* name;
	// Out params
	int accept = 1;
	
	seq = nlmsg_hdr(req_msg)->nlmsg_seq;

	nla = nlmsg_find_attr(nlmsg_hdr(req_msg), sizeof(struct genlmsghdr), DIRECTOR_A_UID);
	if (nla == NULL)
		return  -EBADMSG;
	uid = nla_get_u32(nla);

	nla = nlmsg_find_attr(nlmsg_hdr(req_msg), sizeof(struct genlmsghdr), DIRECTOR_A_INDEX);
	if (nla == NULL)
		return  -EBADMSG;
	slot_index = nla_get_u32(nla);

	nla = nlmsg_find_attr(nlmsg_hdr(req_msg), sizeof(struct genlmsghdr), DIRECTOR_A_NAME);
	if (nla == NULL)
		return  -EBADMSG;
	//name = nl_data_get(nla_get_data(nla));
	name = nla_data(nla);

	//printf("NPM CALLED FOR NAME: %s\n", name);
	if ( immigration_request_callback )
        	immigration_request_callback(uid, slot_index, name, &accept);
	
	if ( (ret=prepare_response_message(state->handle, DIRECTOR_IMMIGRATION_REQUEST_RESPONSE, state->gnl_fid, seq, &msg) ) != 0 ) {
		goto done;
	}
	
	ret = nla_put_u32(msg,
			DIRECTOR_A_DECISION,
			accept);

	if (ret != 0)
		goto error_del_resp;

	ret = send_request_message(state->handle, msg, 0);
	goto done;	

error_del_resp:
	nlmsg_free(msg);
done:	
	return ret;
}
Exemple #18
0
static int nfnl_exp_build_message(const struct nfnl_exp *exp, int cmd, int flags,
				 struct nl_msg **result)
{
	struct nl_msg *msg;
	int err;

	msg = nfnlmsg_alloc_simple(NFNL_SUBSYS_CTNETLINK_EXP, cmd, flags,
				   nfnl_exp_get_family(exp), 0);
	if (msg == NULL)
		return -NLE_NOMEM;

	if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_TUPLE)) < 0)
		goto err_out;

	if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_MASTER)) < 0)
		goto err_out;

	if ((err = nfnl_exp_build_tuple(msg, exp, CTA_EXPECT_MASK)) < 0)
		goto err_out;

	if (nfnl_exp_test_src(exp, NFNL_EXP_TUPLE_NAT)) {
		if ((err = nfnl_exp_build_nat(msg, exp)) < 0)
			goto err_out;
	}

	if (nfnl_exp_test_class(exp))
		NLA_PUT_U32(msg, CTA_EXPECT_CLASS, htonl(nfnl_exp_get_class(exp)));

	if (nfnl_exp_test_fn(exp))
		NLA_PUT_STRING(msg, CTA_EXPECT_FN, nfnl_exp_get_fn(exp));

	if (nfnl_exp_test_id(exp))
		NLA_PUT_U32(msg, CTA_EXPECT_ID, htonl(nfnl_exp_get_id(exp)));

	if (nfnl_exp_test_timeout(exp))
		NLA_PUT_U32(msg, CTA_EXPECT_TIMEOUT, htonl(nfnl_exp_get_timeout(exp)));

	if (nfnl_exp_test_helper_name(exp))
		NLA_PUT_STRING(msg, CTA_EXPECT_HELP_NAME, nfnl_exp_get_helper_name(exp));

	if (nfnl_exp_test_zone(exp))
		NLA_PUT_U16(msg, CTA_EXPECT_ZONE, htons(nfnl_exp_get_zone(exp)));

	if (nfnl_exp_test_flags(exp))
		NLA_PUT_U32(msg, CTA_EXPECT_FLAGS, htonl(nfnl_exp_get_flags(exp)));

	*result = msg;
	return 0;

nla_put_failure:
err_out:
	nlmsg_free(msg);
	return err;
}
Exemple #19
0
/**
 * wimax_msg_alloc - Create a new skb for sending a message to userspace
 *
 * @wimax_dev: WiMAX device descriptor
 * @pipe_name: "named pipe" the message will be sent to
 * @msg: pointer to the message data to send
 * @size: size of the message to send (in bytes), including the header.
 * @gfp_flags: flags for memory allocation.
 *
 * Returns: %0 if ok, negative errno code on error
 *
 * Description:
 *
 * Allocates an skb that will contain the message to send to user
 * space over the messaging pipe and initializes it, copying the
 * payload.
 *
 * Once this call is done, you can deliver it with
 * wimax_msg_send().
 *
 * IMPORTANT:
 *
 * Don't use skb_push()/skb_pull()/skb_reserve() on the skb, as
 * wimax_msg_send() depends on skb->data being placed at the
 * beginning of the user message.
 */
struct sk_buff *wimax_msg_alloc(struct wimax_dev *wimax_dev,
				const char *pipe_name,
				const void *msg, size_t size,
				gfp_t gfp_flags)
{
	int result;
	struct device *dev = wimax_dev->net_dev->dev.parent;
	size_t msg_size;
	void *genl_msg;
	struct sk_buff *skb;

	msg_size = nla_total_size(size)
		+ nla_total_size(sizeof(u32))
		+ (pipe_name ? nla_total_size(strlen(pipe_name)) : 0);
	result = -ENOMEM;
	skb = genlmsg_new(msg_size, gfp_flags);
	if (skb == NULL)
		goto error_new;
	genl_msg = genlmsg_put(skb, 0, 0, &wimax_gnl_family,
			       0, WIMAX_GNL_OP_MSG_TO_USER);
	if (genl_msg == NULL) {
		dev_err(dev, "no memory to create generic netlink message\n");
		goto error_genlmsg_put;
	}
	result = nla_put_u32(skb, WIMAX_GNL_MSG_IFIDX,
			     wimax_dev->net_dev->ifindex);
	if (result < 0) {
		dev_err(dev, "no memory to add ifindex attribute\n");
		goto error_nla_put;
	}
	if (pipe_name) {
		result = nla_put_string(skb, WIMAX_GNL_MSG_PIPE_NAME,
					pipe_name);
		if (result < 0) {
			dev_err(dev, "no memory to add pipe_name attribute\n");
			goto error_nla_put;
		}
	}
	result = nla_put(skb, WIMAX_GNL_MSG_DATA, size, msg);
	if (result < 0) {
		dev_err(dev, "no memory to add payload (msg %p size %zu) in "
			"attribute: %d\n", msg, size, result);
		goto error_nla_put;
	}
	genlmsg_end(skb, genl_msg);
	return skb;

error_nla_put:
error_genlmsg_put:
error_new:
	nlmsg_free(skb);
	return ERR_PTR(result);

}
Exemple #20
0
Fichier : log.c Projet : DINKIN/tuo
static int send_log_msg(struct nl_handle *handle, struct nl_msg *msg)
{
	int err;

	err = nl_send_auto_complete(handle, msg);
	nlmsg_free(msg);
	if (err < 0)
		return err;

	return nl_wait_for_ack(handle);
}
/* function: send_ifaddrmsg
 * sends a netlink/ifaddrmsg message and hands the responses to the callbacks
 * type      - netlink message type
 * flags     - netlink message flags
 * ifa       - ifaddrmsg to send
 * callbacks - callbacks to use with the responses
 */
void send_ifaddrmsg(uint16_t type, uint16_t flags, struct ifaddrmsg *ifa, struct nl_cb *callbacks) {
  struct nl_msg *msg = NULL;

  msg = nlmsg_alloc_ifaddr(type, flags, ifa);
  if(!msg)
    return;

  send_netlink_msg(msg, callbacks);

  nlmsg_free(msg);
}
Exemple #22
0
static int send_log_request(struct nl_sock *sk, struct nl_msg *msg)
{
	int err;

	err = nl_send_auto_complete(sk, msg);
	nlmsg_free(msg);
	if (err < 0)
		return err;

	return wait_for_ack(sk);
}
Exemple #23
0
int nf10_reg_rd(uint32_t addr, uint32_t *val_ptr)
{
    struct nl_msg   *msg;
    int             err;

    err = driver_connect();
    if(err)
        return err;

    msg = nlmsg_alloc();
    if(msg == NULL) {
        driver_disconnect();
        return -NLE_NOMEM;
    }

    /* genlmsg_put will fill in the fields of the nlmsghdr and the genlmsghdr. */
    genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, nf10_genl_family, 0, 0,
            NF10_GENL_C_REG_RD, NF10_GENL_FAMILY_VERSION);

    nla_put_u32(msg, NF10_GENL_A_ADDR32, addr);

    /* nl_send_auto will automatically fill in the PID and the sequence number,
     * and also add an NLM_F_REQUEST flag. It will also add an NLM_F_ACK
     * flag unless the netlink socket has the NL_NO_AUTO_ACK flag set. */
    err = nl_send_auto(nf10_genl_sock, msg);
    if(err < 0) {
        nlmsg_free(msg);
        driver_disconnect();
        return err;
    }

    nlmsg_free(msg);

    nl_socket_modify_cb(nf10_genl_sock, NL_CB_VALID, NL_CB_CUSTOM, nf10_reg_rd_recv_msg_cb, (void*)val_ptr);

    err = nl_recvmsgs_default(nf10_genl_sock);

    driver_disconnect();

    return err;
}
static int nl80211_create_iface_once(struct nl80211_data* ctx, int(*handler)(struct nl_msg *, void *), void *arg)
{
    int ret = -ENOBUFS;
    struct nl_msg *msg;
    struct nlattr *flags;
    int ifidx;
    const char *ifname = ctx->monitor_name;
    fprintf(stderr, "nl80211: Create monitor interface %s\n", ifname);

    msg = nl80211_cmd_msg(ctx, 0, NL80211_CMD_NEW_INTERFACE);
    if (!msg)
        goto fail;

    if (nla_put_string(msg, NL80211_ATTR_IFNAME, ifname))
        goto fail;
    
    if (nla_put_u32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_MONITOR))
        goto fail;

    flags = nla_nest_start(msg, NL80211_ATTR_MNTR_FLAGS);
    if (!flags)
        goto fail;

    if (nla_put_flag(msg, NL80211_MNTR_FLAG_COOK_FRAMES))
        goto fail;

    nla_nest_end(msg, flags);

    /*
    * Tell cfg80211 that the interface belongs to the socket that created
    * it, and the interface should be deleted when the socket is closed.
    */
    if (nla_put_flag(msg, NL80211_ATTR_IFACE_SOCKET_OWNER))
        goto fail;

    ret = send_and_recv_msgs(ctx, msg, handler, arg);
    msg = NULL;


    if (ret) {
    fail:
        nlmsg_free(msg);
        fprintf(stderr, "nl80211: Failed to create Monitor interface: %d (%s)\n", ret, strerror(-ret));
        return -1;
    }

    ifidx = if_nametoindex(ifname);
    fprintf(stderr, "nl80211: New interface %s created at ifindex=%d\n", ifname, ifidx);
    if (ifidx <= 0)
        return -1;

    return ifidx;
}
Exemple #25
0
int rtnl_tc_msg_build(struct rtnl_tc *tc, int type, int flags,
		      struct nl_msg **result)
{
	struct nl_msg *msg;
	struct rtnl_tc_ops *ops;
	struct tcmsg tchdr = {
		.tcm_family = AF_UNSPEC,
		.tcm_ifindex = tc->tc_ifindex,
		.tcm_handle = tc->tc_handle,
		.tcm_parent = tc->tc_parent,
	};
	int err = -NLE_MSGSIZE;

	msg = nlmsg_alloc_simple(type, flags);
	if (!msg)
		return -NLE_NOMEM;

	if (nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO) < 0)
		goto nla_put_failure;

	if (tc->ce_mask & TCA_ATTR_KIND)
	    NLA_PUT_STRING(msg, TCA_KIND, tc->tc_kind);

	ops = rtnl_tc_get_ops(tc);
	if (ops && (ops->to_msg_fill || ops->to_msg_fill_raw)) {
		struct nlattr *opts;
		void *data = rtnl_tc_data(tc);

		if (ops->to_msg_fill) {
			if (!(opts = nla_nest_start(msg, TCA_OPTIONS)))
				goto nla_put_failure;

			if ((err = ops->to_msg_fill(tc, data, msg)) < 0)
				goto nla_put_failure;

			nla_nest_end(msg, opts);
		} else if ((err = ops->to_msg_fill_raw(tc, data, msg)) < 0)
			goto nla_put_failure;
	}

	*result = msg;
	return 0;

nla_put_failure:
	nlmsg_free(msg);
	return err;
}

void tca_set_kind(struct rtnl_tc *t, const char *kind)
{
	strncpy(t->tc_kind, kind, sizeof(t->tc_kind) - 1);
	t->ce_mask |= TCA_ATTR_KIND;
}
Exemple #26
0
static int go_offchan_freq(struct nl80211_state *state, int devidx, int freq)
{
	struct nl_cb *cb;
	struct nl_cb *s_cb;
	struct nl_msg *msg;
	int err;

	msg = nlmsg_alloc();
	if (!msg) {
		fprintf(stderr, "failed to allocate netlink message\n");
		return 2;
	}

	cb = nl_cb_alloc(nl_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
	s_cb = nl_cb_alloc(nl_debug ? NL_CB_DEBUG : NL_CB_DEFAULT);
	if (!cb || !s_cb) {
		fprintf(stderr, "failed to allocate netlink callbacks\n");
		err = 2;
		goto out_free_msg;
	}

	genlmsg_put(msg, 0, 0, genl_family_get_id(state->nl80211), 0,
		    0,
		    NL80211_CMD_REMAIN_ON_CHANNEL, 0);

	NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, devidx);
	NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq);
	/* 5 seconds is the max allowed, values passed are in ms */
	NLA_PUT_U32(msg, NL80211_ATTR_DURATION, 60);

	nl_socket_set_cb(state->nl_sock, s_cb);

	err = nl_send_auto_complete(state->nl_sock, msg);
	if (err < 0)
		goto out;

	err = 1;

	nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
	nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
	nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);

	while (err > 0)
		nl_recvmsgs(state->nl_sock, cb);
 out:
	nl_cb_put(cb);
 out_free_msg:
	nlmsg_free(msg);
	return err;
 nla_put_failure:
	fprintf(stderr, "building message failed\n");
	return 2;
}
int ieee802154_llsec_getparams(struct sk_buff *skb, struct genl_info *info)
{
	struct sk_buff *msg;
	struct net_device *dev = NULL;
	int rc = -ENOBUFS;
	struct ieee802154_mlme_ops *ops;
	void *hdr;
	struct ieee802154_llsec_params params;

	pr_debug("%s\n", __func__);

	dev = ieee802154_nl_get_dev(info);
	if (!dev)
		return -ENODEV;

	ops = ieee802154_mlme_ops(dev);
	if (!ops->llsec) {
		rc = -EOPNOTSUPP;
		goto out_dev;
	}

	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
	if (!msg)
		goto out_dev;

	hdr = genlmsg_put(msg, 0, info->snd_seq, &nl802154_family, 0,
			  IEEE802154_LLSEC_GETPARAMS);
	if (!hdr)
		goto out_free;

	rc = ops->llsec->get_params(dev, &params);
	if (rc < 0)
		goto out_free;

	if (nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, dev->name) ||
	    nla_put_u32(msg, IEEE802154_ATTR_DEV_INDEX, dev->ifindex) ||
	    nla_put_u8(msg, IEEE802154_ATTR_LLSEC_ENABLED, params.enabled) ||
	    nla_put_u8(msg, IEEE802154_ATTR_LLSEC_SECLEVEL, params.out_level) ||
	    nla_put_u32(msg, IEEE802154_ATTR_LLSEC_FRAME_COUNTER,
			be32_to_cpu(params.frame_counter)) ||
	    ieee802154_llsec_fill_key_id(msg, &params.out_key))
		goto out_free;

	dev_put(dev);

	return ieee802154_nl_reply(msg, info);
out_free:
	nlmsg_free(msg);
out_dev:
	dev_put(dev);
	return rc;
}
	void lowpansocket::getAddress(struct ieee802154_addr *ret, const vinterface &iface)
	{
#if defined HAVE_LIBNL || HAVE_LIBNL3
#ifdef HAVE_LIBNL3
		struct nl_sock *nl = nl_socket_alloc();
#else
		struct nl_handle *nl = nl_handle_alloc();
#endif
		unsigned char *buf = NULL;
		struct sockaddr_nl nla;
		struct nlattr *attrs[IEEE802154_ATTR_MAX+1];
		struct genlmsghdr *ghdr;
		struct nlmsghdr *nlh;
		struct nl_msg *msg;
		int family;

		if (!nl)
		        return;

		genl_connect(nl);

		/* Build and send message */
		msg = nlmsg_alloc();
		family = genl_ctrl_resolve(nl, "802.15.4 MAC");
		genlmsg_put(msg, NL_AUTO_PID, NL_AUTO_SEQ, family, 0, NLM_F_ECHO, IEEE802154_LIST_IFACE, 1);
		nla_put_string(msg, IEEE802154_ATTR_DEV_NAME, iface.toString().c_str());
		nl_send_auto_complete(nl, msg);
		nlmsg_free(msg);

		/* Receive and parse answer */
		nl_recv(nl, &nla, &buf, NULL);
		nlh = (struct nlmsghdr*)buf;
		genlmsg_parse(nlh, 0, attrs, IEEE802154_ATTR_MAX, ieee802154_policy);
		ghdr = (genlmsghdr*)nlmsg_data(nlh);
		if (!attrs[IEEE802154_ATTR_SHORT_ADDR] || !attrs[IEEE802154_ATTR_SHORT_ADDR])
		        return;

		// We only handle short addresses right now
		ret->addr_type = IEEE802154_ADDR_SHORT;
		ret->pan_id = nla_get_u16(attrs[IEEE802154_ATTR_PAN_ID]);
		ret->short_addr = nla_get_u16(attrs[IEEE802154_ATTR_SHORT_ADDR]);

		free(buf);
		nl_close(nl);

#ifdef HAVE_LIBNL3
		nl_socket_free(nl);
#else
		nl_handle_destroy(nl);
#endif
#endif
	}
Exemple #29
0
TError TNlCgFilter::Create(const TNlLink &link) {
    TError error = TError::Success();
    struct nl_msg *msg;
    int ret;
	struct tcmsg tchdr;

    tchdr.tcm_family = AF_UNSPEC;
    tchdr.tcm_ifindex = link.GetIndex();
    tchdr.tcm_handle = Handle;
    tchdr.tcm_parent = Parent;
	tchdr.tcm_info = TC_H_MAKE(FilterPrio << 16, htons(ETH_P_ALL));

	msg = nlmsg_alloc_simple(RTM_NEWTFILTER, NLM_F_EXCL|NLM_F_CREATE);
	if (!msg)
        return TError(EError::Unknown, "Unable to add filter: no memory");

    ret = nlmsg_append(msg, &tchdr, sizeof(tchdr), NLMSG_ALIGNTO);
    if (ret < 0) {
        error = TError(EError::Unknown, std::string("Unable to add filter: ") + nl_geterror(ret));
		goto free_msg;
    }

    ret = nla_put(msg, TCA_KIND, strlen(FilterType) + 1, FilterType);
    if (ret < 0) {
        error = TError(EError::Unknown, std::string("Unable to add filter: ") + nl_geterror(ret));
		goto free_msg;
    }

    ret = nla_put(msg, TCA_OPTIONS, 0, NULL);
    if (ret < 0) {
        error = TError(EError::Unknown, std::string("Unable to add filter: ") + nl_geterror(ret));
		goto free_msg;
    }

    L() << "netlink " << link.GetDesc()
        << ": add tfilter id 0x" << std::hex << Handle
        << " parent 0x" << Parent << std::dec  << std::endl;

    ret = nl_send_sync(link.GetSock(), msg);
    if (ret)
        error = TError(EError::Unknown, std::string("Unable to add filter: ") + nl_geterror(ret));

    if (!Exists(link))
        error = TError(EError::Unknown, "BUG: created filter doesn't exist");

    return error;

free_msg:
    nlmsg_free(msg);

    return error;
}
Exemple #30
0
static int wl1251_nl_reg_read(struct sk_buff *skb, struct genl_info *info)
{
	struct wl1251 *wl;
	u32 addr, val;
	int ret = 0;
	struct sk_buff *msg;
	void *hdr;

	if (!info->attrs[WL1251_NL_ATTR_REG_ADDR])
		return -EINVAL;

	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
	if (!msg)
		return -ENOMEM;

	wl = ifname_to_wl1251(&init_net, info);
	if (wl == NULL) {
		wl1251_error("wl1251 not found");
		return -EINVAL;
	}

	addr = nla_get_u32(info->attrs[WL1251_NL_ATTR_REG_ADDR]);

	mutex_lock(&wl->mutex);
	val = wl1251_reg_read32(wl, addr);
	mutex_unlock(&wl->mutex);

	hdr = genlmsg_put(msg, info->snd_pid, info->snd_seq,
			  &wl1251_nl_family, 0, WL1251_NL_CMD_PHY_REG_READ);
	if (IS_ERR(hdr)) {
		ret = PTR_ERR(hdr);
		goto nla_put_failure;
	}

	NLA_PUT_STRING(msg, WL1251_NL_ATTR_IFNAME,
		       nla_data(info->attrs[WL1251_NL_ATTR_IFNAME]));

	NLA_PUT_U32(msg, WL1251_NL_ATTR_REG_VAL, val);

	ret = genlmsg_end(msg, hdr);
	if (ret < 0) {
		wl1251_error("%s() failed", __func__);
		goto nla_put_failure;
	}

	return genlmsg_reply(msg, info);

 nla_put_failure:
	nlmsg_free(msg);

	return ret;
}