xref: /openbmc/linux/net/ieee802154/socket.c (revision 086c653f)
171e36b1bSAlexander Aring /*
271e36b1bSAlexander Aring  * IEEE802154.4 socket interface
371e36b1bSAlexander Aring  *
471e36b1bSAlexander Aring  * Copyright 2007, 2008 Siemens AG
571e36b1bSAlexander Aring  *
671e36b1bSAlexander Aring  * This program is free software; you can redistribute it and/or modify
771e36b1bSAlexander Aring  * it under the terms of the GNU General Public License version 2
871e36b1bSAlexander Aring  * as published by the Free Software Foundation.
971e36b1bSAlexander Aring  *
1071e36b1bSAlexander Aring  * This program is distributed in the hope that it will be useful,
1171e36b1bSAlexander Aring  * but WITHOUT ANY WARRANTY; without even the implied warranty of
1271e36b1bSAlexander Aring  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1371e36b1bSAlexander Aring  * GNU General Public License for more details.
1471e36b1bSAlexander Aring  *
1571e36b1bSAlexander Aring  * Written by:
1671e36b1bSAlexander Aring  * Sergey Lapin <slapin@ossfans.org>
1771e36b1bSAlexander Aring  * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
1871e36b1bSAlexander Aring  */
1971e36b1bSAlexander Aring 
2071e36b1bSAlexander Aring #include <linux/net.h>
2171e36b1bSAlexander Aring #include <linux/capability.h>
2271e36b1bSAlexander Aring #include <linux/module.h>
2371e36b1bSAlexander Aring #include <linux/if_arp.h>
2471e36b1bSAlexander Aring #include <linux/if.h>
2571e36b1bSAlexander Aring #include <linux/termios.h>	/* For TIOCOUTQ/INQ */
2671e36b1bSAlexander Aring #include <linux/list.h>
2771e36b1bSAlexander Aring #include <linux/slab.h>
2871e36b1bSAlexander Aring #include <net/datalink.h>
2971e36b1bSAlexander Aring #include <net/psnap.h>
3071e36b1bSAlexander Aring #include <net/sock.h>
3171e36b1bSAlexander Aring #include <net/tcp_states.h>
3271e36b1bSAlexander Aring #include <net/route.h>
3371e36b1bSAlexander Aring 
3471e36b1bSAlexander Aring #include <net/af_ieee802154.h>
3571e36b1bSAlexander Aring #include <net/ieee802154_netdev.h>
3671e36b1bSAlexander Aring 
3771e36b1bSAlexander Aring /* Utility function for families */
3871e36b1bSAlexander Aring static struct net_device*
3971e36b1bSAlexander Aring ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr)
4071e36b1bSAlexander Aring {
4171e36b1bSAlexander Aring 	struct net_device *dev = NULL;
4271e36b1bSAlexander Aring 	struct net_device *tmp;
4371e36b1bSAlexander Aring 	__le16 pan_id, short_addr;
4471e36b1bSAlexander Aring 	u8 hwaddr[IEEE802154_ADDR_LEN];
4571e36b1bSAlexander Aring 
4671e36b1bSAlexander Aring 	switch (addr->mode) {
4771e36b1bSAlexander Aring 	case IEEE802154_ADDR_LONG:
4871e36b1bSAlexander Aring 		ieee802154_devaddr_to_raw(hwaddr, addr->extended_addr);
4971e36b1bSAlexander Aring 		rcu_read_lock();
5071e36b1bSAlexander Aring 		dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, hwaddr);
5171e36b1bSAlexander Aring 		if (dev)
5271e36b1bSAlexander Aring 			dev_hold(dev);
5371e36b1bSAlexander Aring 		rcu_read_unlock();
5471e36b1bSAlexander Aring 		break;
5571e36b1bSAlexander Aring 	case IEEE802154_ADDR_SHORT:
5671e36b1bSAlexander Aring 		if (addr->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST) ||
5771e36b1bSAlexander Aring 		    addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
5871e36b1bSAlexander Aring 		    addr->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST))
5971e36b1bSAlexander Aring 			break;
6071e36b1bSAlexander Aring 
6171e36b1bSAlexander Aring 		rtnl_lock();
6271e36b1bSAlexander Aring 
6371e36b1bSAlexander Aring 		for_each_netdev(net, tmp) {
6471e36b1bSAlexander Aring 			if (tmp->type != ARPHRD_IEEE802154)
6571e36b1bSAlexander Aring 				continue;
6671e36b1bSAlexander Aring 
67c947f7e1SAlexander Aring 			pan_id = tmp->ieee802154_ptr->pan_id;
68c947f7e1SAlexander Aring 			short_addr = tmp->ieee802154_ptr->short_addr;
6971e36b1bSAlexander Aring 			if (pan_id == addr->pan_id &&
7071e36b1bSAlexander Aring 			    short_addr == addr->short_addr) {
7171e36b1bSAlexander Aring 				dev = tmp;
7271e36b1bSAlexander Aring 				dev_hold(dev);
7371e36b1bSAlexander Aring 				break;
7471e36b1bSAlexander Aring 			}
7571e36b1bSAlexander Aring 		}
7671e36b1bSAlexander Aring 
7771e36b1bSAlexander Aring 		rtnl_unlock();
7871e36b1bSAlexander Aring 		break;
7971e36b1bSAlexander Aring 	default:
8071e36b1bSAlexander Aring 		pr_warn("Unsupported ieee802154 address type: %d\n",
8171e36b1bSAlexander Aring 			addr->mode);
8271e36b1bSAlexander Aring 		break;
8371e36b1bSAlexander Aring 	}
8471e36b1bSAlexander Aring 
8571e36b1bSAlexander Aring 	return dev;
8671e36b1bSAlexander Aring }
8771e36b1bSAlexander Aring 
8871e36b1bSAlexander Aring static int ieee802154_sock_release(struct socket *sock)
8971e36b1bSAlexander Aring {
9071e36b1bSAlexander Aring 	struct sock *sk = sock->sk;
9171e36b1bSAlexander Aring 
9271e36b1bSAlexander Aring 	if (sk) {
9371e36b1bSAlexander Aring 		sock->sk = NULL;
9471e36b1bSAlexander Aring 		sk->sk_prot->close(sk, 0);
9571e36b1bSAlexander Aring 	}
9671e36b1bSAlexander Aring 	return 0;
9771e36b1bSAlexander Aring }
9871e36b1bSAlexander Aring 
991b784140SYing Xue static int ieee802154_sock_sendmsg(struct socket *sock, struct msghdr *msg,
1001b784140SYing Xue 				   size_t len)
10171e36b1bSAlexander Aring {
10271e36b1bSAlexander Aring 	struct sock *sk = sock->sk;
10371e36b1bSAlexander Aring 
1041b784140SYing Xue 	return sk->sk_prot->sendmsg(sk, msg, len);
10571e36b1bSAlexander Aring }
10671e36b1bSAlexander Aring 
10771e36b1bSAlexander Aring static int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr,
10871e36b1bSAlexander Aring 				int addr_len)
10971e36b1bSAlexander Aring {
11071e36b1bSAlexander Aring 	struct sock *sk = sock->sk;
11171e36b1bSAlexander Aring 
11271e36b1bSAlexander Aring 	if (sk->sk_prot->bind)
11371e36b1bSAlexander Aring 		return sk->sk_prot->bind(sk, uaddr, addr_len);
11471e36b1bSAlexander Aring 
11571e36b1bSAlexander Aring 	return sock_no_bind(sock, uaddr, addr_len);
11671e36b1bSAlexander Aring }
11771e36b1bSAlexander Aring 
11871e36b1bSAlexander Aring static int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr,
11971e36b1bSAlexander Aring 				   int addr_len, int flags)
12071e36b1bSAlexander Aring {
12171e36b1bSAlexander Aring 	struct sock *sk = sock->sk;
12271e36b1bSAlexander Aring 
12371e36b1bSAlexander Aring 	if (addr_len < sizeof(uaddr->sa_family))
12471e36b1bSAlexander Aring 		return -EINVAL;
12571e36b1bSAlexander Aring 
12671e36b1bSAlexander Aring 	if (uaddr->sa_family == AF_UNSPEC)
12771e36b1bSAlexander Aring 		return sk->sk_prot->disconnect(sk, flags);
12871e36b1bSAlexander Aring 
12971e36b1bSAlexander Aring 	return sk->sk_prot->connect(sk, uaddr, addr_len);
13071e36b1bSAlexander Aring }
13171e36b1bSAlexander Aring 
13271e36b1bSAlexander Aring static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg,
13371e36b1bSAlexander Aring 				unsigned int cmd)
13471e36b1bSAlexander Aring {
13571e36b1bSAlexander Aring 	struct ifreq ifr;
13671e36b1bSAlexander Aring 	int ret = -ENOIOCTLCMD;
13771e36b1bSAlexander Aring 	struct net_device *dev;
13871e36b1bSAlexander Aring 
13971e36b1bSAlexander Aring 	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
14071e36b1bSAlexander Aring 		return -EFAULT;
14171e36b1bSAlexander Aring 
14271e36b1bSAlexander Aring 	ifr.ifr_name[IFNAMSIZ-1] = 0;
14371e36b1bSAlexander Aring 
14471e36b1bSAlexander Aring 	dev_load(sock_net(sk), ifr.ifr_name);
14571e36b1bSAlexander Aring 	dev = dev_get_by_name(sock_net(sk), ifr.ifr_name);
14671e36b1bSAlexander Aring 
14771e36b1bSAlexander Aring 	if (!dev)
14871e36b1bSAlexander Aring 		return -ENODEV;
14971e36b1bSAlexander Aring 
15071e36b1bSAlexander Aring 	if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl)
15171e36b1bSAlexander Aring 		ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd);
15271e36b1bSAlexander Aring 
15371e36b1bSAlexander Aring 	if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
15471e36b1bSAlexander Aring 		ret = -EFAULT;
15571e36b1bSAlexander Aring 	dev_put(dev);
15671e36b1bSAlexander Aring 
15771e36b1bSAlexander Aring 	return ret;
15871e36b1bSAlexander Aring }
15971e36b1bSAlexander Aring 
16071e36b1bSAlexander Aring static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd,
16171e36b1bSAlexander Aring 				 unsigned long arg)
16271e36b1bSAlexander Aring {
16371e36b1bSAlexander Aring 	struct sock *sk = sock->sk;
16471e36b1bSAlexander Aring 
16571e36b1bSAlexander Aring 	switch (cmd) {
16671e36b1bSAlexander Aring 	case SIOCGSTAMP:
16771e36b1bSAlexander Aring 		return sock_get_timestamp(sk, (struct timeval __user *)arg);
16871e36b1bSAlexander Aring 	case SIOCGSTAMPNS:
16971e36b1bSAlexander Aring 		return sock_get_timestampns(sk, (struct timespec __user *)arg);
17071e36b1bSAlexander Aring 	case SIOCGIFADDR:
17171e36b1bSAlexander Aring 	case SIOCSIFADDR:
17271e36b1bSAlexander Aring 		return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg,
17371e36b1bSAlexander Aring 				cmd);
17471e36b1bSAlexander Aring 	default:
17571e36b1bSAlexander Aring 		if (!sk->sk_prot->ioctl)
17671e36b1bSAlexander Aring 			return -ENOIOCTLCMD;
17771e36b1bSAlexander Aring 		return sk->sk_prot->ioctl(sk, cmd, arg);
17871e36b1bSAlexander Aring 	}
17971e36b1bSAlexander Aring }
18071e36b1bSAlexander Aring 
18171e36b1bSAlexander Aring /* RAW Sockets (802.15.4 created in userspace) */
18271e36b1bSAlexander Aring static HLIST_HEAD(raw_head);
18371e36b1bSAlexander Aring static DEFINE_RWLOCK(raw_lock);
18471e36b1bSAlexander Aring 
185086c653fSCraig Gallek static int raw_hash(struct sock *sk)
18671e36b1bSAlexander Aring {
18771e36b1bSAlexander Aring 	write_lock_bh(&raw_lock);
18871e36b1bSAlexander Aring 	sk_add_node(sk, &raw_head);
18971e36b1bSAlexander Aring 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
19071e36b1bSAlexander Aring 	write_unlock_bh(&raw_lock);
191086c653fSCraig Gallek 
192086c653fSCraig Gallek 	return 0;
19371e36b1bSAlexander Aring }
19471e36b1bSAlexander Aring 
19571e36b1bSAlexander Aring static void raw_unhash(struct sock *sk)
19671e36b1bSAlexander Aring {
19771e36b1bSAlexander Aring 	write_lock_bh(&raw_lock);
19871e36b1bSAlexander Aring 	if (sk_del_node_init(sk))
19971e36b1bSAlexander Aring 		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
20071e36b1bSAlexander Aring 	write_unlock_bh(&raw_lock);
20171e36b1bSAlexander Aring }
20271e36b1bSAlexander Aring 
20371e36b1bSAlexander Aring static void raw_close(struct sock *sk, long timeout)
20471e36b1bSAlexander Aring {
20571e36b1bSAlexander Aring 	sk_common_release(sk);
20671e36b1bSAlexander Aring }
20771e36b1bSAlexander Aring 
20871e36b1bSAlexander Aring static int raw_bind(struct sock *sk, struct sockaddr *_uaddr, int len)
20971e36b1bSAlexander Aring {
21071e36b1bSAlexander Aring 	struct ieee802154_addr addr;
21171e36b1bSAlexander Aring 	struct sockaddr_ieee802154 *uaddr = (struct sockaddr_ieee802154 *)_uaddr;
21271e36b1bSAlexander Aring 	int err = 0;
21371e36b1bSAlexander Aring 	struct net_device *dev = NULL;
21471e36b1bSAlexander Aring 
21571e36b1bSAlexander Aring 	if (len < sizeof(*uaddr))
21671e36b1bSAlexander Aring 		return -EINVAL;
21771e36b1bSAlexander Aring 
21871e36b1bSAlexander Aring 	uaddr = (struct sockaddr_ieee802154 *)_uaddr;
21971e36b1bSAlexander Aring 	if (uaddr->family != AF_IEEE802154)
22071e36b1bSAlexander Aring 		return -EINVAL;
22171e36b1bSAlexander Aring 
22271e36b1bSAlexander Aring 	lock_sock(sk);
22371e36b1bSAlexander Aring 
22471e36b1bSAlexander Aring 	ieee802154_addr_from_sa(&addr, &uaddr->addr);
22571e36b1bSAlexander Aring 	dev = ieee802154_get_dev(sock_net(sk), &addr);
22671e36b1bSAlexander Aring 	if (!dev) {
22771e36b1bSAlexander Aring 		err = -ENODEV;
22871e36b1bSAlexander Aring 		goto out;
22971e36b1bSAlexander Aring 	}
23071e36b1bSAlexander Aring 
23171e36b1bSAlexander Aring 	sk->sk_bound_dev_if = dev->ifindex;
23271e36b1bSAlexander Aring 	sk_dst_reset(sk);
23371e36b1bSAlexander Aring 
23471e36b1bSAlexander Aring 	dev_put(dev);
23571e36b1bSAlexander Aring out:
23671e36b1bSAlexander Aring 	release_sock(sk);
23771e36b1bSAlexander Aring 
23871e36b1bSAlexander Aring 	return err;
23971e36b1bSAlexander Aring }
24071e36b1bSAlexander Aring 
24171e36b1bSAlexander Aring static int raw_connect(struct sock *sk, struct sockaddr *uaddr,
24271e36b1bSAlexander Aring 		       int addr_len)
24371e36b1bSAlexander Aring {
24471e36b1bSAlexander Aring 	return -ENOTSUPP;
24571e36b1bSAlexander Aring }
24671e36b1bSAlexander Aring 
24771e36b1bSAlexander Aring static int raw_disconnect(struct sock *sk, int flags)
24871e36b1bSAlexander Aring {
24971e36b1bSAlexander Aring 	return 0;
25071e36b1bSAlexander Aring }
25171e36b1bSAlexander Aring 
2521b784140SYing Xue static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
25371e36b1bSAlexander Aring {
25471e36b1bSAlexander Aring 	struct net_device *dev;
25571e36b1bSAlexander Aring 	unsigned int mtu;
25671e36b1bSAlexander Aring 	struct sk_buff *skb;
25771e36b1bSAlexander Aring 	int hlen, tlen;
25871e36b1bSAlexander Aring 	int err;
25971e36b1bSAlexander Aring 
26071e36b1bSAlexander Aring 	if (msg->msg_flags & MSG_OOB) {
26171e36b1bSAlexander Aring 		pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
26271e36b1bSAlexander Aring 		return -EOPNOTSUPP;
26371e36b1bSAlexander Aring 	}
26471e36b1bSAlexander Aring 
26571e36b1bSAlexander Aring 	lock_sock(sk);
26671e36b1bSAlexander Aring 	if (!sk->sk_bound_dev_if)
26771e36b1bSAlexander Aring 		dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
26871e36b1bSAlexander Aring 	else
26971e36b1bSAlexander Aring 		dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
27071e36b1bSAlexander Aring 	release_sock(sk);
27171e36b1bSAlexander Aring 
27271e36b1bSAlexander Aring 	if (!dev) {
27371e36b1bSAlexander Aring 		pr_debug("no dev\n");
27471e36b1bSAlexander Aring 		err = -ENXIO;
27571e36b1bSAlexander Aring 		goto out;
27671e36b1bSAlexander Aring 	}
27771e36b1bSAlexander Aring 
278b40988c4SAlexander Aring 	mtu = IEEE802154_MTU;
27971e36b1bSAlexander Aring 	pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
28071e36b1bSAlexander Aring 
28171e36b1bSAlexander Aring 	if (size > mtu) {
28271e36b1bSAlexander Aring 		pr_debug("size = %Zu, mtu = %u\n", size, mtu);
283c032705eSLennert Buytenhek 		err = -EMSGSIZE;
28471e36b1bSAlexander Aring 		goto out_dev;
28571e36b1bSAlexander Aring 	}
28671e36b1bSAlexander Aring 
28771e36b1bSAlexander Aring 	hlen = LL_RESERVED_SPACE(dev);
28871e36b1bSAlexander Aring 	tlen = dev->needed_tailroom;
28971e36b1bSAlexander Aring 	skb = sock_alloc_send_skb(sk, hlen + tlen + size,
29071e36b1bSAlexander Aring 				  msg->msg_flags & MSG_DONTWAIT, &err);
29171e36b1bSAlexander Aring 	if (!skb)
29271e36b1bSAlexander Aring 		goto out_dev;
29371e36b1bSAlexander Aring 
29471e36b1bSAlexander Aring 	skb_reserve(skb, hlen);
29571e36b1bSAlexander Aring 
29671e36b1bSAlexander Aring 	skb_reset_mac_header(skb);
29771e36b1bSAlexander Aring 	skb_reset_network_header(skb);
29871e36b1bSAlexander Aring 
29971e36b1bSAlexander Aring 	err = memcpy_from_msg(skb_put(skb, size), msg, size);
30071e36b1bSAlexander Aring 	if (err < 0)
30171e36b1bSAlexander Aring 		goto out_skb;
30271e36b1bSAlexander Aring 
30371e36b1bSAlexander Aring 	skb->dev = dev;
30471e36b1bSAlexander Aring 	skb->sk  = sk;
30571e36b1bSAlexander Aring 	skb->protocol = htons(ETH_P_IEEE802154);
30671e36b1bSAlexander Aring 
30771e36b1bSAlexander Aring 	dev_put(dev);
30871e36b1bSAlexander Aring 
30971e36b1bSAlexander Aring 	err = dev_queue_xmit(skb);
31071e36b1bSAlexander Aring 	if (err > 0)
31171e36b1bSAlexander Aring 		err = net_xmit_errno(err);
31271e36b1bSAlexander Aring 
31371e36b1bSAlexander Aring 	return err ?: size;
31471e36b1bSAlexander Aring 
31571e36b1bSAlexander Aring out_skb:
31671e36b1bSAlexander Aring 	kfree_skb(skb);
31771e36b1bSAlexander Aring out_dev:
31871e36b1bSAlexander Aring 	dev_put(dev);
31971e36b1bSAlexander Aring out:
32071e36b1bSAlexander Aring 	return err;
32171e36b1bSAlexander Aring }
32271e36b1bSAlexander Aring 
3231b784140SYing Xue static int raw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
3241b784140SYing Xue 		       int noblock, int flags, int *addr_len)
32571e36b1bSAlexander Aring {
32671e36b1bSAlexander Aring 	size_t copied = 0;
32771e36b1bSAlexander Aring 	int err = -EOPNOTSUPP;
32871e36b1bSAlexander Aring 	struct sk_buff *skb;
32971e36b1bSAlexander Aring 
33071e36b1bSAlexander Aring 	skb = skb_recv_datagram(sk, flags, noblock, &err);
33171e36b1bSAlexander Aring 	if (!skb)
33271e36b1bSAlexander Aring 		goto out;
33371e36b1bSAlexander Aring 
33471e36b1bSAlexander Aring 	copied = skb->len;
33571e36b1bSAlexander Aring 	if (len < copied) {
33671e36b1bSAlexander Aring 		msg->msg_flags |= MSG_TRUNC;
33771e36b1bSAlexander Aring 		copied = len;
33871e36b1bSAlexander Aring 	}
33971e36b1bSAlexander Aring 
34071e36b1bSAlexander Aring 	err = skb_copy_datagram_msg(skb, 0, msg, copied);
34171e36b1bSAlexander Aring 	if (err)
34271e36b1bSAlexander Aring 		goto done;
34371e36b1bSAlexander Aring 
34471e36b1bSAlexander Aring 	sock_recv_ts_and_drops(msg, sk, skb);
34571e36b1bSAlexander Aring 
34671e36b1bSAlexander Aring 	if (flags & MSG_TRUNC)
34771e36b1bSAlexander Aring 		copied = skb->len;
34871e36b1bSAlexander Aring done:
34971e36b1bSAlexander Aring 	skb_free_datagram(sk, skb);
35071e36b1bSAlexander Aring out:
35171e36b1bSAlexander Aring 	if (err)
35271e36b1bSAlexander Aring 		return err;
35371e36b1bSAlexander Aring 	return copied;
35471e36b1bSAlexander Aring }
35571e36b1bSAlexander Aring 
35671e36b1bSAlexander Aring static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
35771e36b1bSAlexander Aring {
35871e36b1bSAlexander Aring 	skb = skb_share_check(skb, GFP_ATOMIC);
35971e36b1bSAlexander Aring 	if (!skb)
36071e36b1bSAlexander Aring 		return NET_RX_DROP;
36171e36b1bSAlexander Aring 
36271e36b1bSAlexander Aring 	if (sock_queue_rcv_skb(sk, skb) < 0) {
36371e36b1bSAlexander Aring 		kfree_skb(skb);
36471e36b1bSAlexander Aring 		return NET_RX_DROP;
36571e36b1bSAlexander Aring 	}
36671e36b1bSAlexander Aring 
36771e36b1bSAlexander Aring 	return NET_RX_SUCCESS;
36871e36b1bSAlexander Aring }
36971e36b1bSAlexander Aring 
37071e36b1bSAlexander Aring static void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb)
37171e36b1bSAlexander Aring {
37271e36b1bSAlexander Aring 	struct sock *sk;
37371e36b1bSAlexander Aring 
37471e36b1bSAlexander Aring 	read_lock(&raw_lock);
37571e36b1bSAlexander Aring 	sk_for_each(sk, &raw_head) {
37671e36b1bSAlexander Aring 		bh_lock_sock(sk);
37771e36b1bSAlexander Aring 		if (!sk->sk_bound_dev_if ||
37871e36b1bSAlexander Aring 		    sk->sk_bound_dev_if == dev->ifindex) {
37971e36b1bSAlexander Aring 			struct sk_buff *clone;
38071e36b1bSAlexander Aring 
38171e36b1bSAlexander Aring 			clone = skb_clone(skb, GFP_ATOMIC);
38271e36b1bSAlexander Aring 			if (clone)
38371e36b1bSAlexander Aring 				raw_rcv_skb(sk, clone);
38471e36b1bSAlexander Aring 		}
38571e36b1bSAlexander Aring 		bh_unlock_sock(sk);
38671e36b1bSAlexander Aring 	}
38771e36b1bSAlexander Aring 	read_unlock(&raw_lock);
38871e36b1bSAlexander Aring }
38971e36b1bSAlexander Aring 
39071e36b1bSAlexander Aring static int raw_getsockopt(struct sock *sk, int level, int optname,
39171e36b1bSAlexander Aring 			  char __user *optval, int __user *optlen)
39271e36b1bSAlexander Aring {
39371e36b1bSAlexander Aring 	return -EOPNOTSUPP;
39471e36b1bSAlexander Aring }
39571e36b1bSAlexander Aring 
39671e36b1bSAlexander Aring static int raw_setsockopt(struct sock *sk, int level, int optname,
39771e36b1bSAlexander Aring 			  char __user *optval, unsigned int optlen)
39871e36b1bSAlexander Aring {
39971e36b1bSAlexander Aring 	return -EOPNOTSUPP;
40071e36b1bSAlexander Aring }
40171e36b1bSAlexander Aring 
40271e36b1bSAlexander Aring static struct proto ieee802154_raw_prot = {
40371e36b1bSAlexander Aring 	.name		= "IEEE-802.15.4-RAW",
40471e36b1bSAlexander Aring 	.owner		= THIS_MODULE,
40571e36b1bSAlexander Aring 	.obj_size	= sizeof(struct sock),
40671e36b1bSAlexander Aring 	.close		= raw_close,
40771e36b1bSAlexander Aring 	.bind		= raw_bind,
40871e36b1bSAlexander Aring 	.sendmsg	= raw_sendmsg,
40971e36b1bSAlexander Aring 	.recvmsg	= raw_recvmsg,
41071e36b1bSAlexander Aring 	.hash		= raw_hash,
41171e36b1bSAlexander Aring 	.unhash		= raw_unhash,
41271e36b1bSAlexander Aring 	.connect	= raw_connect,
41371e36b1bSAlexander Aring 	.disconnect	= raw_disconnect,
41471e36b1bSAlexander Aring 	.getsockopt	= raw_getsockopt,
41571e36b1bSAlexander Aring 	.setsockopt	= raw_setsockopt,
41671e36b1bSAlexander Aring };
41771e36b1bSAlexander Aring 
41871e36b1bSAlexander Aring static const struct proto_ops ieee802154_raw_ops = {
41971e36b1bSAlexander Aring 	.family		   = PF_IEEE802154,
42071e36b1bSAlexander Aring 	.owner		   = THIS_MODULE,
42171e36b1bSAlexander Aring 	.release	   = ieee802154_sock_release,
42271e36b1bSAlexander Aring 	.bind		   = ieee802154_sock_bind,
42371e36b1bSAlexander Aring 	.connect	   = ieee802154_sock_connect,
42471e36b1bSAlexander Aring 	.socketpair	   = sock_no_socketpair,
42571e36b1bSAlexander Aring 	.accept		   = sock_no_accept,
42671e36b1bSAlexander Aring 	.getname	   = sock_no_getname,
42771e36b1bSAlexander Aring 	.poll		   = datagram_poll,
42871e36b1bSAlexander Aring 	.ioctl		   = ieee802154_sock_ioctl,
42971e36b1bSAlexander Aring 	.listen		   = sock_no_listen,
43071e36b1bSAlexander Aring 	.shutdown	   = sock_no_shutdown,
43171e36b1bSAlexander Aring 	.setsockopt	   = sock_common_setsockopt,
43271e36b1bSAlexander Aring 	.getsockopt	   = sock_common_getsockopt,
43371e36b1bSAlexander Aring 	.sendmsg	   = ieee802154_sock_sendmsg,
43471e36b1bSAlexander Aring 	.recvmsg	   = sock_common_recvmsg,
43571e36b1bSAlexander Aring 	.mmap		   = sock_no_mmap,
43671e36b1bSAlexander Aring 	.sendpage	   = sock_no_sendpage,
43771e36b1bSAlexander Aring #ifdef CONFIG_COMPAT
43871e36b1bSAlexander Aring 	.compat_setsockopt = compat_sock_common_setsockopt,
43971e36b1bSAlexander Aring 	.compat_getsockopt = compat_sock_common_getsockopt,
44071e36b1bSAlexander Aring #endif
44171e36b1bSAlexander Aring };
44271e36b1bSAlexander Aring 
44371e36b1bSAlexander Aring /* DGRAM Sockets (802.15.4 dataframes) */
44471e36b1bSAlexander Aring static HLIST_HEAD(dgram_head);
44571e36b1bSAlexander Aring static DEFINE_RWLOCK(dgram_lock);
44671e36b1bSAlexander Aring 
44771e36b1bSAlexander Aring struct dgram_sock {
44871e36b1bSAlexander Aring 	struct sock sk;
44971e36b1bSAlexander Aring 
45071e36b1bSAlexander Aring 	struct ieee802154_addr src_addr;
45171e36b1bSAlexander Aring 	struct ieee802154_addr dst_addr;
45271e36b1bSAlexander Aring 
45371e36b1bSAlexander Aring 	unsigned int bound:1;
45471e36b1bSAlexander Aring 	unsigned int connected:1;
45571e36b1bSAlexander Aring 	unsigned int want_ack:1;
45671e36b1bSAlexander Aring 	unsigned int secen:1;
45771e36b1bSAlexander Aring 	unsigned int secen_override:1;
45871e36b1bSAlexander Aring 	unsigned int seclevel:3;
45971e36b1bSAlexander Aring 	unsigned int seclevel_override:1;
46071e36b1bSAlexander Aring };
46171e36b1bSAlexander Aring 
46271e36b1bSAlexander Aring static inline struct dgram_sock *dgram_sk(const struct sock *sk)
46371e36b1bSAlexander Aring {
46471e36b1bSAlexander Aring 	return container_of(sk, struct dgram_sock, sk);
46571e36b1bSAlexander Aring }
46671e36b1bSAlexander Aring 
467086c653fSCraig Gallek static int dgram_hash(struct sock *sk)
46871e36b1bSAlexander Aring {
46971e36b1bSAlexander Aring 	write_lock_bh(&dgram_lock);
47071e36b1bSAlexander Aring 	sk_add_node(sk, &dgram_head);
47171e36b1bSAlexander Aring 	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
47271e36b1bSAlexander Aring 	write_unlock_bh(&dgram_lock);
473086c653fSCraig Gallek 
474086c653fSCraig Gallek 	return 0;
47571e36b1bSAlexander Aring }
47671e36b1bSAlexander Aring 
47771e36b1bSAlexander Aring static void dgram_unhash(struct sock *sk)
47871e36b1bSAlexander Aring {
47971e36b1bSAlexander Aring 	write_lock_bh(&dgram_lock);
48071e36b1bSAlexander Aring 	if (sk_del_node_init(sk))
48171e36b1bSAlexander Aring 		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
48271e36b1bSAlexander Aring 	write_unlock_bh(&dgram_lock);
48371e36b1bSAlexander Aring }
48471e36b1bSAlexander Aring 
48571e36b1bSAlexander Aring static int dgram_init(struct sock *sk)
48671e36b1bSAlexander Aring {
48771e36b1bSAlexander Aring 	struct dgram_sock *ro = dgram_sk(sk);
48871e36b1bSAlexander Aring 
48971e36b1bSAlexander Aring 	ro->want_ack = 1;
49071e36b1bSAlexander Aring 	return 0;
49171e36b1bSAlexander Aring }
49271e36b1bSAlexander Aring 
49371e36b1bSAlexander Aring static void dgram_close(struct sock *sk, long timeout)
49471e36b1bSAlexander Aring {
49571e36b1bSAlexander Aring 	sk_common_release(sk);
49671e36b1bSAlexander Aring }
49771e36b1bSAlexander Aring 
49871e36b1bSAlexander Aring static int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
49971e36b1bSAlexander Aring {
50071e36b1bSAlexander Aring 	struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
50171e36b1bSAlexander Aring 	struct ieee802154_addr haddr;
50271e36b1bSAlexander Aring 	struct dgram_sock *ro = dgram_sk(sk);
50371e36b1bSAlexander Aring 	int err = -EINVAL;
50471e36b1bSAlexander Aring 	struct net_device *dev;
50571e36b1bSAlexander Aring 
50671e36b1bSAlexander Aring 	lock_sock(sk);
50771e36b1bSAlexander Aring 
50871e36b1bSAlexander Aring 	ro->bound = 0;
50971e36b1bSAlexander Aring 
51071e36b1bSAlexander Aring 	if (len < sizeof(*addr))
51171e36b1bSAlexander Aring 		goto out;
51271e36b1bSAlexander Aring 
51371e36b1bSAlexander Aring 	if (addr->family != AF_IEEE802154)
51471e36b1bSAlexander Aring 		goto out;
51571e36b1bSAlexander Aring 
51671e36b1bSAlexander Aring 	ieee802154_addr_from_sa(&haddr, &addr->addr);
51771e36b1bSAlexander Aring 	dev = ieee802154_get_dev(sock_net(sk), &haddr);
51871e36b1bSAlexander Aring 	if (!dev) {
51971e36b1bSAlexander Aring 		err = -ENODEV;
52071e36b1bSAlexander Aring 		goto out;
52171e36b1bSAlexander Aring 	}
52271e36b1bSAlexander Aring 
52371e36b1bSAlexander Aring 	if (dev->type != ARPHRD_IEEE802154) {
52471e36b1bSAlexander Aring 		err = -ENODEV;
52571e36b1bSAlexander Aring 		goto out_put;
52671e36b1bSAlexander Aring 	}
52771e36b1bSAlexander Aring 
52871e36b1bSAlexander Aring 	ro->src_addr = haddr;
52971e36b1bSAlexander Aring 
53071e36b1bSAlexander Aring 	ro->bound = 1;
53171e36b1bSAlexander Aring 	err = 0;
53271e36b1bSAlexander Aring out_put:
53371e36b1bSAlexander Aring 	dev_put(dev);
53471e36b1bSAlexander Aring out:
53571e36b1bSAlexander Aring 	release_sock(sk);
53671e36b1bSAlexander Aring 
53771e36b1bSAlexander Aring 	return err;
53871e36b1bSAlexander Aring }
53971e36b1bSAlexander Aring 
54071e36b1bSAlexander Aring static int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg)
54171e36b1bSAlexander Aring {
54271e36b1bSAlexander Aring 	switch (cmd) {
54371e36b1bSAlexander Aring 	case SIOCOUTQ:
54471e36b1bSAlexander Aring 	{
54571e36b1bSAlexander Aring 		int amount = sk_wmem_alloc_get(sk);
54671e36b1bSAlexander Aring 
54771e36b1bSAlexander Aring 		return put_user(amount, (int __user *)arg);
54871e36b1bSAlexander Aring 	}
54971e36b1bSAlexander Aring 
55071e36b1bSAlexander Aring 	case SIOCINQ:
55171e36b1bSAlexander Aring 	{
55271e36b1bSAlexander Aring 		struct sk_buff *skb;
55371e36b1bSAlexander Aring 		unsigned long amount;
55471e36b1bSAlexander Aring 
55571e36b1bSAlexander Aring 		amount = 0;
55671e36b1bSAlexander Aring 		spin_lock_bh(&sk->sk_receive_queue.lock);
55771e36b1bSAlexander Aring 		skb = skb_peek(&sk->sk_receive_queue);
55871e36b1bSAlexander Aring 		if (skb) {
55971e36b1bSAlexander Aring 			/* We will only return the amount
56071e36b1bSAlexander Aring 			 * of this packet since that is all
56171e36b1bSAlexander Aring 			 * that will be read.
56271e36b1bSAlexander Aring 			 */
56371e36b1bSAlexander Aring 			amount = skb->len - ieee802154_hdr_length(skb);
56471e36b1bSAlexander Aring 		}
56571e36b1bSAlexander Aring 		spin_unlock_bh(&sk->sk_receive_queue.lock);
56671e36b1bSAlexander Aring 		return put_user(amount, (int __user *)arg);
56771e36b1bSAlexander Aring 	}
56871e36b1bSAlexander Aring 	}
56971e36b1bSAlexander Aring 
57071e36b1bSAlexander Aring 	return -ENOIOCTLCMD;
57171e36b1bSAlexander Aring }
57271e36b1bSAlexander Aring 
57371e36b1bSAlexander Aring /* FIXME: autobind */
57471e36b1bSAlexander Aring static int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
57571e36b1bSAlexander Aring 			 int len)
57671e36b1bSAlexander Aring {
57771e36b1bSAlexander Aring 	struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
57871e36b1bSAlexander Aring 	struct dgram_sock *ro = dgram_sk(sk);
57971e36b1bSAlexander Aring 	int err = 0;
58071e36b1bSAlexander Aring 
58171e36b1bSAlexander Aring 	if (len < sizeof(*addr))
58271e36b1bSAlexander Aring 		return -EINVAL;
58371e36b1bSAlexander Aring 
58471e36b1bSAlexander Aring 	if (addr->family != AF_IEEE802154)
58571e36b1bSAlexander Aring 		return -EINVAL;
58671e36b1bSAlexander Aring 
58771e36b1bSAlexander Aring 	lock_sock(sk);
58871e36b1bSAlexander Aring 
58971e36b1bSAlexander Aring 	if (!ro->bound) {
59071e36b1bSAlexander Aring 		err = -ENETUNREACH;
59171e36b1bSAlexander Aring 		goto out;
59271e36b1bSAlexander Aring 	}
59371e36b1bSAlexander Aring 
59471e36b1bSAlexander Aring 	ieee802154_addr_from_sa(&ro->dst_addr, &addr->addr);
59571e36b1bSAlexander Aring 	ro->connected = 1;
59671e36b1bSAlexander Aring 
59771e36b1bSAlexander Aring out:
59871e36b1bSAlexander Aring 	release_sock(sk);
59971e36b1bSAlexander Aring 	return err;
60071e36b1bSAlexander Aring }
60171e36b1bSAlexander Aring 
60271e36b1bSAlexander Aring static int dgram_disconnect(struct sock *sk, int flags)
60371e36b1bSAlexander Aring {
60471e36b1bSAlexander Aring 	struct dgram_sock *ro = dgram_sk(sk);
60571e36b1bSAlexander Aring 
60671e36b1bSAlexander Aring 	lock_sock(sk);
60771e36b1bSAlexander Aring 	ro->connected = 0;
60871e36b1bSAlexander Aring 	release_sock(sk);
60971e36b1bSAlexander Aring 
61071e36b1bSAlexander Aring 	return 0;
61171e36b1bSAlexander Aring }
61271e36b1bSAlexander Aring 
6131b784140SYing Xue static int dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
61471e36b1bSAlexander Aring {
61571e36b1bSAlexander Aring 	struct net_device *dev;
61671e36b1bSAlexander Aring 	unsigned int mtu;
61771e36b1bSAlexander Aring 	struct sk_buff *skb;
61871e36b1bSAlexander Aring 	struct ieee802154_mac_cb *cb;
61971e36b1bSAlexander Aring 	struct dgram_sock *ro = dgram_sk(sk);
62071e36b1bSAlexander Aring 	struct ieee802154_addr dst_addr;
62171e36b1bSAlexander Aring 	int hlen, tlen;
62271e36b1bSAlexander Aring 	int err;
62371e36b1bSAlexander Aring 
62471e36b1bSAlexander Aring 	if (msg->msg_flags & MSG_OOB) {
62571e36b1bSAlexander Aring 		pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
62671e36b1bSAlexander Aring 		return -EOPNOTSUPP;
62771e36b1bSAlexander Aring 	}
62871e36b1bSAlexander Aring 
62971e36b1bSAlexander Aring 	if (!ro->connected && !msg->msg_name)
63071e36b1bSAlexander Aring 		return -EDESTADDRREQ;
63171e36b1bSAlexander Aring 	else if (ro->connected && msg->msg_name)
63271e36b1bSAlexander Aring 		return -EISCONN;
63371e36b1bSAlexander Aring 
63471e36b1bSAlexander Aring 	if (!ro->bound)
63571e36b1bSAlexander Aring 		dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
63671e36b1bSAlexander Aring 	else
63771e36b1bSAlexander Aring 		dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr);
63871e36b1bSAlexander Aring 
63971e36b1bSAlexander Aring 	if (!dev) {
64071e36b1bSAlexander Aring 		pr_debug("no dev\n");
64171e36b1bSAlexander Aring 		err = -ENXIO;
64271e36b1bSAlexander Aring 		goto out;
64371e36b1bSAlexander Aring 	}
644b40988c4SAlexander Aring 	mtu = IEEE802154_MTU;
64571e36b1bSAlexander Aring 	pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
64671e36b1bSAlexander Aring 
64771e36b1bSAlexander Aring 	if (size > mtu) {
64871e36b1bSAlexander Aring 		pr_debug("size = %Zu, mtu = %u\n", size, mtu);
64971e36b1bSAlexander Aring 		err = -EMSGSIZE;
65071e36b1bSAlexander Aring 		goto out_dev;
65171e36b1bSAlexander Aring 	}
65271e36b1bSAlexander Aring 
65371e36b1bSAlexander Aring 	hlen = LL_RESERVED_SPACE(dev);
65471e36b1bSAlexander Aring 	tlen = dev->needed_tailroom;
65571e36b1bSAlexander Aring 	skb = sock_alloc_send_skb(sk, hlen + tlen + size,
65671e36b1bSAlexander Aring 				  msg->msg_flags & MSG_DONTWAIT,
65771e36b1bSAlexander Aring 				  &err);
65871e36b1bSAlexander Aring 	if (!skb)
65971e36b1bSAlexander Aring 		goto out_dev;
66071e36b1bSAlexander Aring 
66171e36b1bSAlexander Aring 	skb_reserve(skb, hlen);
66271e36b1bSAlexander Aring 
66371e36b1bSAlexander Aring 	skb_reset_network_header(skb);
66471e36b1bSAlexander Aring 
66571e36b1bSAlexander Aring 	cb = mac_cb_init(skb);
66671e36b1bSAlexander Aring 	cb->type = IEEE802154_FC_TYPE_DATA;
66771e36b1bSAlexander Aring 	cb->ackreq = ro->want_ack;
66871e36b1bSAlexander Aring 
66971e36b1bSAlexander Aring 	if (msg->msg_name) {
67071e36b1bSAlexander Aring 		DECLARE_SOCKADDR(struct sockaddr_ieee802154*,
67171e36b1bSAlexander Aring 				 daddr, msg->msg_name);
67271e36b1bSAlexander Aring 
67371e36b1bSAlexander Aring 		ieee802154_addr_from_sa(&dst_addr, &daddr->addr);
67471e36b1bSAlexander Aring 	} else {
67571e36b1bSAlexander Aring 		dst_addr = ro->dst_addr;
67671e36b1bSAlexander Aring 	}
67771e36b1bSAlexander Aring 
67871e36b1bSAlexander Aring 	cb->secen = ro->secen;
67971e36b1bSAlexander Aring 	cb->secen_override = ro->secen_override;
68071e36b1bSAlexander Aring 	cb->seclevel = ro->seclevel;
68171e36b1bSAlexander Aring 	cb->seclevel_override = ro->seclevel_override;
68271e36b1bSAlexander Aring 
683838b83d6SAlexander Aring 	err = wpan_dev_hard_header(skb, dev, &dst_addr,
68471e36b1bSAlexander Aring 				   ro->bound ? &ro->src_addr : NULL, size);
68571e36b1bSAlexander Aring 	if (err < 0)
68671e36b1bSAlexander Aring 		goto out_skb;
68771e36b1bSAlexander Aring 
68871e36b1bSAlexander Aring 	err = memcpy_from_msg(skb_put(skb, size), msg, size);
68971e36b1bSAlexander Aring 	if (err < 0)
69071e36b1bSAlexander Aring 		goto out_skb;
69171e36b1bSAlexander Aring 
69271e36b1bSAlexander Aring 	skb->dev = dev;
69371e36b1bSAlexander Aring 	skb->sk  = sk;
69471e36b1bSAlexander Aring 	skb->protocol = htons(ETH_P_IEEE802154);
69571e36b1bSAlexander Aring 
69671e36b1bSAlexander Aring 	dev_put(dev);
69771e36b1bSAlexander Aring 
69871e36b1bSAlexander Aring 	err = dev_queue_xmit(skb);
69971e36b1bSAlexander Aring 	if (err > 0)
70071e36b1bSAlexander Aring 		err = net_xmit_errno(err);
70171e36b1bSAlexander Aring 
70271e36b1bSAlexander Aring 	return err ?: size;
70371e36b1bSAlexander Aring 
70471e36b1bSAlexander Aring out_skb:
70571e36b1bSAlexander Aring 	kfree_skb(skb);
70671e36b1bSAlexander Aring out_dev:
70771e36b1bSAlexander Aring 	dev_put(dev);
70871e36b1bSAlexander Aring out:
70971e36b1bSAlexander Aring 	return err;
71071e36b1bSAlexander Aring }
71171e36b1bSAlexander Aring 
7121b784140SYing Xue static int dgram_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
7131b784140SYing Xue 			 int noblock, int flags, int *addr_len)
71471e36b1bSAlexander Aring {
71571e36b1bSAlexander Aring 	size_t copied = 0;
71671e36b1bSAlexander Aring 	int err = -EOPNOTSUPP;
71771e36b1bSAlexander Aring 	struct sk_buff *skb;
71871e36b1bSAlexander Aring 	DECLARE_SOCKADDR(struct sockaddr_ieee802154 *, saddr, msg->msg_name);
71971e36b1bSAlexander Aring 
72071e36b1bSAlexander Aring 	skb = skb_recv_datagram(sk, flags, noblock, &err);
72171e36b1bSAlexander Aring 	if (!skb)
72271e36b1bSAlexander Aring 		goto out;
72371e36b1bSAlexander Aring 
72471e36b1bSAlexander Aring 	copied = skb->len;
72571e36b1bSAlexander Aring 	if (len < copied) {
72671e36b1bSAlexander Aring 		msg->msg_flags |= MSG_TRUNC;
72771e36b1bSAlexander Aring 		copied = len;
72871e36b1bSAlexander Aring 	}
72971e36b1bSAlexander Aring 
73071e36b1bSAlexander Aring 	/* FIXME: skip headers if necessary ?! */
73171e36b1bSAlexander Aring 	err = skb_copy_datagram_msg(skb, 0, msg, copied);
73271e36b1bSAlexander Aring 	if (err)
73371e36b1bSAlexander Aring 		goto done;
73471e36b1bSAlexander Aring 
73571e36b1bSAlexander Aring 	sock_recv_ts_and_drops(msg, sk, skb);
73671e36b1bSAlexander Aring 
73771e36b1bSAlexander Aring 	if (saddr) {
7388a70cefaSLennert Buytenhek 		/* Clear the implicit padding in struct sockaddr_ieee802154
7398a70cefaSLennert Buytenhek 		 * (16 bits between 'family' and 'addr') and in struct
7408a70cefaSLennert Buytenhek 		 * ieee802154_addr_sa (16 bits at the end of the structure).
7418a70cefaSLennert Buytenhek 		 */
7428a70cefaSLennert Buytenhek 		memset(saddr, 0, sizeof(*saddr));
7438a70cefaSLennert Buytenhek 
74471e36b1bSAlexander Aring 		saddr->family = AF_IEEE802154;
74571e36b1bSAlexander Aring 		ieee802154_addr_to_sa(&saddr->addr, &mac_cb(skb)->source);
74671e36b1bSAlexander Aring 		*addr_len = sizeof(*saddr);
74771e36b1bSAlexander Aring 	}
74871e36b1bSAlexander Aring 
74971e36b1bSAlexander Aring 	if (flags & MSG_TRUNC)
75071e36b1bSAlexander Aring 		copied = skb->len;
75171e36b1bSAlexander Aring done:
75271e36b1bSAlexander Aring 	skb_free_datagram(sk, skb);
75371e36b1bSAlexander Aring out:
75471e36b1bSAlexander Aring 	if (err)
75571e36b1bSAlexander Aring 		return err;
75671e36b1bSAlexander Aring 	return copied;
75771e36b1bSAlexander Aring }
75871e36b1bSAlexander Aring 
75971e36b1bSAlexander Aring static int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
76071e36b1bSAlexander Aring {
76171e36b1bSAlexander Aring 	skb = skb_share_check(skb, GFP_ATOMIC);
76271e36b1bSAlexander Aring 	if (!skb)
76371e36b1bSAlexander Aring 		return NET_RX_DROP;
76471e36b1bSAlexander Aring 
76571e36b1bSAlexander Aring 	if (sock_queue_rcv_skb(sk, skb) < 0) {
76671e36b1bSAlexander Aring 		kfree_skb(skb);
76771e36b1bSAlexander Aring 		return NET_RX_DROP;
76871e36b1bSAlexander Aring 	}
76971e36b1bSAlexander Aring 
77071e36b1bSAlexander Aring 	return NET_RX_SUCCESS;
77171e36b1bSAlexander Aring }
77271e36b1bSAlexander Aring 
77371e36b1bSAlexander Aring static inline bool
77471e36b1bSAlexander Aring ieee802154_match_sock(__le64 hw_addr, __le16 pan_id, __le16 short_addr,
77571e36b1bSAlexander Aring 		      struct dgram_sock *ro)
77671e36b1bSAlexander Aring {
77771e36b1bSAlexander Aring 	if (!ro->bound)
77871e36b1bSAlexander Aring 		return true;
77971e36b1bSAlexander Aring 
78071e36b1bSAlexander Aring 	if (ro->src_addr.mode == IEEE802154_ADDR_LONG &&
78171e36b1bSAlexander Aring 	    hw_addr == ro->src_addr.extended_addr)
78271e36b1bSAlexander Aring 		return true;
78371e36b1bSAlexander Aring 
78471e36b1bSAlexander Aring 	if (ro->src_addr.mode == IEEE802154_ADDR_SHORT &&
78571e36b1bSAlexander Aring 	    pan_id == ro->src_addr.pan_id &&
78671e36b1bSAlexander Aring 	    short_addr == ro->src_addr.short_addr)
78771e36b1bSAlexander Aring 		return true;
78871e36b1bSAlexander Aring 
78971e36b1bSAlexander Aring 	return false;
79071e36b1bSAlexander Aring }
79171e36b1bSAlexander Aring 
79271e36b1bSAlexander Aring static int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
79371e36b1bSAlexander Aring {
79471e36b1bSAlexander Aring 	struct sock *sk, *prev = NULL;
79571e36b1bSAlexander Aring 	int ret = NET_RX_SUCCESS;
79671e36b1bSAlexander Aring 	__le16 pan_id, short_addr;
79771e36b1bSAlexander Aring 	__le64 hw_addr;
79871e36b1bSAlexander Aring 
79971e36b1bSAlexander Aring 	/* Data frame processing */
80071e36b1bSAlexander Aring 	BUG_ON(dev->type != ARPHRD_IEEE802154);
80171e36b1bSAlexander Aring 
802c947f7e1SAlexander Aring 	pan_id = dev->ieee802154_ptr->pan_id;
803c947f7e1SAlexander Aring 	short_addr = dev->ieee802154_ptr->short_addr;
804c947f7e1SAlexander Aring 	hw_addr = dev->ieee802154_ptr->extended_addr;
80571e36b1bSAlexander Aring 
80671e36b1bSAlexander Aring 	read_lock(&dgram_lock);
80771e36b1bSAlexander Aring 	sk_for_each(sk, &dgram_head) {
80871e36b1bSAlexander Aring 		if (ieee802154_match_sock(hw_addr, pan_id, short_addr,
80971e36b1bSAlexander Aring 					  dgram_sk(sk))) {
81071e36b1bSAlexander Aring 			if (prev) {
81171e36b1bSAlexander Aring 				struct sk_buff *clone;
81271e36b1bSAlexander Aring 
81371e36b1bSAlexander Aring 				clone = skb_clone(skb, GFP_ATOMIC);
81471e36b1bSAlexander Aring 				if (clone)
81571e36b1bSAlexander Aring 					dgram_rcv_skb(prev, clone);
81671e36b1bSAlexander Aring 			}
81771e36b1bSAlexander Aring 
81871e36b1bSAlexander Aring 			prev = sk;
81971e36b1bSAlexander Aring 		}
82071e36b1bSAlexander Aring 	}
82171e36b1bSAlexander Aring 
82271e36b1bSAlexander Aring 	if (prev) {
82371e36b1bSAlexander Aring 		dgram_rcv_skb(prev, skb);
82471e36b1bSAlexander Aring 	} else {
82571e36b1bSAlexander Aring 		kfree_skb(skb);
82671e36b1bSAlexander Aring 		ret = NET_RX_DROP;
82771e36b1bSAlexander Aring 	}
82871e36b1bSAlexander Aring 	read_unlock(&dgram_lock);
82971e36b1bSAlexander Aring 
83071e36b1bSAlexander Aring 	return ret;
83171e36b1bSAlexander Aring }
83271e36b1bSAlexander Aring 
83371e36b1bSAlexander Aring static int dgram_getsockopt(struct sock *sk, int level, int optname,
83471e36b1bSAlexander Aring 			    char __user *optval, int __user *optlen)
83571e36b1bSAlexander Aring {
83671e36b1bSAlexander Aring 	struct dgram_sock *ro = dgram_sk(sk);
83771e36b1bSAlexander Aring 
83871e36b1bSAlexander Aring 	int val, len;
83971e36b1bSAlexander Aring 
84071e36b1bSAlexander Aring 	if (level != SOL_IEEE802154)
84171e36b1bSAlexander Aring 		return -EOPNOTSUPP;
84271e36b1bSAlexander Aring 
84371e36b1bSAlexander Aring 	if (get_user(len, optlen))
84471e36b1bSAlexander Aring 		return -EFAULT;
84571e36b1bSAlexander Aring 
84671e36b1bSAlexander Aring 	len = min_t(unsigned int, len, sizeof(int));
84771e36b1bSAlexander Aring 
84871e36b1bSAlexander Aring 	switch (optname) {
84971e36b1bSAlexander Aring 	case WPAN_WANTACK:
85071e36b1bSAlexander Aring 		val = ro->want_ack;
85171e36b1bSAlexander Aring 		break;
85271e36b1bSAlexander Aring 	case WPAN_SECURITY:
85371e36b1bSAlexander Aring 		if (!ro->secen_override)
85471e36b1bSAlexander Aring 			val = WPAN_SECURITY_DEFAULT;
85571e36b1bSAlexander Aring 		else if (ro->secen)
85671e36b1bSAlexander Aring 			val = WPAN_SECURITY_ON;
85771e36b1bSAlexander Aring 		else
85871e36b1bSAlexander Aring 			val = WPAN_SECURITY_OFF;
85971e36b1bSAlexander Aring 		break;
86071e36b1bSAlexander Aring 	case WPAN_SECURITY_LEVEL:
86171e36b1bSAlexander Aring 		if (!ro->seclevel_override)
86271e36b1bSAlexander Aring 			val = WPAN_SECURITY_LEVEL_DEFAULT;
86371e36b1bSAlexander Aring 		else
86471e36b1bSAlexander Aring 			val = ro->seclevel;
86571e36b1bSAlexander Aring 		break;
86671e36b1bSAlexander Aring 	default:
86771e36b1bSAlexander Aring 		return -ENOPROTOOPT;
86871e36b1bSAlexander Aring 	}
86971e36b1bSAlexander Aring 
87071e36b1bSAlexander Aring 	if (put_user(len, optlen))
87171e36b1bSAlexander Aring 		return -EFAULT;
87271e36b1bSAlexander Aring 	if (copy_to_user(optval, &val, len))
87371e36b1bSAlexander Aring 		return -EFAULT;
87471e36b1bSAlexander Aring 	return 0;
87571e36b1bSAlexander Aring }
87671e36b1bSAlexander Aring 
87771e36b1bSAlexander Aring static int dgram_setsockopt(struct sock *sk, int level, int optname,
87871e36b1bSAlexander Aring 			    char __user *optval, unsigned int optlen)
87971e36b1bSAlexander Aring {
88071e36b1bSAlexander Aring 	struct dgram_sock *ro = dgram_sk(sk);
88171e36b1bSAlexander Aring 	struct net *net = sock_net(sk);
88271e36b1bSAlexander Aring 	int val;
88371e36b1bSAlexander Aring 	int err = 0;
88471e36b1bSAlexander Aring 
88571e36b1bSAlexander Aring 	if (optlen < sizeof(int))
88671e36b1bSAlexander Aring 		return -EINVAL;
88771e36b1bSAlexander Aring 
88871e36b1bSAlexander Aring 	if (get_user(val, (int __user *)optval))
88971e36b1bSAlexander Aring 		return -EFAULT;
89071e36b1bSAlexander Aring 
89171e36b1bSAlexander Aring 	lock_sock(sk);
89271e36b1bSAlexander Aring 
89371e36b1bSAlexander Aring 	switch (optname) {
89471e36b1bSAlexander Aring 	case WPAN_WANTACK:
89571e36b1bSAlexander Aring 		ro->want_ack = !!val;
89671e36b1bSAlexander Aring 		break;
89771e36b1bSAlexander Aring 	case WPAN_SECURITY:
89871e36b1bSAlexander Aring 		if (!ns_capable(net->user_ns, CAP_NET_ADMIN) &&
89971e36b1bSAlexander Aring 		    !ns_capable(net->user_ns, CAP_NET_RAW)) {
90071e36b1bSAlexander Aring 			err = -EPERM;
90171e36b1bSAlexander Aring 			break;
90271e36b1bSAlexander Aring 		}
90371e36b1bSAlexander Aring 
90471e36b1bSAlexander Aring 		switch (val) {
90571e36b1bSAlexander Aring 		case WPAN_SECURITY_DEFAULT:
90671e36b1bSAlexander Aring 			ro->secen_override = 0;
90771e36b1bSAlexander Aring 			break;
90871e36b1bSAlexander Aring 		case WPAN_SECURITY_ON:
90971e36b1bSAlexander Aring 			ro->secen_override = 1;
91071e36b1bSAlexander Aring 			ro->secen = 1;
91171e36b1bSAlexander Aring 			break;
91271e36b1bSAlexander Aring 		case WPAN_SECURITY_OFF:
91371e36b1bSAlexander Aring 			ro->secen_override = 1;
91471e36b1bSAlexander Aring 			ro->secen = 0;
91571e36b1bSAlexander Aring 			break;
91671e36b1bSAlexander Aring 		default:
91771e36b1bSAlexander Aring 			err = -EINVAL;
91871e36b1bSAlexander Aring 			break;
91971e36b1bSAlexander Aring 		}
92071e36b1bSAlexander Aring 		break;
92171e36b1bSAlexander Aring 	case WPAN_SECURITY_LEVEL:
92271e36b1bSAlexander Aring 		if (!ns_capable(net->user_ns, CAP_NET_ADMIN) &&
92371e36b1bSAlexander Aring 		    !ns_capable(net->user_ns, CAP_NET_RAW)) {
92471e36b1bSAlexander Aring 			err = -EPERM;
92571e36b1bSAlexander Aring 			break;
92671e36b1bSAlexander Aring 		}
92771e36b1bSAlexander Aring 
92871e36b1bSAlexander Aring 		if (val < WPAN_SECURITY_LEVEL_DEFAULT ||
92971e36b1bSAlexander Aring 		    val > IEEE802154_SCF_SECLEVEL_ENC_MIC128) {
93071e36b1bSAlexander Aring 			err = -EINVAL;
93171e36b1bSAlexander Aring 		} else if (val == WPAN_SECURITY_LEVEL_DEFAULT) {
93271e36b1bSAlexander Aring 			ro->seclevel_override = 0;
93371e36b1bSAlexander Aring 		} else {
93471e36b1bSAlexander Aring 			ro->seclevel_override = 1;
93571e36b1bSAlexander Aring 			ro->seclevel = val;
93671e36b1bSAlexander Aring 		}
93771e36b1bSAlexander Aring 		break;
93871e36b1bSAlexander Aring 	default:
93971e36b1bSAlexander Aring 		err = -ENOPROTOOPT;
94071e36b1bSAlexander Aring 		break;
94171e36b1bSAlexander Aring 	}
94271e36b1bSAlexander Aring 
94371e36b1bSAlexander Aring 	release_sock(sk);
94471e36b1bSAlexander Aring 	return err;
94571e36b1bSAlexander Aring }
94671e36b1bSAlexander Aring 
94771e36b1bSAlexander Aring static struct proto ieee802154_dgram_prot = {
94871e36b1bSAlexander Aring 	.name		= "IEEE-802.15.4-MAC",
94971e36b1bSAlexander Aring 	.owner		= THIS_MODULE,
95071e36b1bSAlexander Aring 	.obj_size	= sizeof(struct dgram_sock),
95171e36b1bSAlexander Aring 	.init		= dgram_init,
95271e36b1bSAlexander Aring 	.close		= dgram_close,
95371e36b1bSAlexander Aring 	.bind		= dgram_bind,
95471e36b1bSAlexander Aring 	.sendmsg	= dgram_sendmsg,
95571e36b1bSAlexander Aring 	.recvmsg	= dgram_recvmsg,
95671e36b1bSAlexander Aring 	.hash		= dgram_hash,
95771e36b1bSAlexander Aring 	.unhash		= dgram_unhash,
95871e36b1bSAlexander Aring 	.connect	= dgram_connect,
95971e36b1bSAlexander Aring 	.disconnect	= dgram_disconnect,
96071e36b1bSAlexander Aring 	.ioctl		= dgram_ioctl,
96171e36b1bSAlexander Aring 	.getsockopt	= dgram_getsockopt,
96271e36b1bSAlexander Aring 	.setsockopt	= dgram_setsockopt,
96371e36b1bSAlexander Aring };
96471e36b1bSAlexander Aring 
96571e36b1bSAlexander Aring static const struct proto_ops ieee802154_dgram_ops = {
96671e36b1bSAlexander Aring 	.family		   = PF_IEEE802154,
96771e36b1bSAlexander Aring 	.owner		   = THIS_MODULE,
96871e36b1bSAlexander Aring 	.release	   = ieee802154_sock_release,
96971e36b1bSAlexander Aring 	.bind		   = ieee802154_sock_bind,
97071e36b1bSAlexander Aring 	.connect	   = ieee802154_sock_connect,
97171e36b1bSAlexander Aring 	.socketpair	   = sock_no_socketpair,
97271e36b1bSAlexander Aring 	.accept		   = sock_no_accept,
97371e36b1bSAlexander Aring 	.getname	   = sock_no_getname,
97471e36b1bSAlexander Aring 	.poll		   = datagram_poll,
97571e36b1bSAlexander Aring 	.ioctl		   = ieee802154_sock_ioctl,
97671e36b1bSAlexander Aring 	.listen		   = sock_no_listen,
97771e36b1bSAlexander Aring 	.shutdown	   = sock_no_shutdown,
97871e36b1bSAlexander Aring 	.setsockopt	   = sock_common_setsockopt,
97971e36b1bSAlexander Aring 	.getsockopt	   = sock_common_getsockopt,
98071e36b1bSAlexander Aring 	.sendmsg	   = ieee802154_sock_sendmsg,
98171e36b1bSAlexander Aring 	.recvmsg	   = sock_common_recvmsg,
98271e36b1bSAlexander Aring 	.mmap		   = sock_no_mmap,
98371e36b1bSAlexander Aring 	.sendpage	   = sock_no_sendpage,
98471e36b1bSAlexander Aring #ifdef CONFIG_COMPAT
98571e36b1bSAlexander Aring 	.compat_setsockopt = compat_sock_common_setsockopt,
98671e36b1bSAlexander Aring 	.compat_getsockopt = compat_sock_common_getsockopt,
98771e36b1bSAlexander Aring #endif
98871e36b1bSAlexander Aring };
98971e36b1bSAlexander Aring 
99071e36b1bSAlexander Aring /* Create a socket. Initialise the socket, blank the addresses
99171e36b1bSAlexander Aring  * set the state.
99271e36b1bSAlexander Aring  */
99371e36b1bSAlexander Aring static int ieee802154_create(struct net *net, struct socket *sock,
99471e36b1bSAlexander Aring 			     int protocol, int kern)
99571e36b1bSAlexander Aring {
99671e36b1bSAlexander Aring 	struct sock *sk;
99771e36b1bSAlexander Aring 	int rc;
99871e36b1bSAlexander Aring 	struct proto *proto;
99971e36b1bSAlexander Aring 	const struct proto_ops *ops;
100071e36b1bSAlexander Aring 
100171e36b1bSAlexander Aring 	if (!net_eq(net, &init_net))
100271e36b1bSAlexander Aring 		return -EAFNOSUPPORT;
100371e36b1bSAlexander Aring 
100471e36b1bSAlexander Aring 	switch (sock->type) {
100571e36b1bSAlexander Aring 	case SOCK_RAW:
100671e36b1bSAlexander Aring 		proto = &ieee802154_raw_prot;
100771e36b1bSAlexander Aring 		ops = &ieee802154_raw_ops;
100871e36b1bSAlexander Aring 		break;
100971e36b1bSAlexander Aring 	case SOCK_DGRAM:
101071e36b1bSAlexander Aring 		proto = &ieee802154_dgram_prot;
101171e36b1bSAlexander Aring 		ops = &ieee802154_dgram_ops;
101271e36b1bSAlexander Aring 		break;
101371e36b1bSAlexander Aring 	default:
101471e36b1bSAlexander Aring 		rc = -ESOCKTNOSUPPORT;
101571e36b1bSAlexander Aring 		goto out;
101671e36b1bSAlexander Aring 	}
101771e36b1bSAlexander Aring 
101871e36b1bSAlexander Aring 	rc = -ENOMEM;
101911aa9c28SEric W. Biederman 	sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto, kern);
102071e36b1bSAlexander Aring 	if (!sk)
102171e36b1bSAlexander Aring 		goto out;
102271e36b1bSAlexander Aring 	rc = 0;
102371e36b1bSAlexander Aring 
102471e36b1bSAlexander Aring 	sock->ops = ops;
102571e36b1bSAlexander Aring 
102671e36b1bSAlexander Aring 	sock_init_data(sock, sk);
102771e36b1bSAlexander Aring 	/* FIXME: sk->sk_destruct */
102871e36b1bSAlexander Aring 	sk->sk_family = PF_IEEE802154;
102971e36b1bSAlexander Aring 
103071e36b1bSAlexander Aring 	/* Checksums on by default */
103171e36b1bSAlexander Aring 	sock_set_flag(sk, SOCK_ZAPPED);
103271e36b1bSAlexander Aring 
1033086c653fSCraig Gallek 	if (sk->sk_prot->hash) {
1034086c653fSCraig Gallek 		rc = sk->sk_prot->hash(sk);
1035086c653fSCraig Gallek 		if (rc) {
1036086c653fSCraig Gallek 			sk_common_release(sk);
1037086c653fSCraig Gallek 			goto out;
1038086c653fSCraig Gallek 		}
1039086c653fSCraig Gallek 	}
104071e36b1bSAlexander Aring 
104171e36b1bSAlexander Aring 	if (sk->sk_prot->init) {
104271e36b1bSAlexander Aring 		rc = sk->sk_prot->init(sk);
104371e36b1bSAlexander Aring 		if (rc)
104471e36b1bSAlexander Aring 			sk_common_release(sk);
104571e36b1bSAlexander Aring 	}
104671e36b1bSAlexander Aring out:
104771e36b1bSAlexander Aring 	return rc;
104871e36b1bSAlexander Aring }
104971e36b1bSAlexander Aring 
105071e36b1bSAlexander Aring static const struct net_proto_family ieee802154_family_ops = {
105171e36b1bSAlexander Aring 	.family		= PF_IEEE802154,
105271e36b1bSAlexander Aring 	.create		= ieee802154_create,
105371e36b1bSAlexander Aring 	.owner		= THIS_MODULE,
105471e36b1bSAlexander Aring };
105571e36b1bSAlexander Aring 
105671e36b1bSAlexander Aring static int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev,
105771e36b1bSAlexander Aring 			  struct packet_type *pt, struct net_device *orig_dev)
105871e36b1bSAlexander Aring {
105971e36b1bSAlexander Aring 	if (!netif_running(dev))
106071e36b1bSAlexander Aring 		goto drop;
106171e36b1bSAlexander Aring 	pr_debug("got frame, type %d, dev %p\n", dev->type, dev);
106271e36b1bSAlexander Aring #ifdef DEBUG
106371e36b1bSAlexander Aring 	print_hex_dump_bytes("ieee802154_rcv ",
106471e36b1bSAlexander Aring 			     DUMP_PREFIX_NONE, skb->data, skb->len);
106571e36b1bSAlexander Aring #endif
106671e36b1bSAlexander Aring 
106771e36b1bSAlexander Aring 	if (!net_eq(dev_net(dev), &init_net))
106871e36b1bSAlexander Aring 		goto drop;
106971e36b1bSAlexander Aring 
107071e36b1bSAlexander Aring 	ieee802154_raw_deliver(dev, skb);
107171e36b1bSAlexander Aring 
107271e36b1bSAlexander Aring 	if (dev->type != ARPHRD_IEEE802154)
107371e36b1bSAlexander Aring 		goto drop;
107471e36b1bSAlexander Aring 
107571e36b1bSAlexander Aring 	if (skb->pkt_type != PACKET_OTHERHOST)
107671e36b1bSAlexander Aring 		return ieee802154_dgram_deliver(dev, skb);
107771e36b1bSAlexander Aring 
107871e36b1bSAlexander Aring drop:
107971e36b1bSAlexander Aring 	kfree_skb(skb);
108071e36b1bSAlexander Aring 	return NET_RX_DROP;
108171e36b1bSAlexander Aring }
108271e36b1bSAlexander Aring 
108371e36b1bSAlexander Aring static struct packet_type ieee802154_packet_type = {
108471e36b1bSAlexander Aring 	.type = htons(ETH_P_IEEE802154),
108571e36b1bSAlexander Aring 	.func = ieee802154_rcv,
108671e36b1bSAlexander Aring };
108771e36b1bSAlexander Aring 
108871e36b1bSAlexander Aring static int __init af_ieee802154_init(void)
108971e36b1bSAlexander Aring {
109071e36b1bSAlexander Aring 	int rc = -EINVAL;
109171e36b1bSAlexander Aring 
109271e36b1bSAlexander Aring 	rc = proto_register(&ieee802154_raw_prot, 1);
109371e36b1bSAlexander Aring 	if (rc)
109471e36b1bSAlexander Aring 		goto out;
109571e36b1bSAlexander Aring 
109671e36b1bSAlexander Aring 	rc = proto_register(&ieee802154_dgram_prot, 1);
109771e36b1bSAlexander Aring 	if (rc)
109871e36b1bSAlexander Aring 		goto err_dgram;
109971e36b1bSAlexander Aring 
110071e36b1bSAlexander Aring 	/* Tell SOCKET that we are alive */
110171e36b1bSAlexander Aring 	rc = sock_register(&ieee802154_family_ops);
110271e36b1bSAlexander Aring 	if (rc)
110371e36b1bSAlexander Aring 		goto err_sock;
110471e36b1bSAlexander Aring 	dev_add_pack(&ieee802154_packet_type);
110571e36b1bSAlexander Aring 
110671e36b1bSAlexander Aring 	rc = 0;
110771e36b1bSAlexander Aring 	goto out;
110871e36b1bSAlexander Aring 
110971e36b1bSAlexander Aring err_sock:
111071e36b1bSAlexander Aring 	proto_unregister(&ieee802154_dgram_prot);
111171e36b1bSAlexander Aring err_dgram:
111271e36b1bSAlexander Aring 	proto_unregister(&ieee802154_raw_prot);
111371e36b1bSAlexander Aring out:
111471e36b1bSAlexander Aring 	return rc;
111571e36b1bSAlexander Aring }
111671e36b1bSAlexander Aring 
111771e36b1bSAlexander Aring static void __exit af_ieee802154_remove(void)
111871e36b1bSAlexander Aring {
111971e36b1bSAlexander Aring 	dev_remove_pack(&ieee802154_packet_type);
112071e36b1bSAlexander Aring 	sock_unregister(PF_IEEE802154);
112171e36b1bSAlexander Aring 	proto_unregister(&ieee802154_dgram_prot);
112271e36b1bSAlexander Aring 	proto_unregister(&ieee802154_raw_prot);
112371e36b1bSAlexander Aring }
112471e36b1bSAlexander Aring 
112571e36b1bSAlexander Aring module_init(af_ieee802154_init);
112671e36b1bSAlexander Aring module_exit(af_ieee802154_remove);
112771e36b1bSAlexander Aring 
112871e36b1bSAlexander Aring MODULE_LICENSE("GPL");
112971e36b1bSAlexander Aring MODULE_ALIAS_NETPROTO(PF_IEEE802154);
1130