diff options
Diffstat (limited to 'net/nfc/netlink.c')
| -rw-r--r-- | net/nfc/netlink.c | 183 | 
1 files changed, 182 insertions, 1 deletions
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c index f0c4d61f37c0..f16fd59d4160 100644 --- a/net/nfc/netlink.c +++ b/net/nfc/netlink.c @@ -56,6 +56,8 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {  	[NFC_ATTR_LLC_PARAM_RW] = { .type = NLA_U8 },  	[NFC_ATTR_LLC_PARAM_MIUX] = { .type = NLA_U16 },  	[NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED }, +	[NFC_ATTR_FIRMWARE_NAME] = { .type = NLA_STRING, +				     .len = NFC_FIRMWARE_NAME_MAXSIZE },  };  static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = { @@ -424,6 +426,69 @@ free_msg:  	return rc;  } +int nfc_genl_se_added(struct nfc_dev *dev, u32 se_idx, u16 type) +{ +	struct sk_buff *msg; +	void *hdr; + +	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); +	if (!msg) +		return -ENOMEM; + +	hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, +			  NFC_EVENT_SE_ADDED); +	if (!hdr) +		goto free_msg; + +	if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) || +	    nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx) || +	    nla_put_u8(msg, NFC_ATTR_SE_TYPE, type)) +		goto nla_put_failure; + +	genlmsg_end(msg, hdr); + +	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + +	return 0; + +nla_put_failure: +	genlmsg_cancel(msg, hdr); +free_msg: +	nlmsg_free(msg); +	return -EMSGSIZE; +} + +int nfc_genl_se_removed(struct nfc_dev *dev, u32 se_idx) +{ +	struct sk_buff *msg; +	void *hdr; + +	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); +	if (!msg) +		return -ENOMEM; + +	hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, +			  NFC_EVENT_SE_REMOVED); +	if (!hdr) +		goto free_msg; + +	if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) || +	    nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx)) +		goto nla_put_failure; + +	genlmsg_end(msg, hdr); + +	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + +	return 0; + +nla_put_failure: +	genlmsg_cancel(msg, hdr); +free_msg: +	nlmsg_free(msg); +	return -EMSGSIZE; +} +  static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,  				u32 portid, u32 seq,  				struct netlink_callback *cb, @@ -442,7 +507,6 @@ static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,  	if (nla_put_string(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev)) ||  	    nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||  	    nla_put_u32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols) || -	    nla_put_u32(msg, NFC_ATTR_SE, dev->supported_se) ||  	    nla_put_u8(msg, NFC_ATTR_DEVICE_POWERED, dev->dev_up) ||  	    nla_put_u8(msg, NFC_ATTR_RF_MODE, dev->rf_mode))  		goto nla_put_failure; @@ -1025,6 +1089,108 @@ exit:  	return rc;  } +static int nfc_genl_fw_download(struct sk_buff *skb, struct genl_info *info) +{ +	struct nfc_dev *dev; +	int rc; +	u32 idx; +	char firmware_name[NFC_FIRMWARE_NAME_MAXSIZE + 1]; + +	if (!info->attrs[NFC_ATTR_DEVICE_INDEX]) +		return -EINVAL; + +	idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); + +	dev = nfc_get_device(idx); +	if (!dev) +		return -ENODEV; + +	nla_strlcpy(firmware_name, info->attrs[NFC_ATTR_FIRMWARE_NAME], +		    sizeof(firmware_name)); + +	rc = nfc_fw_download(dev, firmware_name); + +	nfc_put_device(dev); +	return rc; +} + +int nfc_genl_fw_download_done(struct nfc_dev *dev, const char *firmware_name) +{ +	struct sk_buff *msg; +	void *hdr; + +	msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); +	if (!msg) +		return -ENOMEM; + +	hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0, +			  NFC_CMD_FW_DOWNLOAD); +	if (!hdr) +		goto free_msg; + +	if (nla_put_string(msg, NFC_ATTR_FIRMWARE_NAME, firmware_name) || +	    nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx)) +		goto nla_put_failure; + +	genlmsg_end(msg, hdr); + +	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL); + +	return 0; + +nla_put_failure: +	genlmsg_cancel(msg, hdr); +free_msg: +	nlmsg_free(msg); +	return -EMSGSIZE; +} + +static int nfc_genl_enable_se(struct sk_buff *skb, struct genl_info *info) +{ +	struct nfc_dev *dev; +	int rc; +	u32 idx, se_idx; + +	if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || +	    !info->attrs[NFC_ATTR_SE_INDEX]) +		return -EINVAL; + +	idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); +	se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]); + +	dev = nfc_get_device(idx); +	if (!dev) +		return -ENODEV; + +	rc = nfc_enable_se(dev, se_idx); + +	nfc_put_device(dev); +	return rc; +} + +static int nfc_genl_disable_se(struct sk_buff *skb, struct genl_info *info) +{ +	struct nfc_dev *dev; +	int rc; +	u32 idx, se_idx; + +	if (!info->attrs[NFC_ATTR_DEVICE_INDEX] || +	    !info->attrs[NFC_ATTR_SE_INDEX]) +		return -EINVAL; + +	idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]); +	se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]); + +	dev = nfc_get_device(idx); +	if (!dev) +		return -ENODEV; + +	rc = nfc_disable_se(dev, se_idx); + +	nfc_put_device(dev); +	return rc; +} +  static struct genl_ops nfc_genl_ops[] = {  	{  		.cmd = NFC_CMD_GET_DEVICE, @@ -1084,6 +1250,21 @@ static struct genl_ops nfc_genl_ops[] = {  		.doit = nfc_genl_llc_sdreq,  		.policy = nfc_genl_policy,  	}, +	{ +		.cmd = NFC_CMD_FW_DOWNLOAD, +		.doit = nfc_genl_fw_download, +		.policy = nfc_genl_policy, +	}, +	{ +		.cmd = NFC_CMD_ENABLE_SE, +		.doit = nfc_genl_enable_se, +		.policy = nfc_genl_policy, +	}, +	{ +		.cmd = NFC_CMD_DISABLE_SE, +		.doit = nfc_genl_disable_se, +		.policy = nfc_genl_policy, +	},  };  | 
