diff options
| -rw-r--r-- | include/linux/socket.h | 1 | ||||
| -rw-r--r-- | include/uapi/linux/nfc.h | 4 | ||||
| -rw-r--r-- | net/nfc/llcp/llcp.h | 3 | ||||
| -rw-r--r-- | net/nfc/llcp/sock.c | 119 | 
4 files changed, 125 insertions, 2 deletions
diff --git a/include/linux/socket.h b/include/linux/socket.h index 2b9f74b0ffe..428c37a1f95 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h @@ -298,6 +298,7 @@ struct ucred {  #define SOL_IUCV	277  #define SOL_CAIF	278  #define SOL_ALG		279 +#define SOL_NFC		280  /* IPX options */  #define IPX_TYPE	1 diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h index 7969f46f1bb..855630fe731 100644 --- a/include/uapi/linux/nfc.h +++ b/include/uapi/linux/nfc.h @@ -220,4 +220,8 @@ struct sockaddr_nfc_llcp {  #define NFC_LLCP_DIRECTION_RX		0x00  #define NFC_LLCP_DIRECTION_TX		0x01 +/* socket option names */ +#define NFC_LLCP_RW   0 +#define NFC_LLCP_MIUX 1 +  #endif /*__LINUX_NFC_H */ diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 32cec81939e..5f117adac2e 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h @@ -104,6 +104,9 @@ struct nfc_llcp_sock {  	u8 dsap;  	char *service_name;  	size_t service_name_len; +	u8 rw; +	u16 miux; +  	/* Remote link parameters */  	u8 remote_rw; diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index cc564992ba9..9357a756f7a 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c @@ -223,6 +223,121 @@ error:  	return ret;  } +static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname, +			       char __user *optval, unsigned int optlen) +{ +	struct sock *sk = sock->sk; +	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); +	u32 opt; +	int err = 0; + +	pr_debug("%p optname %d\n", sk, optname); + +	if (level != SOL_NFC) +		return -ENOPROTOOPT; + +	lock_sock(sk); + +	switch (optname) { +	case NFC_LLCP_RW: +		if (sk->sk_state == LLCP_CONNECTED || +		    sk->sk_state == LLCP_BOUND || +		    sk->sk_state == LLCP_LISTEN) { +			err = -EINVAL; +			break; +		} + +		if (get_user(opt, (u32 __user *) optval)) { +			err = -EFAULT; +			break; +		} + +		if (opt > LLCP_MAX_RW) { +			err = -EINVAL; +			break; +		} + +		llcp_sock->rw = (u8) opt; + +		break; + +	case NFC_LLCP_MIUX: +		if (sk->sk_state == LLCP_CONNECTED || +		    sk->sk_state == LLCP_BOUND || +		    sk->sk_state == LLCP_LISTEN) { +			err = -EINVAL; +			break; +		} + +		if (get_user(opt, (u32 __user *) optval)) { +			err = -EFAULT; +			break; +		} + +		if (opt > LLCP_MAX_MIUX) { +			err = -EINVAL; +			break; +		} + +		llcp_sock->miux = (u16) opt; + +		break; + +	default: +		err = -ENOPROTOOPT; +		break; +	} + +	release_sock(sk); + +	return err; +} + +static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname, +			       char __user *optval, int __user *optlen) +{ +	struct sock *sk = sock->sk; +	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); +	int len, err = 0; + +	pr_debug("%p optname %d\n", sk, optname); + +	if (level != SOL_NFC) +		return -ENOPROTOOPT; + +	if (get_user(len, optlen)) +		return -EFAULT; + +	len = min_t(u32, len, sizeof(u32)); + +	lock_sock(sk); + +	switch (optname) { +	case NFC_LLCP_RW: +		if (put_user(llcp_sock->rw, (u32 __user *) optval)) +			err = -EFAULT; + +		break; + +	case NFC_LLCP_MIUX: +		if (put_user(llcp_sock->miux, (u32 __user *) optval)) +			err = -EFAULT; + +		break; + +	default: +		err = -ENOPROTOOPT; +		break; +	} + +	release_sock(sk); + +	if (put_user(len, optlen)) +		return -EFAULT; + +	return err; +} +  void nfc_llcp_accept_unlink(struct sock *sk)  {  	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); @@ -735,8 +850,8 @@ static const struct proto_ops llcp_sock_ops = {  	.ioctl          = sock_no_ioctl,  	.listen         = llcp_sock_listen,  	.shutdown       = sock_no_shutdown, -	.setsockopt     = sock_no_setsockopt, -	.getsockopt     = sock_no_getsockopt, +	.setsockopt     = nfc_llcp_setsockopt, +	.getsockopt     = nfc_llcp_getsockopt,  	.sendmsg        = llcp_sock_sendmsg,  	.recvmsg        = llcp_sock_recvmsg,  	.mmap           = sock_no_mmap,  |