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