diff options
Diffstat (limited to 'net/ieee802154/dgram.c')
-rw-r--r-- | net/ieee802154/dgram.c | 78 |
1 files changed, 65 insertions, 13 deletions
diff --git a/net/ieee802154/dgram.c b/net/ieee802154/dgram.c index ba8b214dda8f..77ae6852b93d 100644 --- a/net/ieee802154/dgram.c +++ b/net/ieee802154/dgram.c | |||
@@ -26,9 +26,9 @@ | |||
26 | #include <linux/if_arp.h> | 26 | #include <linux/if_arp.h> |
27 | #include <linux/list.h> | 27 | #include <linux/list.h> |
28 | #include <net/sock.h> | 28 | #include <net/sock.h> |
29 | #include <net/ieee802154/af_ieee802154.h> | 29 | #include <net/af_ieee802154.h> |
30 | #include <net/ieee802154/mac_def.h> | 30 | #include <net/ieee802154.h> |
31 | #include <net/ieee802154/netdevice.h> | 31 | #include <net/ieee802154_netdev.h> |
32 | 32 | ||
33 | #include <asm/ioctls.h> | 33 | #include <asm/ioctls.h> |
34 | 34 | ||
@@ -40,9 +40,11 @@ static DEFINE_RWLOCK(dgram_lock); | |||
40 | struct dgram_sock { | 40 | struct dgram_sock { |
41 | struct sock sk; | 41 | struct sock sk; |
42 | 42 | ||
43 | int bound; | ||
44 | struct ieee802154_addr src_addr; | 43 | struct ieee802154_addr src_addr; |
45 | struct ieee802154_addr dst_addr; | 44 | struct ieee802154_addr dst_addr; |
45 | |||
46 | unsigned bound:1; | ||
47 | unsigned want_ack:1; | ||
46 | }; | 48 | }; |
47 | 49 | ||
48 | static inline struct dgram_sock *dgram_sk(const struct sock *sk) | 50 | static inline struct dgram_sock *dgram_sk(const struct sock *sk) |
@@ -50,7 +52,6 @@ static inline struct dgram_sock *dgram_sk(const struct sock *sk) | |||
50 | return container_of(sk, struct dgram_sock, sk); | 52 | return container_of(sk, struct dgram_sock, sk); |
51 | } | 53 | } |
52 | 54 | ||
53 | |||
54 | static void dgram_hash(struct sock *sk) | 55 | static void dgram_hash(struct sock *sk) |
55 | { | 56 | { |
56 | write_lock_bh(&dgram_lock); | 57 | write_lock_bh(&dgram_lock); |
@@ -73,6 +74,7 @@ static int dgram_init(struct sock *sk) | |||
73 | 74 | ||
74 | ro->dst_addr.addr_type = IEEE802154_ADDR_LONG; | 75 | ro->dst_addr.addr_type = IEEE802154_ADDR_LONG; |
75 | ro->dst_addr.pan_id = 0xffff; | 76 | ro->dst_addr.pan_id = 0xffff; |
77 | ro->want_ack = 1; | ||
76 | memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr)); | 78 | memset(&ro->dst_addr.hwaddr, 0xff, sizeof(ro->dst_addr.hwaddr)); |
77 | return 0; | 79 | return 0; |
78 | } | 80 | } |
@@ -86,18 +88,18 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) | |||
86 | { | 88 | { |
87 | struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; | 89 | struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; |
88 | struct dgram_sock *ro = dgram_sk(sk); | 90 | struct dgram_sock *ro = dgram_sk(sk); |
89 | int err = 0; | 91 | int err = -EINVAL; |
90 | struct net_device *dev; | 92 | struct net_device *dev; |
91 | 93 | ||
94 | lock_sock(sk); | ||
95 | |||
92 | ro->bound = 0; | 96 | ro->bound = 0; |
93 | 97 | ||
94 | if (len < sizeof(*addr)) | 98 | if (len < sizeof(*addr)) |
95 | return -EINVAL; | 99 | goto out; |
96 | 100 | ||
97 | if (addr->family != AF_IEEE802154) | 101 | if (addr->family != AF_IEEE802154) |
98 | return -EINVAL; | 102 | goto out; |
99 | |||
100 | lock_sock(sk); | ||
101 | 103 | ||
102 | dev = ieee802154_get_dev(sock_net(sk), &addr->addr); | 104 | dev = ieee802154_get_dev(sock_net(sk), &addr->addr); |
103 | if (!dev) { | 105 | if (!dev) { |
@@ -113,6 +115,7 @@ static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) | |||
113 | memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr)); | 115 | memcpy(&ro->src_addr, &addr->addr, sizeof(struct ieee802154_addr)); |
114 | 116 | ||
115 | ro->bound = 1; | 117 | ro->bound = 1; |
118 | err = 0; | ||
116 | out_put: | 119 | out_put: |
117 | dev_put(dev); | 120 | dev_put(dev); |
118 | out: | 121 | out: |
@@ -235,7 +238,10 @@ static int dgram_sendmsg(struct kiocb *iocb, struct sock *sk, | |||
235 | 238 | ||
236 | skb_reset_network_header(skb); | 239 | skb_reset_network_header(skb); |
237 | 240 | ||
238 | mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA | MAC_CB_FLAG_ACKREQ; | 241 | mac_cb(skb)->flags = IEEE802154_FC_TYPE_DATA; |
242 | if (ro->want_ack) | ||
243 | mac_cb(skb)->flags |= MAC_CB_FLAG_ACKREQ; | ||
244 | |||
239 | mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev); | 245 | mac_cb(skb)->seq = ieee802154_mlme_ops(dev)->get_dsn(dev); |
240 | err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &ro->dst_addr, | 246 | err = dev_hard_header(skb, dev, ETH_P_IEEE802154, &ro->dst_addr, |
241 | ro->bound ? &ro->src_addr : NULL, size); | 247 | ro->bound ? &ro->src_addr : NULL, size); |
@@ -380,13 +386,59 @@ int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) | |||
380 | static int dgram_getsockopt(struct sock *sk, int level, int optname, | 386 | static int dgram_getsockopt(struct sock *sk, int level, int optname, |
381 | char __user *optval, int __user *optlen) | 387 | char __user *optval, int __user *optlen) |
382 | { | 388 | { |
383 | return -EOPNOTSUPP; | 389 | struct dgram_sock *ro = dgram_sk(sk); |
390 | |||
391 | int val, len; | ||
392 | |||
393 | if (level != SOL_IEEE802154) | ||
394 | return -EOPNOTSUPP; | ||
395 | |||
396 | if (get_user(len, optlen)) | ||
397 | return -EFAULT; | ||
398 | |||
399 | len = min_t(unsigned int, len, sizeof(int)); | ||
400 | |||
401 | switch (optname) { | ||
402 | case WPAN_WANTACK: | ||
403 | val = ro->want_ack; | ||
404 | break; | ||
405 | default: | ||
406 | return -ENOPROTOOPT; | ||
407 | } | ||
408 | |||
409 | if (put_user(len, optlen)) | ||
410 | return -EFAULT; | ||
411 | if (copy_to_user(optval, &val, len)) | ||
412 | return -EFAULT; | ||
413 | return 0; | ||
384 | } | 414 | } |
385 | 415 | ||
386 | static int dgram_setsockopt(struct sock *sk, int level, int optname, | 416 | static int dgram_setsockopt(struct sock *sk, int level, int optname, |
387 | char __user *optval, int __user optlen) | 417 | char __user *optval, int __user optlen) |
388 | { | 418 | { |
389 | return -EOPNOTSUPP; | 419 | struct dgram_sock *ro = dgram_sk(sk); |
420 | int val; | ||
421 | int err = 0; | ||
422 | |||
423 | if (optlen < sizeof(int)) | ||
424 | return -EINVAL; | ||
425 | |||
426 | if (get_user(val, (int __user *)optval)) | ||
427 | return -EFAULT; | ||
428 | |||
429 | lock_sock(sk); | ||
430 | |||
431 | switch (optname) { | ||
432 | case WPAN_WANTACK: | ||
433 | ro->want_ack = !!val; | ||
434 | break; | ||
435 | default: | ||
436 | err = -ENOPROTOOPT; | ||
437 | break; | ||
438 | } | ||
439 | |||
440 | release_sock(sk); | ||
441 | return err; | ||
390 | } | 442 | } |
391 | 443 | ||
392 | struct proto ieee802154_dgram_prot = { | 444 | struct proto ieee802154_dgram_prot = { |