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 2b9f74b0ffea..428c37a1f95c 100644 --- a/include/linux/socket.h +++ b/include/linux/socket.h | |||
@@ -298,6 +298,7 @@ struct ucred { | |||
298 | #define SOL_IUCV 277 | 298 | #define SOL_IUCV 277 |
299 | #define SOL_CAIF 278 | 299 | #define SOL_CAIF 278 |
300 | #define SOL_ALG 279 | 300 | #define SOL_ALG 279 |
301 | #define SOL_NFC 280 | ||
301 | 302 | ||
302 | /* IPX options */ | 303 | /* IPX options */ |
303 | #define IPX_TYPE 1 | 304 | #define IPX_TYPE 1 |
diff --git a/include/uapi/linux/nfc.h b/include/uapi/linux/nfc.h index 7969f46f1bb3..855630fe731d 100644 --- a/include/uapi/linux/nfc.h +++ b/include/uapi/linux/nfc.h | |||
@@ -220,4 +220,8 @@ struct sockaddr_nfc_llcp { | |||
220 | #define NFC_LLCP_DIRECTION_RX 0x00 | 220 | #define NFC_LLCP_DIRECTION_RX 0x00 |
221 | #define NFC_LLCP_DIRECTION_TX 0x01 | 221 | #define NFC_LLCP_DIRECTION_TX 0x01 |
222 | 222 | ||
223 | /* socket option names */ | ||
224 | #define NFC_LLCP_RW 0 | ||
225 | #define NFC_LLCP_MIUX 1 | ||
226 | |||
223 | #endif /*__LINUX_NFC_H */ | 227 | #endif /*__LINUX_NFC_H */ |
diff --git a/net/nfc/llcp/llcp.h b/net/nfc/llcp/llcp.h index 32cec81939e6..5f117adac2e5 100644 --- a/net/nfc/llcp/llcp.h +++ b/net/nfc/llcp/llcp.h | |||
@@ -104,6 +104,9 @@ struct nfc_llcp_sock { | |||
104 | u8 dsap; | 104 | u8 dsap; |
105 | char *service_name; | 105 | char *service_name; |
106 | size_t service_name_len; | 106 | size_t service_name_len; |
107 | u8 rw; | ||
108 | u16 miux; | ||
109 | |||
107 | 110 | ||
108 | /* Remote link parameters */ | 111 | /* Remote link parameters */ |
109 | u8 remote_rw; | 112 | u8 remote_rw; |
diff --git a/net/nfc/llcp/sock.c b/net/nfc/llcp/sock.c index cc564992ba95..9357a756f7a9 100644 --- a/net/nfc/llcp/sock.c +++ b/net/nfc/llcp/sock.c | |||
@@ -223,6 +223,121 @@ error: | |||
223 | return ret; | 223 | return ret; |
224 | } | 224 | } |
225 | 225 | ||
226 | static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname, | ||
227 | char __user *optval, unsigned int optlen) | ||
228 | { | ||
229 | struct sock *sk = sock->sk; | ||
230 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | ||
231 | u32 opt; | ||
232 | int err = 0; | ||
233 | |||
234 | pr_debug("%p optname %d\n", sk, optname); | ||
235 | |||
236 | if (level != SOL_NFC) | ||
237 | return -ENOPROTOOPT; | ||
238 | |||
239 | lock_sock(sk); | ||
240 | |||
241 | switch (optname) { | ||
242 | case NFC_LLCP_RW: | ||
243 | if (sk->sk_state == LLCP_CONNECTED || | ||
244 | sk->sk_state == LLCP_BOUND || | ||
245 | sk->sk_state == LLCP_LISTEN) { | ||
246 | err = -EINVAL; | ||
247 | break; | ||
248 | } | ||
249 | |||
250 | if (get_user(opt, (u32 __user *) optval)) { | ||
251 | err = -EFAULT; | ||
252 | break; | ||
253 | } | ||
254 | |||
255 | if (opt > LLCP_MAX_RW) { | ||
256 | err = -EINVAL; | ||
257 | break; | ||
258 | } | ||
259 | |||
260 | llcp_sock->rw = (u8) opt; | ||
261 | |||
262 | break; | ||
263 | |||
264 | case NFC_LLCP_MIUX: | ||
265 | if (sk->sk_state == LLCP_CONNECTED || | ||
266 | sk->sk_state == LLCP_BOUND || | ||
267 | sk->sk_state == LLCP_LISTEN) { | ||
268 | err = -EINVAL; | ||
269 | break; | ||
270 | } | ||
271 | |||
272 | if (get_user(opt, (u32 __user *) optval)) { | ||
273 | err = -EFAULT; | ||
274 | break; | ||
275 | } | ||
276 | |||
277 | if (opt > LLCP_MAX_MIUX) { | ||
278 | err = -EINVAL; | ||
279 | break; | ||
280 | } | ||
281 | |||
282 | llcp_sock->miux = (u16) opt; | ||
283 | |||
284 | break; | ||
285 | |||
286 | default: | ||
287 | err = -ENOPROTOOPT; | ||
288 | break; | ||
289 | } | ||
290 | |||
291 | release_sock(sk); | ||
292 | |||
293 | return err; | ||
294 | } | ||
295 | |||
296 | static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname, | ||
297 | char __user *optval, int __user *optlen) | ||
298 | { | ||
299 | struct sock *sk = sock->sk; | ||
300 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | ||
301 | int len, err = 0; | ||
302 | |||
303 | pr_debug("%p optname %d\n", sk, optname); | ||
304 | |||
305 | if (level != SOL_NFC) | ||
306 | return -ENOPROTOOPT; | ||
307 | |||
308 | if (get_user(len, optlen)) | ||
309 | return -EFAULT; | ||
310 | |||
311 | len = min_t(u32, len, sizeof(u32)); | ||
312 | |||
313 | lock_sock(sk); | ||
314 | |||
315 | switch (optname) { | ||
316 | case NFC_LLCP_RW: | ||
317 | if (put_user(llcp_sock->rw, (u32 __user *) optval)) | ||
318 | err = -EFAULT; | ||
319 | |||
320 | break; | ||
321 | |||
322 | case NFC_LLCP_MIUX: | ||
323 | if (put_user(llcp_sock->miux, (u32 __user *) optval)) | ||
324 | err = -EFAULT; | ||
325 | |||
326 | break; | ||
327 | |||
328 | default: | ||
329 | err = -ENOPROTOOPT; | ||
330 | break; | ||
331 | } | ||
332 | |||
333 | release_sock(sk); | ||
334 | |||
335 | if (put_user(len, optlen)) | ||
336 | return -EFAULT; | ||
337 | |||
338 | return err; | ||
339 | } | ||
340 | |||
226 | void nfc_llcp_accept_unlink(struct sock *sk) | 341 | void nfc_llcp_accept_unlink(struct sock *sk) |
227 | { | 342 | { |
228 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); | 343 | struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk); |
@@ -735,8 +850,8 @@ static const struct proto_ops llcp_sock_ops = { | |||
735 | .ioctl = sock_no_ioctl, | 850 | .ioctl = sock_no_ioctl, |
736 | .listen = llcp_sock_listen, | 851 | .listen = llcp_sock_listen, |
737 | .shutdown = sock_no_shutdown, | 852 | .shutdown = sock_no_shutdown, |
738 | .setsockopt = sock_no_setsockopt, | 853 | .setsockopt = nfc_llcp_setsockopt, |
739 | .getsockopt = sock_no_getsockopt, | 854 | .getsockopt = nfc_llcp_getsockopt, |
740 | .sendmsg = llcp_sock_sendmsg, | 855 | .sendmsg = llcp_sock_sendmsg, |
741 | .recvmsg = llcp_sock_recvmsg, | 856 | .recvmsg = llcp_sock_recvmsg, |
742 | .mmap = sock_no_mmap, | 857 | .mmap = sock_no_mmap, |