18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * IEEE802154.4 socket interface
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright 2007, 2008 Siemens AG
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Written by:
88c2ecf20Sopenharmony_ci * Sergey Lapin <slapin@ossfans.org>
98c2ecf20Sopenharmony_ci * Maxim Gorbachyov <maxim.gorbachev@siemens.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/net.h>
138c2ecf20Sopenharmony_ci#include <linux/capability.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/if_arp.h>
168c2ecf20Sopenharmony_ci#include <linux/if.h>
178c2ecf20Sopenharmony_ci#include <linux/termios.h>	/* For TIOCOUTQ/INQ */
188c2ecf20Sopenharmony_ci#include <linux/list.h>
198c2ecf20Sopenharmony_ci#include <linux/slab.h>
208c2ecf20Sopenharmony_ci#include <linux/socket.h>
218c2ecf20Sopenharmony_ci#include <net/datalink.h>
228c2ecf20Sopenharmony_ci#include <net/psnap.h>
238c2ecf20Sopenharmony_ci#include <net/sock.h>
248c2ecf20Sopenharmony_ci#include <net/tcp_states.h>
258c2ecf20Sopenharmony_ci#include <net/route.h>
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_ci#include <net/af_ieee802154.h>
288c2ecf20Sopenharmony_ci#include <net/ieee802154_netdev.h>
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci/* Utility function for families */
318c2ecf20Sopenharmony_cistatic struct net_device*
328c2ecf20Sopenharmony_ciieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	struct net_device *dev = NULL;
358c2ecf20Sopenharmony_ci	struct net_device *tmp;
368c2ecf20Sopenharmony_ci	__le16 pan_id, short_addr;
378c2ecf20Sopenharmony_ci	u8 hwaddr[IEEE802154_ADDR_LEN];
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	switch (addr->mode) {
408c2ecf20Sopenharmony_ci	case IEEE802154_ADDR_LONG:
418c2ecf20Sopenharmony_ci		ieee802154_devaddr_to_raw(hwaddr, addr->extended_addr);
428c2ecf20Sopenharmony_ci		rcu_read_lock();
438c2ecf20Sopenharmony_ci		dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, hwaddr);
448c2ecf20Sopenharmony_ci		if (dev)
458c2ecf20Sopenharmony_ci			dev_hold(dev);
468c2ecf20Sopenharmony_ci		rcu_read_unlock();
478c2ecf20Sopenharmony_ci		break;
488c2ecf20Sopenharmony_ci	case IEEE802154_ADDR_SHORT:
498c2ecf20Sopenharmony_ci		if (addr->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST) ||
508c2ecf20Sopenharmony_ci		    addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||
518c2ecf20Sopenharmony_ci		    addr->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST))
528c2ecf20Sopenharmony_ci			break;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci		rtnl_lock();
558c2ecf20Sopenharmony_ci
568c2ecf20Sopenharmony_ci		for_each_netdev(net, tmp) {
578c2ecf20Sopenharmony_ci			if (tmp->type != ARPHRD_IEEE802154)
588c2ecf20Sopenharmony_ci				continue;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci			pan_id = tmp->ieee802154_ptr->pan_id;
618c2ecf20Sopenharmony_ci			short_addr = tmp->ieee802154_ptr->short_addr;
628c2ecf20Sopenharmony_ci			if (pan_id == addr->pan_id &&
638c2ecf20Sopenharmony_ci			    short_addr == addr->short_addr) {
648c2ecf20Sopenharmony_ci				dev = tmp;
658c2ecf20Sopenharmony_ci				dev_hold(dev);
668c2ecf20Sopenharmony_ci				break;
678c2ecf20Sopenharmony_ci			}
688c2ecf20Sopenharmony_ci		}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci		rtnl_unlock();
718c2ecf20Sopenharmony_ci		break;
728c2ecf20Sopenharmony_ci	default:
738c2ecf20Sopenharmony_ci		pr_warn("Unsupported ieee802154 address type: %d\n",
748c2ecf20Sopenharmony_ci			addr->mode);
758c2ecf20Sopenharmony_ci		break;
768c2ecf20Sopenharmony_ci	}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	return dev;
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic int ieee802154_sock_release(struct socket *sock)
828c2ecf20Sopenharmony_ci{
838c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (sk) {
868c2ecf20Sopenharmony_ci		sock->sk = NULL;
878c2ecf20Sopenharmony_ci		sk->sk_prot->close(sk, 0);
888c2ecf20Sopenharmony_ci	}
898c2ecf20Sopenharmony_ci	return 0;
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cistatic int ieee802154_sock_sendmsg(struct socket *sock, struct msghdr *msg,
938c2ecf20Sopenharmony_ci				   size_t len)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci	return sk->sk_prot->sendmsg(sk, msg, len);
988c2ecf20Sopenharmony_ci}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_cistatic int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr,
1018c2ecf20Sopenharmony_ci				int addr_len)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	if (sk->sk_prot->bind)
1068c2ecf20Sopenharmony_ci		return sk->sk_prot->bind(sk, uaddr, addr_len);
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	return sock_no_bind(sock, uaddr, addr_len);
1098c2ecf20Sopenharmony_ci}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_cistatic int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr,
1128c2ecf20Sopenharmony_ci				   int addr_len, int flags)
1138c2ecf20Sopenharmony_ci{
1148c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	if (addr_len < sizeof(uaddr->sa_family))
1178c2ecf20Sopenharmony_ci		return -EINVAL;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	if (uaddr->sa_family == AF_UNSPEC)
1208c2ecf20Sopenharmony_ci		return sk->sk_prot->disconnect(sk, flags);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	return sk->sk_prot->connect(sk, uaddr, addr_len);
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistatic int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg,
1268c2ecf20Sopenharmony_ci				unsigned int cmd)
1278c2ecf20Sopenharmony_ci{
1288c2ecf20Sopenharmony_ci	struct ifreq ifr;
1298c2ecf20Sopenharmony_ci	int ret = -ENOIOCTLCMD;
1308c2ecf20Sopenharmony_ci	struct net_device *dev;
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	if (copy_from_user(&ifr, arg, sizeof(struct ifreq)))
1338c2ecf20Sopenharmony_ci		return -EFAULT;
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	ifr.ifr_name[IFNAMSIZ-1] = 0;
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci	dev_load(sock_net(sk), ifr.ifr_name);
1388c2ecf20Sopenharmony_ci	dev = dev_get_by_name(sock_net(sk), ifr.ifr_name);
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	if (!dev)
1418c2ecf20Sopenharmony_ci		return -ENODEV;
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_ci	if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl)
1448c2ecf20Sopenharmony_ci		ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd);
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
1478c2ecf20Sopenharmony_ci		ret = -EFAULT;
1488c2ecf20Sopenharmony_ci	dev_put(dev);
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	return ret;
1518c2ecf20Sopenharmony_ci}
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_cistatic int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd,
1548c2ecf20Sopenharmony_ci				 unsigned long arg)
1558c2ecf20Sopenharmony_ci{
1568c2ecf20Sopenharmony_ci	struct sock *sk = sock->sk;
1578c2ecf20Sopenharmony_ci
1588c2ecf20Sopenharmony_ci	switch (cmd) {
1598c2ecf20Sopenharmony_ci	case SIOCGIFADDR:
1608c2ecf20Sopenharmony_ci	case SIOCSIFADDR:
1618c2ecf20Sopenharmony_ci		return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg,
1628c2ecf20Sopenharmony_ci				cmd);
1638c2ecf20Sopenharmony_ci	default:
1648c2ecf20Sopenharmony_ci		if (!sk->sk_prot->ioctl)
1658c2ecf20Sopenharmony_ci			return -ENOIOCTLCMD;
1668c2ecf20Sopenharmony_ci		return sk->sk_prot->ioctl(sk, cmd, arg);
1678c2ecf20Sopenharmony_ci	}
1688c2ecf20Sopenharmony_ci}
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci/* RAW Sockets (802.15.4 created in userspace) */
1718c2ecf20Sopenharmony_cistatic HLIST_HEAD(raw_head);
1728c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(raw_lock);
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_cistatic int raw_hash(struct sock *sk)
1758c2ecf20Sopenharmony_ci{
1768c2ecf20Sopenharmony_ci	write_lock_bh(&raw_lock);
1778c2ecf20Sopenharmony_ci	sk_add_node(sk, &raw_head);
1788c2ecf20Sopenharmony_ci	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
1798c2ecf20Sopenharmony_ci	write_unlock_bh(&raw_lock);
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	return 0;
1828c2ecf20Sopenharmony_ci}
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_cistatic void raw_unhash(struct sock *sk)
1858c2ecf20Sopenharmony_ci{
1868c2ecf20Sopenharmony_ci	write_lock_bh(&raw_lock);
1878c2ecf20Sopenharmony_ci	if (sk_del_node_init(sk))
1888c2ecf20Sopenharmony_ci		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
1898c2ecf20Sopenharmony_ci	write_unlock_bh(&raw_lock);
1908c2ecf20Sopenharmony_ci}
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cistatic void raw_close(struct sock *sk, long timeout)
1938c2ecf20Sopenharmony_ci{
1948c2ecf20Sopenharmony_ci	sk_common_release(sk);
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic int raw_bind(struct sock *sk, struct sockaddr *_uaddr, int len)
1988c2ecf20Sopenharmony_ci{
1998c2ecf20Sopenharmony_ci	struct ieee802154_addr addr;
2008c2ecf20Sopenharmony_ci	struct sockaddr_ieee802154 *uaddr = (struct sockaddr_ieee802154 *)_uaddr;
2018c2ecf20Sopenharmony_ci	int err = 0;
2028c2ecf20Sopenharmony_ci	struct net_device *dev = NULL;
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci	err = ieee802154_sockaddr_check_size(uaddr, len);
2058c2ecf20Sopenharmony_ci	if (err < 0)
2068c2ecf20Sopenharmony_ci		return err;
2078c2ecf20Sopenharmony_ci
2088c2ecf20Sopenharmony_ci	uaddr = (struct sockaddr_ieee802154 *)_uaddr;
2098c2ecf20Sopenharmony_ci	if (uaddr->family != AF_IEEE802154)
2108c2ecf20Sopenharmony_ci		return -EINVAL;
2118c2ecf20Sopenharmony_ci
2128c2ecf20Sopenharmony_ci	lock_sock(sk);
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	ieee802154_addr_from_sa(&addr, &uaddr->addr);
2158c2ecf20Sopenharmony_ci	dev = ieee802154_get_dev(sock_net(sk), &addr);
2168c2ecf20Sopenharmony_ci	if (!dev) {
2178c2ecf20Sopenharmony_ci		err = -ENODEV;
2188c2ecf20Sopenharmony_ci		goto out;
2198c2ecf20Sopenharmony_ci	}
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	sk->sk_bound_dev_if = dev->ifindex;
2228c2ecf20Sopenharmony_ci	sk_dst_reset(sk);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	dev_put(dev);
2258c2ecf20Sopenharmony_ciout:
2268c2ecf20Sopenharmony_ci	release_sock(sk);
2278c2ecf20Sopenharmony_ci
2288c2ecf20Sopenharmony_ci	return err;
2298c2ecf20Sopenharmony_ci}
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_cistatic int raw_connect(struct sock *sk, struct sockaddr *uaddr,
2328c2ecf20Sopenharmony_ci		       int addr_len)
2338c2ecf20Sopenharmony_ci{
2348c2ecf20Sopenharmony_ci	return -ENOTSUPP;
2358c2ecf20Sopenharmony_ci}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_cistatic int raw_disconnect(struct sock *sk, int flags)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	return 0;
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
2438c2ecf20Sopenharmony_ci{
2448c2ecf20Sopenharmony_ci	struct net_device *dev;
2458c2ecf20Sopenharmony_ci	unsigned int mtu;
2468c2ecf20Sopenharmony_ci	struct sk_buff *skb;
2478c2ecf20Sopenharmony_ci	int hlen, tlen;
2488c2ecf20Sopenharmony_ci	int err;
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci	if (msg->msg_flags & MSG_OOB) {
2518c2ecf20Sopenharmony_ci		pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
2528c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
2538c2ecf20Sopenharmony_ci	}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	lock_sock(sk);
2568c2ecf20Sopenharmony_ci	if (!sk->sk_bound_dev_if)
2578c2ecf20Sopenharmony_ci		dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
2588c2ecf20Sopenharmony_ci	else
2598c2ecf20Sopenharmony_ci		dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);
2608c2ecf20Sopenharmony_ci	release_sock(sk);
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	if (!dev) {
2638c2ecf20Sopenharmony_ci		pr_debug("no dev\n");
2648c2ecf20Sopenharmony_ci		err = -ENXIO;
2658c2ecf20Sopenharmony_ci		goto out;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	mtu = IEEE802154_MTU;
2698c2ecf20Sopenharmony_ci	pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
2708c2ecf20Sopenharmony_ci
2718c2ecf20Sopenharmony_ci	if (size > mtu) {
2728c2ecf20Sopenharmony_ci		pr_debug("size = %zu, mtu = %u\n", size, mtu);
2738c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
2748c2ecf20Sopenharmony_ci		goto out_dev;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci	if (!size) {
2778c2ecf20Sopenharmony_ci		err = 0;
2788c2ecf20Sopenharmony_ci		goto out_dev;
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	hlen = LL_RESERVED_SPACE(dev);
2828c2ecf20Sopenharmony_ci	tlen = dev->needed_tailroom;
2838c2ecf20Sopenharmony_ci	skb = sock_alloc_send_skb(sk, hlen + tlen + size,
2848c2ecf20Sopenharmony_ci				  msg->msg_flags & MSG_DONTWAIT, &err);
2858c2ecf20Sopenharmony_ci	if (!skb)
2868c2ecf20Sopenharmony_ci		goto out_dev;
2878c2ecf20Sopenharmony_ci
2888c2ecf20Sopenharmony_ci	skb_reserve(skb, hlen);
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	skb_reset_mac_header(skb);
2918c2ecf20Sopenharmony_ci	skb_reset_network_header(skb);
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	err = memcpy_from_msg(skb_put(skb, size), msg, size);
2948c2ecf20Sopenharmony_ci	if (err < 0)
2958c2ecf20Sopenharmony_ci		goto out_skb;
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	skb->dev = dev;
2988c2ecf20Sopenharmony_ci	skb->protocol = htons(ETH_P_IEEE802154);
2998c2ecf20Sopenharmony_ci
3008c2ecf20Sopenharmony_ci	err = dev_queue_xmit(skb);
3018c2ecf20Sopenharmony_ci	if (err > 0)
3028c2ecf20Sopenharmony_ci		err = net_xmit_errno(err);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci	dev_put(dev);
3058c2ecf20Sopenharmony_ci
3068c2ecf20Sopenharmony_ci	return err ?: size;
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ciout_skb:
3098c2ecf20Sopenharmony_ci	kfree_skb(skb);
3108c2ecf20Sopenharmony_ciout_dev:
3118c2ecf20Sopenharmony_ci	dev_put(dev);
3128c2ecf20Sopenharmony_ciout:
3138c2ecf20Sopenharmony_ci	return err;
3148c2ecf20Sopenharmony_ci}
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_cistatic int raw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
3178c2ecf20Sopenharmony_ci		       int noblock, int flags, int *addr_len)
3188c2ecf20Sopenharmony_ci{
3198c2ecf20Sopenharmony_ci	size_t copied = 0;
3208c2ecf20Sopenharmony_ci	int err = -EOPNOTSUPP;
3218c2ecf20Sopenharmony_ci	struct sk_buff *skb;
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci	skb = skb_recv_datagram(sk, flags, noblock, &err);
3248c2ecf20Sopenharmony_ci	if (!skb)
3258c2ecf20Sopenharmony_ci		goto out;
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_ci	copied = skb->len;
3288c2ecf20Sopenharmony_ci	if (len < copied) {
3298c2ecf20Sopenharmony_ci		msg->msg_flags |= MSG_TRUNC;
3308c2ecf20Sopenharmony_ci		copied = len;
3318c2ecf20Sopenharmony_ci	}
3328c2ecf20Sopenharmony_ci
3338c2ecf20Sopenharmony_ci	err = skb_copy_datagram_msg(skb, 0, msg, copied);
3348c2ecf20Sopenharmony_ci	if (err)
3358c2ecf20Sopenharmony_ci		goto done;
3368c2ecf20Sopenharmony_ci
3378c2ecf20Sopenharmony_ci	sock_recv_ts_and_drops(msg, sk, skb);
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci	if (flags & MSG_TRUNC)
3408c2ecf20Sopenharmony_ci		copied = skb->len;
3418c2ecf20Sopenharmony_cidone:
3428c2ecf20Sopenharmony_ci	skb_free_datagram(sk, skb);
3438c2ecf20Sopenharmony_ciout:
3448c2ecf20Sopenharmony_ci	if (err)
3458c2ecf20Sopenharmony_ci		return err;
3468c2ecf20Sopenharmony_ci	return copied;
3478c2ecf20Sopenharmony_ci}
3488c2ecf20Sopenharmony_ci
3498c2ecf20Sopenharmony_cistatic int raw_rcv_skb(struct sock *sk, struct sk_buff *skb)
3508c2ecf20Sopenharmony_ci{
3518c2ecf20Sopenharmony_ci	skb = skb_share_check(skb, GFP_ATOMIC);
3528c2ecf20Sopenharmony_ci	if (!skb)
3538c2ecf20Sopenharmony_ci		return NET_RX_DROP;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	if (sock_queue_rcv_skb(sk, skb) < 0) {
3568c2ecf20Sopenharmony_ci		kfree_skb(skb);
3578c2ecf20Sopenharmony_ci		return NET_RX_DROP;
3588c2ecf20Sopenharmony_ci	}
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	return NET_RX_SUCCESS;
3618c2ecf20Sopenharmony_ci}
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_cistatic void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb)
3648c2ecf20Sopenharmony_ci{
3658c2ecf20Sopenharmony_ci	struct sock *sk;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci	read_lock(&raw_lock);
3688c2ecf20Sopenharmony_ci	sk_for_each(sk, &raw_head) {
3698c2ecf20Sopenharmony_ci		bh_lock_sock(sk);
3708c2ecf20Sopenharmony_ci		if (!sk->sk_bound_dev_if ||
3718c2ecf20Sopenharmony_ci		    sk->sk_bound_dev_if == dev->ifindex) {
3728c2ecf20Sopenharmony_ci			struct sk_buff *clone;
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci			clone = skb_clone(skb, GFP_ATOMIC);
3758c2ecf20Sopenharmony_ci			if (clone)
3768c2ecf20Sopenharmony_ci				raw_rcv_skb(sk, clone);
3778c2ecf20Sopenharmony_ci		}
3788c2ecf20Sopenharmony_ci		bh_unlock_sock(sk);
3798c2ecf20Sopenharmony_ci	}
3808c2ecf20Sopenharmony_ci	read_unlock(&raw_lock);
3818c2ecf20Sopenharmony_ci}
3828c2ecf20Sopenharmony_ci
3838c2ecf20Sopenharmony_cistatic int raw_getsockopt(struct sock *sk, int level, int optname,
3848c2ecf20Sopenharmony_ci			  char __user *optval, int __user *optlen)
3858c2ecf20Sopenharmony_ci{
3868c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
3878c2ecf20Sopenharmony_ci}
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_cistatic int raw_setsockopt(struct sock *sk, int level, int optname,
3908c2ecf20Sopenharmony_ci			  sockptr_t optval, unsigned int optlen)
3918c2ecf20Sopenharmony_ci{
3928c2ecf20Sopenharmony_ci	return -EOPNOTSUPP;
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_cistatic struct proto ieee802154_raw_prot = {
3968c2ecf20Sopenharmony_ci	.name		= "IEEE-802.15.4-RAW",
3978c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
3988c2ecf20Sopenharmony_ci	.obj_size	= sizeof(struct sock),
3998c2ecf20Sopenharmony_ci	.close		= raw_close,
4008c2ecf20Sopenharmony_ci	.bind		= raw_bind,
4018c2ecf20Sopenharmony_ci	.sendmsg	= raw_sendmsg,
4028c2ecf20Sopenharmony_ci	.recvmsg	= raw_recvmsg,
4038c2ecf20Sopenharmony_ci	.hash		= raw_hash,
4048c2ecf20Sopenharmony_ci	.unhash		= raw_unhash,
4058c2ecf20Sopenharmony_ci	.connect	= raw_connect,
4068c2ecf20Sopenharmony_ci	.disconnect	= raw_disconnect,
4078c2ecf20Sopenharmony_ci	.getsockopt	= raw_getsockopt,
4088c2ecf20Sopenharmony_ci	.setsockopt	= raw_setsockopt,
4098c2ecf20Sopenharmony_ci};
4108c2ecf20Sopenharmony_ci
4118c2ecf20Sopenharmony_cistatic const struct proto_ops ieee802154_raw_ops = {
4128c2ecf20Sopenharmony_ci	.family		   = PF_IEEE802154,
4138c2ecf20Sopenharmony_ci	.owner		   = THIS_MODULE,
4148c2ecf20Sopenharmony_ci	.release	   = ieee802154_sock_release,
4158c2ecf20Sopenharmony_ci	.bind		   = ieee802154_sock_bind,
4168c2ecf20Sopenharmony_ci	.connect	   = ieee802154_sock_connect,
4178c2ecf20Sopenharmony_ci	.socketpair	   = sock_no_socketpair,
4188c2ecf20Sopenharmony_ci	.accept		   = sock_no_accept,
4198c2ecf20Sopenharmony_ci	.getname	   = sock_no_getname,
4208c2ecf20Sopenharmony_ci	.poll		   = datagram_poll,
4218c2ecf20Sopenharmony_ci	.ioctl		   = ieee802154_sock_ioctl,
4228c2ecf20Sopenharmony_ci	.gettstamp	   = sock_gettstamp,
4238c2ecf20Sopenharmony_ci	.listen		   = sock_no_listen,
4248c2ecf20Sopenharmony_ci	.shutdown	   = sock_no_shutdown,
4258c2ecf20Sopenharmony_ci	.setsockopt	   = sock_common_setsockopt,
4268c2ecf20Sopenharmony_ci	.getsockopt	   = sock_common_getsockopt,
4278c2ecf20Sopenharmony_ci	.sendmsg	   = ieee802154_sock_sendmsg,
4288c2ecf20Sopenharmony_ci	.recvmsg	   = sock_common_recvmsg,
4298c2ecf20Sopenharmony_ci	.mmap		   = sock_no_mmap,
4308c2ecf20Sopenharmony_ci	.sendpage	   = sock_no_sendpage,
4318c2ecf20Sopenharmony_ci};
4328c2ecf20Sopenharmony_ci
4338c2ecf20Sopenharmony_ci/* DGRAM Sockets (802.15.4 dataframes) */
4348c2ecf20Sopenharmony_cistatic HLIST_HEAD(dgram_head);
4358c2ecf20Sopenharmony_cistatic DEFINE_RWLOCK(dgram_lock);
4368c2ecf20Sopenharmony_ci
4378c2ecf20Sopenharmony_cistruct dgram_sock {
4388c2ecf20Sopenharmony_ci	struct sock sk;
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	struct ieee802154_addr src_addr;
4418c2ecf20Sopenharmony_ci	struct ieee802154_addr dst_addr;
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	unsigned int bound:1;
4448c2ecf20Sopenharmony_ci	unsigned int connected:1;
4458c2ecf20Sopenharmony_ci	unsigned int want_ack:1;
4468c2ecf20Sopenharmony_ci	unsigned int want_lqi:1;
4478c2ecf20Sopenharmony_ci	unsigned int secen:1;
4488c2ecf20Sopenharmony_ci	unsigned int secen_override:1;
4498c2ecf20Sopenharmony_ci	unsigned int seclevel:3;
4508c2ecf20Sopenharmony_ci	unsigned int seclevel_override:1;
4518c2ecf20Sopenharmony_ci};
4528c2ecf20Sopenharmony_ci
4538c2ecf20Sopenharmony_cistatic inline struct dgram_sock *dgram_sk(const struct sock *sk)
4548c2ecf20Sopenharmony_ci{
4558c2ecf20Sopenharmony_ci	return container_of(sk, struct dgram_sock, sk);
4568c2ecf20Sopenharmony_ci}
4578c2ecf20Sopenharmony_ci
4588c2ecf20Sopenharmony_cistatic int dgram_hash(struct sock *sk)
4598c2ecf20Sopenharmony_ci{
4608c2ecf20Sopenharmony_ci	write_lock_bh(&dgram_lock);
4618c2ecf20Sopenharmony_ci	sk_add_node(sk, &dgram_head);
4628c2ecf20Sopenharmony_ci	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
4638c2ecf20Sopenharmony_ci	write_unlock_bh(&dgram_lock);
4648c2ecf20Sopenharmony_ci
4658c2ecf20Sopenharmony_ci	return 0;
4668c2ecf20Sopenharmony_ci}
4678c2ecf20Sopenharmony_ci
4688c2ecf20Sopenharmony_cistatic void dgram_unhash(struct sock *sk)
4698c2ecf20Sopenharmony_ci{
4708c2ecf20Sopenharmony_ci	write_lock_bh(&dgram_lock);
4718c2ecf20Sopenharmony_ci	if (sk_del_node_init(sk))
4728c2ecf20Sopenharmony_ci		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
4738c2ecf20Sopenharmony_ci	write_unlock_bh(&dgram_lock);
4748c2ecf20Sopenharmony_ci}
4758c2ecf20Sopenharmony_ci
4768c2ecf20Sopenharmony_cistatic int dgram_init(struct sock *sk)
4778c2ecf20Sopenharmony_ci{
4788c2ecf20Sopenharmony_ci	struct dgram_sock *ro = dgram_sk(sk);
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci	ro->want_ack = 1;
4818c2ecf20Sopenharmony_ci	ro->want_lqi = 0;
4828c2ecf20Sopenharmony_ci	return 0;
4838c2ecf20Sopenharmony_ci}
4848c2ecf20Sopenharmony_ci
4858c2ecf20Sopenharmony_cistatic void dgram_close(struct sock *sk, long timeout)
4868c2ecf20Sopenharmony_ci{
4878c2ecf20Sopenharmony_ci	sk_common_release(sk);
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ci
4908c2ecf20Sopenharmony_cistatic int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len)
4918c2ecf20Sopenharmony_ci{
4928c2ecf20Sopenharmony_ci	struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
4938c2ecf20Sopenharmony_ci	struct ieee802154_addr haddr;
4948c2ecf20Sopenharmony_ci	struct dgram_sock *ro = dgram_sk(sk);
4958c2ecf20Sopenharmony_ci	int err = -EINVAL;
4968c2ecf20Sopenharmony_ci	struct net_device *dev;
4978c2ecf20Sopenharmony_ci
4988c2ecf20Sopenharmony_ci	lock_sock(sk);
4998c2ecf20Sopenharmony_ci
5008c2ecf20Sopenharmony_ci	ro->bound = 0;
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci	err = ieee802154_sockaddr_check_size(addr, len);
5038c2ecf20Sopenharmony_ci	if (err < 0)
5048c2ecf20Sopenharmony_ci		goto out;
5058c2ecf20Sopenharmony_ci
5068c2ecf20Sopenharmony_ci	if (addr->family != AF_IEEE802154) {
5078c2ecf20Sopenharmony_ci		err = -EINVAL;
5088c2ecf20Sopenharmony_ci		goto out;
5098c2ecf20Sopenharmony_ci	}
5108c2ecf20Sopenharmony_ci
5118c2ecf20Sopenharmony_ci	ieee802154_addr_from_sa(&haddr, &addr->addr);
5128c2ecf20Sopenharmony_ci	dev = ieee802154_get_dev(sock_net(sk), &haddr);
5138c2ecf20Sopenharmony_ci	if (!dev) {
5148c2ecf20Sopenharmony_ci		err = -ENODEV;
5158c2ecf20Sopenharmony_ci		goto out;
5168c2ecf20Sopenharmony_ci	}
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_ci	if (dev->type != ARPHRD_IEEE802154) {
5198c2ecf20Sopenharmony_ci		err = -ENODEV;
5208c2ecf20Sopenharmony_ci		goto out_put;
5218c2ecf20Sopenharmony_ci	}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_ci	ro->src_addr = haddr;
5248c2ecf20Sopenharmony_ci
5258c2ecf20Sopenharmony_ci	ro->bound = 1;
5268c2ecf20Sopenharmony_ci	err = 0;
5278c2ecf20Sopenharmony_ciout_put:
5288c2ecf20Sopenharmony_ci	dev_put(dev);
5298c2ecf20Sopenharmony_ciout:
5308c2ecf20Sopenharmony_ci	release_sock(sk);
5318c2ecf20Sopenharmony_ci
5328c2ecf20Sopenharmony_ci	return err;
5338c2ecf20Sopenharmony_ci}
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_cistatic int dgram_ioctl(struct sock *sk, int cmd, unsigned long arg)
5368c2ecf20Sopenharmony_ci{
5378c2ecf20Sopenharmony_ci	switch (cmd) {
5388c2ecf20Sopenharmony_ci	case SIOCOUTQ:
5398c2ecf20Sopenharmony_ci	{
5408c2ecf20Sopenharmony_ci		int amount = sk_wmem_alloc_get(sk);
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci		return put_user(amount, (int __user *)arg);
5438c2ecf20Sopenharmony_ci	}
5448c2ecf20Sopenharmony_ci
5458c2ecf20Sopenharmony_ci	case SIOCINQ:
5468c2ecf20Sopenharmony_ci	{
5478c2ecf20Sopenharmony_ci		struct sk_buff *skb;
5488c2ecf20Sopenharmony_ci		unsigned long amount;
5498c2ecf20Sopenharmony_ci
5508c2ecf20Sopenharmony_ci		amount = 0;
5518c2ecf20Sopenharmony_ci		spin_lock_bh(&sk->sk_receive_queue.lock);
5528c2ecf20Sopenharmony_ci		skb = skb_peek(&sk->sk_receive_queue);
5538c2ecf20Sopenharmony_ci		if (skb) {
5548c2ecf20Sopenharmony_ci			/* We will only return the amount
5558c2ecf20Sopenharmony_ci			 * of this packet since that is all
5568c2ecf20Sopenharmony_ci			 * that will be read.
5578c2ecf20Sopenharmony_ci			 */
5588c2ecf20Sopenharmony_ci			amount = skb->len - ieee802154_hdr_length(skb);
5598c2ecf20Sopenharmony_ci		}
5608c2ecf20Sopenharmony_ci		spin_unlock_bh(&sk->sk_receive_queue.lock);
5618c2ecf20Sopenharmony_ci		return put_user(amount, (int __user *)arg);
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci	}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_ci	return -ENOIOCTLCMD;
5668c2ecf20Sopenharmony_ci}
5678c2ecf20Sopenharmony_ci
5688c2ecf20Sopenharmony_ci/* FIXME: autobind */
5698c2ecf20Sopenharmony_cistatic int dgram_connect(struct sock *sk, struct sockaddr *uaddr,
5708c2ecf20Sopenharmony_ci			 int len)
5718c2ecf20Sopenharmony_ci{
5728c2ecf20Sopenharmony_ci	struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;
5738c2ecf20Sopenharmony_ci	struct dgram_sock *ro = dgram_sk(sk);
5748c2ecf20Sopenharmony_ci	int err = 0;
5758c2ecf20Sopenharmony_ci
5768c2ecf20Sopenharmony_ci	err = ieee802154_sockaddr_check_size(addr, len);
5778c2ecf20Sopenharmony_ci	if (err < 0)
5788c2ecf20Sopenharmony_ci		return err;
5798c2ecf20Sopenharmony_ci
5808c2ecf20Sopenharmony_ci	if (addr->family != AF_IEEE802154)
5818c2ecf20Sopenharmony_ci		return -EINVAL;
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_ci	lock_sock(sk);
5848c2ecf20Sopenharmony_ci
5858c2ecf20Sopenharmony_ci	if (!ro->bound) {
5868c2ecf20Sopenharmony_ci		err = -ENETUNREACH;
5878c2ecf20Sopenharmony_ci		goto out;
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci
5908c2ecf20Sopenharmony_ci	ieee802154_addr_from_sa(&ro->dst_addr, &addr->addr);
5918c2ecf20Sopenharmony_ci	ro->connected = 1;
5928c2ecf20Sopenharmony_ci
5938c2ecf20Sopenharmony_ciout:
5948c2ecf20Sopenharmony_ci	release_sock(sk);
5958c2ecf20Sopenharmony_ci	return err;
5968c2ecf20Sopenharmony_ci}
5978c2ecf20Sopenharmony_ci
5988c2ecf20Sopenharmony_cistatic int dgram_disconnect(struct sock *sk, int flags)
5998c2ecf20Sopenharmony_ci{
6008c2ecf20Sopenharmony_ci	struct dgram_sock *ro = dgram_sk(sk);
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_ci	lock_sock(sk);
6038c2ecf20Sopenharmony_ci	ro->connected = 0;
6048c2ecf20Sopenharmony_ci	release_sock(sk);
6058c2ecf20Sopenharmony_ci
6068c2ecf20Sopenharmony_ci	return 0;
6078c2ecf20Sopenharmony_ci}
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_cistatic int dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size)
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci	struct net_device *dev;
6128c2ecf20Sopenharmony_ci	unsigned int mtu;
6138c2ecf20Sopenharmony_ci	struct sk_buff *skb;
6148c2ecf20Sopenharmony_ci	struct ieee802154_mac_cb *cb;
6158c2ecf20Sopenharmony_ci	struct dgram_sock *ro = dgram_sk(sk);
6168c2ecf20Sopenharmony_ci	struct ieee802154_addr dst_addr;
6178c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_ieee802154*, daddr, msg->msg_name);
6188c2ecf20Sopenharmony_ci	int hlen, tlen;
6198c2ecf20Sopenharmony_ci	int err;
6208c2ecf20Sopenharmony_ci
6218c2ecf20Sopenharmony_ci	if (msg->msg_flags & MSG_OOB) {
6228c2ecf20Sopenharmony_ci		pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);
6238c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
6248c2ecf20Sopenharmony_ci	}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_ci	if (msg->msg_name) {
6278c2ecf20Sopenharmony_ci		if (ro->connected)
6288c2ecf20Sopenharmony_ci			return -EISCONN;
6298c2ecf20Sopenharmony_ci		if (msg->msg_namelen < IEEE802154_MIN_NAMELEN)
6308c2ecf20Sopenharmony_ci			return -EINVAL;
6318c2ecf20Sopenharmony_ci		err = ieee802154_sockaddr_check_size(daddr, msg->msg_namelen);
6328c2ecf20Sopenharmony_ci		if (err < 0)
6338c2ecf20Sopenharmony_ci			return err;
6348c2ecf20Sopenharmony_ci		ieee802154_addr_from_sa(&dst_addr, &daddr->addr);
6358c2ecf20Sopenharmony_ci	} else {
6368c2ecf20Sopenharmony_ci		if (!ro->connected)
6378c2ecf20Sopenharmony_ci			return -EDESTADDRREQ;
6388c2ecf20Sopenharmony_ci		dst_addr = ro->dst_addr;
6398c2ecf20Sopenharmony_ci	}
6408c2ecf20Sopenharmony_ci
6418c2ecf20Sopenharmony_ci	if (!ro->bound)
6428c2ecf20Sopenharmony_ci		dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);
6438c2ecf20Sopenharmony_ci	else
6448c2ecf20Sopenharmony_ci		dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr);
6458c2ecf20Sopenharmony_ci
6468c2ecf20Sopenharmony_ci	if (!dev) {
6478c2ecf20Sopenharmony_ci		pr_debug("no dev\n");
6488c2ecf20Sopenharmony_ci		err = -ENXIO;
6498c2ecf20Sopenharmony_ci		goto out;
6508c2ecf20Sopenharmony_ci	}
6518c2ecf20Sopenharmony_ci	mtu = IEEE802154_MTU;
6528c2ecf20Sopenharmony_ci	pr_debug("name = %s, mtu = %u\n", dev->name, mtu);
6538c2ecf20Sopenharmony_ci
6548c2ecf20Sopenharmony_ci	if (size > mtu) {
6558c2ecf20Sopenharmony_ci		pr_debug("size = %zu, mtu = %u\n", size, mtu);
6568c2ecf20Sopenharmony_ci		err = -EMSGSIZE;
6578c2ecf20Sopenharmony_ci		goto out_dev;
6588c2ecf20Sopenharmony_ci	}
6598c2ecf20Sopenharmony_ci
6608c2ecf20Sopenharmony_ci	hlen = LL_RESERVED_SPACE(dev);
6618c2ecf20Sopenharmony_ci	tlen = dev->needed_tailroom;
6628c2ecf20Sopenharmony_ci	skb = sock_alloc_send_skb(sk, hlen + tlen + size,
6638c2ecf20Sopenharmony_ci				  msg->msg_flags & MSG_DONTWAIT,
6648c2ecf20Sopenharmony_ci				  &err);
6658c2ecf20Sopenharmony_ci	if (!skb)
6668c2ecf20Sopenharmony_ci		goto out_dev;
6678c2ecf20Sopenharmony_ci
6688c2ecf20Sopenharmony_ci	skb_reserve(skb, hlen);
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	skb_reset_network_header(skb);
6718c2ecf20Sopenharmony_ci
6728c2ecf20Sopenharmony_ci	cb = mac_cb_init(skb);
6738c2ecf20Sopenharmony_ci	cb->type = IEEE802154_FC_TYPE_DATA;
6748c2ecf20Sopenharmony_ci	cb->ackreq = ro->want_ack;
6758c2ecf20Sopenharmony_ci	cb->secen = ro->secen;
6768c2ecf20Sopenharmony_ci	cb->secen_override = ro->secen_override;
6778c2ecf20Sopenharmony_ci	cb->seclevel = ro->seclevel;
6788c2ecf20Sopenharmony_ci	cb->seclevel_override = ro->seclevel_override;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	err = wpan_dev_hard_header(skb, dev, &dst_addr,
6818c2ecf20Sopenharmony_ci				   ro->bound ? &ro->src_addr : NULL, size);
6828c2ecf20Sopenharmony_ci	if (err < 0)
6838c2ecf20Sopenharmony_ci		goto out_skb;
6848c2ecf20Sopenharmony_ci
6858c2ecf20Sopenharmony_ci	err = memcpy_from_msg(skb_put(skb, size), msg, size);
6868c2ecf20Sopenharmony_ci	if (err < 0)
6878c2ecf20Sopenharmony_ci		goto out_skb;
6888c2ecf20Sopenharmony_ci
6898c2ecf20Sopenharmony_ci	skb->dev = dev;
6908c2ecf20Sopenharmony_ci	skb->protocol = htons(ETH_P_IEEE802154);
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	err = dev_queue_xmit(skb);
6938c2ecf20Sopenharmony_ci	if (err > 0)
6948c2ecf20Sopenharmony_ci		err = net_xmit_errno(err);
6958c2ecf20Sopenharmony_ci
6968c2ecf20Sopenharmony_ci	dev_put(dev);
6978c2ecf20Sopenharmony_ci
6988c2ecf20Sopenharmony_ci	return err ?: size;
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ciout_skb:
7018c2ecf20Sopenharmony_ci	kfree_skb(skb);
7028c2ecf20Sopenharmony_ciout_dev:
7038c2ecf20Sopenharmony_ci	dev_put(dev);
7048c2ecf20Sopenharmony_ciout:
7058c2ecf20Sopenharmony_ci	return err;
7068c2ecf20Sopenharmony_ci}
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_cistatic int dgram_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,
7098c2ecf20Sopenharmony_ci			 int noblock, int flags, int *addr_len)
7108c2ecf20Sopenharmony_ci{
7118c2ecf20Sopenharmony_ci	size_t copied = 0;
7128c2ecf20Sopenharmony_ci	int err = -EOPNOTSUPP;
7138c2ecf20Sopenharmony_ci	struct sk_buff *skb;
7148c2ecf20Sopenharmony_ci	struct dgram_sock *ro = dgram_sk(sk);
7158c2ecf20Sopenharmony_ci	DECLARE_SOCKADDR(struct sockaddr_ieee802154 *, saddr, msg->msg_name);
7168c2ecf20Sopenharmony_ci
7178c2ecf20Sopenharmony_ci	skb = skb_recv_datagram(sk, flags, noblock, &err);
7188c2ecf20Sopenharmony_ci	if (!skb)
7198c2ecf20Sopenharmony_ci		goto out;
7208c2ecf20Sopenharmony_ci
7218c2ecf20Sopenharmony_ci	copied = skb->len;
7228c2ecf20Sopenharmony_ci	if (len < copied) {
7238c2ecf20Sopenharmony_ci		msg->msg_flags |= MSG_TRUNC;
7248c2ecf20Sopenharmony_ci		copied = len;
7258c2ecf20Sopenharmony_ci	}
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	/* FIXME: skip headers if necessary ?! */
7288c2ecf20Sopenharmony_ci	err = skb_copy_datagram_msg(skb, 0, msg, copied);
7298c2ecf20Sopenharmony_ci	if (err)
7308c2ecf20Sopenharmony_ci		goto done;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	sock_recv_ts_and_drops(msg, sk, skb);
7338c2ecf20Sopenharmony_ci
7348c2ecf20Sopenharmony_ci	if (saddr) {
7358c2ecf20Sopenharmony_ci		/* Clear the implicit padding in struct sockaddr_ieee802154
7368c2ecf20Sopenharmony_ci		 * (16 bits between 'family' and 'addr') and in struct
7378c2ecf20Sopenharmony_ci		 * ieee802154_addr_sa (16 bits at the end of the structure).
7388c2ecf20Sopenharmony_ci		 */
7398c2ecf20Sopenharmony_ci		memset(saddr, 0, sizeof(*saddr));
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		saddr->family = AF_IEEE802154;
7428c2ecf20Sopenharmony_ci		ieee802154_addr_to_sa(&saddr->addr, &mac_cb(skb)->source);
7438c2ecf20Sopenharmony_ci		*addr_len = sizeof(*saddr);
7448c2ecf20Sopenharmony_ci	}
7458c2ecf20Sopenharmony_ci
7468c2ecf20Sopenharmony_ci	if (ro->want_lqi) {
7478c2ecf20Sopenharmony_ci		err = put_cmsg(msg, SOL_IEEE802154, WPAN_WANTLQI,
7488c2ecf20Sopenharmony_ci			       sizeof(uint8_t), &(mac_cb(skb)->lqi));
7498c2ecf20Sopenharmony_ci		if (err)
7508c2ecf20Sopenharmony_ci			goto done;
7518c2ecf20Sopenharmony_ci	}
7528c2ecf20Sopenharmony_ci
7538c2ecf20Sopenharmony_ci	if (flags & MSG_TRUNC)
7548c2ecf20Sopenharmony_ci		copied = skb->len;
7558c2ecf20Sopenharmony_cidone:
7568c2ecf20Sopenharmony_ci	skb_free_datagram(sk, skb);
7578c2ecf20Sopenharmony_ciout:
7588c2ecf20Sopenharmony_ci	if (err)
7598c2ecf20Sopenharmony_ci		return err;
7608c2ecf20Sopenharmony_ci	return copied;
7618c2ecf20Sopenharmony_ci}
7628c2ecf20Sopenharmony_ci
7638c2ecf20Sopenharmony_cistatic int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb)
7648c2ecf20Sopenharmony_ci{
7658c2ecf20Sopenharmony_ci	skb = skb_share_check(skb, GFP_ATOMIC);
7668c2ecf20Sopenharmony_ci	if (!skb)
7678c2ecf20Sopenharmony_ci		return NET_RX_DROP;
7688c2ecf20Sopenharmony_ci
7698c2ecf20Sopenharmony_ci	if (sock_queue_rcv_skb(sk, skb) < 0) {
7708c2ecf20Sopenharmony_ci		kfree_skb(skb);
7718c2ecf20Sopenharmony_ci		return NET_RX_DROP;
7728c2ecf20Sopenharmony_ci	}
7738c2ecf20Sopenharmony_ci
7748c2ecf20Sopenharmony_ci	return NET_RX_SUCCESS;
7758c2ecf20Sopenharmony_ci}
7768c2ecf20Sopenharmony_ci
7778c2ecf20Sopenharmony_cistatic inline bool
7788c2ecf20Sopenharmony_ciieee802154_match_sock(__le64 hw_addr, __le16 pan_id, __le16 short_addr,
7798c2ecf20Sopenharmony_ci		      struct dgram_sock *ro)
7808c2ecf20Sopenharmony_ci{
7818c2ecf20Sopenharmony_ci	if (!ro->bound)
7828c2ecf20Sopenharmony_ci		return true;
7838c2ecf20Sopenharmony_ci
7848c2ecf20Sopenharmony_ci	if (ro->src_addr.mode == IEEE802154_ADDR_LONG &&
7858c2ecf20Sopenharmony_ci	    hw_addr == ro->src_addr.extended_addr)
7868c2ecf20Sopenharmony_ci		return true;
7878c2ecf20Sopenharmony_ci
7888c2ecf20Sopenharmony_ci	if (ro->src_addr.mode == IEEE802154_ADDR_SHORT &&
7898c2ecf20Sopenharmony_ci	    pan_id == ro->src_addr.pan_id &&
7908c2ecf20Sopenharmony_ci	    short_addr == ro->src_addr.short_addr)
7918c2ecf20Sopenharmony_ci		return true;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	return false;
7948c2ecf20Sopenharmony_ci}
7958c2ecf20Sopenharmony_ci
7968c2ecf20Sopenharmony_cistatic int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb)
7978c2ecf20Sopenharmony_ci{
7988c2ecf20Sopenharmony_ci	struct sock *sk, *prev = NULL;
7998c2ecf20Sopenharmony_ci	int ret = NET_RX_SUCCESS;
8008c2ecf20Sopenharmony_ci	__le16 pan_id, short_addr;
8018c2ecf20Sopenharmony_ci	__le64 hw_addr;
8028c2ecf20Sopenharmony_ci
8038c2ecf20Sopenharmony_ci	/* Data frame processing */
8048c2ecf20Sopenharmony_ci	BUG_ON(dev->type != ARPHRD_IEEE802154);
8058c2ecf20Sopenharmony_ci
8068c2ecf20Sopenharmony_ci	pan_id = dev->ieee802154_ptr->pan_id;
8078c2ecf20Sopenharmony_ci	short_addr = dev->ieee802154_ptr->short_addr;
8088c2ecf20Sopenharmony_ci	hw_addr = dev->ieee802154_ptr->extended_addr;
8098c2ecf20Sopenharmony_ci
8108c2ecf20Sopenharmony_ci	read_lock(&dgram_lock);
8118c2ecf20Sopenharmony_ci	sk_for_each(sk, &dgram_head) {
8128c2ecf20Sopenharmony_ci		if (ieee802154_match_sock(hw_addr, pan_id, short_addr,
8138c2ecf20Sopenharmony_ci					  dgram_sk(sk))) {
8148c2ecf20Sopenharmony_ci			if (prev) {
8158c2ecf20Sopenharmony_ci				struct sk_buff *clone;
8168c2ecf20Sopenharmony_ci
8178c2ecf20Sopenharmony_ci				clone = skb_clone(skb, GFP_ATOMIC);
8188c2ecf20Sopenharmony_ci				if (clone)
8198c2ecf20Sopenharmony_ci					dgram_rcv_skb(prev, clone);
8208c2ecf20Sopenharmony_ci			}
8218c2ecf20Sopenharmony_ci
8228c2ecf20Sopenharmony_ci			prev = sk;
8238c2ecf20Sopenharmony_ci		}
8248c2ecf20Sopenharmony_ci	}
8258c2ecf20Sopenharmony_ci
8268c2ecf20Sopenharmony_ci	if (prev) {
8278c2ecf20Sopenharmony_ci		dgram_rcv_skb(prev, skb);
8288c2ecf20Sopenharmony_ci	} else {
8298c2ecf20Sopenharmony_ci		kfree_skb(skb);
8308c2ecf20Sopenharmony_ci		ret = NET_RX_DROP;
8318c2ecf20Sopenharmony_ci	}
8328c2ecf20Sopenharmony_ci	read_unlock(&dgram_lock);
8338c2ecf20Sopenharmony_ci
8348c2ecf20Sopenharmony_ci	return ret;
8358c2ecf20Sopenharmony_ci}
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_cistatic int dgram_getsockopt(struct sock *sk, int level, int optname,
8388c2ecf20Sopenharmony_ci			    char __user *optval, int __user *optlen)
8398c2ecf20Sopenharmony_ci{
8408c2ecf20Sopenharmony_ci	struct dgram_sock *ro = dgram_sk(sk);
8418c2ecf20Sopenharmony_ci
8428c2ecf20Sopenharmony_ci	int val, len;
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	if (level != SOL_IEEE802154)
8458c2ecf20Sopenharmony_ci		return -EOPNOTSUPP;
8468c2ecf20Sopenharmony_ci
8478c2ecf20Sopenharmony_ci	if (get_user(len, optlen))
8488c2ecf20Sopenharmony_ci		return -EFAULT;
8498c2ecf20Sopenharmony_ci
8508c2ecf20Sopenharmony_ci	len = min_t(unsigned int, len, sizeof(int));
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	switch (optname) {
8538c2ecf20Sopenharmony_ci	case WPAN_WANTACK:
8548c2ecf20Sopenharmony_ci		val = ro->want_ack;
8558c2ecf20Sopenharmony_ci		break;
8568c2ecf20Sopenharmony_ci	case WPAN_WANTLQI:
8578c2ecf20Sopenharmony_ci		val = ro->want_lqi;
8588c2ecf20Sopenharmony_ci		break;
8598c2ecf20Sopenharmony_ci	case WPAN_SECURITY:
8608c2ecf20Sopenharmony_ci		if (!ro->secen_override)
8618c2ecf20Sopenharmony_ci			val = WPAN_SECURITY_DEFAULT;
8628c2ecf20Sopenharmony_ci		else if (ro->secen)
8638c2ecf20Sopenharmony_ci			val = WPAN_SECURITY_ON;
8648c2ecf20Sopenharmony_ci		else
8658c2ecf20Sopenharmony_ci			val = WPAN_SECURITY_OFF;
8668c2ecf20Sopenharmony_ci		break;
8678c2ecf20Sopenharmony_ci	case WPAN_SECURITY_LEVEL:
8688c2ecf20Sopenharmony_ci		if (!ro->seclevel_override)
8698c2ecf20Sopenharmony_ci			val = WPAN_SECURITY_LEVEL_DEFAULT;
8708c2ecf20Sopenharmony_ci		else
8718c2ecf20Sopenharmony_ci			val = ro->seclevel;
8728c2ecf20Sopenharmony_ci		break;
8738c2ecf20Sopenharmony_ci	default:
8748c2ecf20Sopenharmony_ci		return -ENOPROTOOPT;
8758c2ecf20Sopenharmony_ci	}
8768c2ecf20Sopenharmony_ci
8778c2ecf20Sopenharmony_ci	if (put_user(len, optlen))
8788c2ecf20Sopenharmony_ci		return -EFAULT;
8798c2ecf20Sopenharmony_ci	if (copy_to_user(optval, &val, len))
8808c2ecf20Sopenharmony_ci		return -EFAULT;
8818c2ecf20Sopenharmony_ci	return 0;
8828c2ecf20Sopenharmony_ci}
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_cistatic int dgram_setsockopt(struct sock *sk, int level, int optname,
8858c2ecf20Sopenharmony_ci			    sockptr_t optval, unsigned int optlen)
8868c2ecf20Sopenharmony_ci{
8878c2ecf20Sopenharmony_ci	struct dgram_sock *ro = dgram_sk(sk);
8888c2ecf20Sopenharmony_ci	struct net *net = sock_net(sk);
8898c2ecf20Sopenharmony_ci	int val;
8908c2ecf20Sopenharmony_ci	int err = 0;
8918c2ecf20Sopenharmony_ci
8928c2ecf20Sopenharmony_ci	if (optlen < sizeof(int))
8938c2ecf20Sopenharmony_ci		return -EINVAL;
8948c2ecf20Sopenharmony_ci
8958c2ecf20Sopenharmony_ci	if (copy_from_sockptr(&val, optval, sizeof(int)))
8968c2ecf20Sopenharmony_ci		return -EFAULT;
8978c2ecf20Sopenharmony_ci
8988c2ecf20Sopenharmony_ci	lock_sock(sk);
8998c2ecf20Sopenharmony_ci
9008c2ecf20Sopenharmony_ci	switch (optname) {
9018c2ecf20Sopenharmony_ci	case WPAN_WANTACK:
9028c2ecf20Sopenharmony_ci		ro->want_ack = !!val;
9038c2ecf20Sopenharmony_ci		break;
9048c2ecf20Sopenharmony_ci	case WPAN_WANTLQI:
9058c2ecf20Sopenharmony_ci		ro->want_lqi = !!val;
9068c2ecf20Sopenharmony_ci		break;
9078c2ecf20Sopenharmony_ci	case WPAN_SECURITY:
9088c2ecf20Sopenharmony_ci		if (!ns_capable(net->user_ns, CAP_NET_ADMIN) &&
9098c2ecf20Sopenharmony_ci		    !ns_capable(net->user_ns, CAP_NET_RAW)) {
9108c2ecf20Sopenharmony_ci			err = -EPERM;
9118c2ecf20Sopenharmony_ci			break;
9128c2ecf20Sopenharmony_ci		}
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci		switch (val) {
9158c2ecf20Sopenharmony_ci		case WPAN_SECURITY_DEFAULT:
9168c2ecf20Sopenharmony_ci			ro->secen_override = 0;
9178c2ecf20Sopenharmony_ci			break;
9188c2ecf20Sopenharmony_ci		case WPAN_SECURITY_ON:
9198c2ecf20Sopenharmony_ci			ro->secen_override = 1;
9208c2ecf20Sopenharmony_ci			ro->secen = 1;
9218c2ecf20Sopenharmony_ci			break;
9228c2ecf20Sopenharmony_ci		case WPAN_SECURITY_OFF:
9238c2ecf20Sopenharmony_ci			ro->secen_override = 1;
9248c2ecf20Sopenharmony_ci			ro->secen = 0;
9258c2ecf20Sopenharmony_ci			break;
9268c2ecf20Sopenharmony_ci		default:
9278c2ecf20Sopenharmony_ci			err = -EINVAL;
9288c2ecf20Sopenharmony_ci			break;
9298c2ecf20Sopenharmony_ci		}
9308c2ecf20Sopenharmony_ci		break;
9318c2ecf20Sopenharmony_ci	case WPAN_SECURITY_LEVEL:
9328c2ecf20Sopenharmony_ci		if (!ns_capable(net->user_ns, CAP_NET_ADMIN) &&
9338c2ecf20Sopenharmony_ci		    !ns_capable(net->user_ns, CAP_NET_RAW)) {
9348c2ecf20Sopenharmony_ci			err = -EPERM;
9358c2ecf20Sopenharmony_ci			break;
9368c2ecf20Sopenharmony_ci		}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_ci		if (val < WPAN_SECURITY_LEVEL_DEFAULT ||
9398c2ecf20Sopenharmony_ci		    val > IEEE802154_SCF_SECLEVEL_ENC_MIC128) {
9408c2ecf20Sopenharmony_ci			err = -EINVAL;
9418c2ecf20Sopenharmony_ci		} else if (val == WPAN_SECURITY_LEVEL_DEFAULT) {
9428c2ecf20Sopenharmony_ci			ro->seclevel_override = 0;
9438c2ecf20Sopenharmony_ci		} else {
9448c2ecf20Sopenharmony_ci			ro->seclevel_override = 1;
9458c2ecf20Sopenharmony_ci			ro->seclevel = val;
9468c2ecf20Sopenharmony_ci		}
9478c2ecf20Sopenharmony_ci		break;
9488c2ecf20Sopenharmony_ci	default:
9498c2ecf20Sopenharmony_ci		err = -ENOPROTOOPT;
9508c2ecf20Sopenharmony_ci		break;
9518c2ecf20Sopenharmony_ci	}
9528c2ecf20Sopenharmony_ci
9538c2ecf20Sopenharmony_ci	release_sock(sk);
9548c2ecf20Sopenharmony_ci	return err;
9558c2ecf20Sopenharmony_ci}
9568c2ecf20Sopenharmony_ci
9578c2ecf20Sopenharmony_cistatic struct proto ieee802154_dgram_prot = {
9588c2ecf20Sopenharmony_ci	.name		= "IEEE-802.15.4-MAC",
9598c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
9608c2ecf20Sopenharmony_ci	.obj_size	= sizeof(struct dgram_sock),
9618c2ecf20Sopenharmony_ci	.init		= dgram_init,
9628c2ecf20Sopenharmony_ci	.close		= dgram_close,
9638c2ecf20Sopenharmony_ci	.bind		= dgram_bind,
9648c2ecf20Sopenharmony_ci	.sendmsg	= dgram_sendmsg,
9658c2ecf20Sopenharmony_ci	.recvmsg	= dgram_recvmsg,
9668c2ecf20Sopenharmony_ci	.hash		= dgram_hash,
9678c2ecf20Sopenharmony_ci	.unhash		= dgram_unhash,
9688c2ecf20Sopenharmony_ci	.connect	= dgram_connect,
9698c2ecf20Sopenharmony_ci	.disconnect	= dgram_disconnect,
9708c2ecf20Sopenharmony_ci	.ioctl		= dgram_ioctl,
9718c2ecf20Sopenharmony_ci	.getsockopt	= dgram_getsockopt,
9728c2ecf20Sopenharmony_ci	.setsockopt	= dgram_setsockopt,
9738c2ecf20Sopenharmony_ci};
9748c2ecf20Sopenharmony_ci
9758c2ecf20Sopenharmony_cistatic const struct proto_ops ieee802154_dgram_ops = {
9768c2ecf20Sopenharmony_ci	.family		   = PF_IEEE802154,
9778c2ecf20Sopenharmony_ci	.owner		   = THIS_MODULE,
9788c2ecf20Sopenharmony_ci	.release	   = ieee802154_sock_release,
9798c2ecf20Sopenharmony_ci	.bind		   = ieee802154_sock_bind,
9808c2ecf20Sopenharmony_ci	.connect	   = ieee802154_sock_connect,
9818c2ecf20Sopenharmony_ci	.socketpair	   = sock_no_socketpair,
9828c2ecf20Sopenharmony_ci	.accept		   = sock_no_accept,
9838c2ecf20Sopenharmony_ci	.getname	   = sock_no_getname,
9848c2ecf20Sopenharmony_ci	.poll		   = datagram_poll,
9858c2ecf20Sopenharmony_ci	.ioctl		   = ieee802154_sock_ioctl,
9868c2ecf20Sopenharmony_ci	.gettstamp	   = sock_gettstamp,
9878c2ecf20Sopenharmony_ci	.listen		   = sock_no_listen,
9888c2ecf20Sopenharmony_ci	.shutdown	   = sock_no_shutdown,
9898c2ecf20Sopenharmony_ci	.setsockopt	   = sock_common_setsockopt,
9908c2ecf20Sopenharmony_ci	.getsockopt	   = sock_common_getsockopt,
9918c2ecf20Sopenharmony_ci	.sendmsg	   = ieee802154_sock_sendmsg,
9928c2ecf20Sopenharmony_ci	.recvmsg	   = sock_common_recvmsg,
9938c2ecf20Sopenharmony_ci	.mmap		   = sock_no_mmap,
9948c2ecf20Sopenharmony_ci	.sendpage	   = sock_no_sendpage,
9958c2ecf20Sopenharmony_ci};
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_cistatic void ieee802154_sock_destruct(struct sock *sk)
9988c2ecf20Sopenharmony_ci{
9998c2ecf20Sopenharmony_ci	skb_queue_purge(&sk->sk_receive_queue);
10008c2ecf20Sopenharmony_ci}
10018c2ecf20Sopenharmony_ci
10028c2ecf20Sopenharmony_ci/* Create a socket. Initialise the socket, blank the addresses
10038c2ecf20Sopenharmony_ci * set the state.
10048c2ecf20Sopenharmony_ci */
10058c2ecf20Sopenharmony_cistatic int ieee802154_create(struct net *net, struct socket *sock,
10068c2ecf20Sopenharmony_ci			     int protocol, int kern)
10078c2ecf20Sopenharmony_ci{
10088c2ecf20Sopenharmony_ci	struct sock *sk;
10098c2ecf20Sopenharmony_ci	int rc;
10108c2ecf20Sopenharmony_ci	struct proto *proto;
10118c2ecf20Sopenharmony_ci	const struct proto_ops *ops;
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_ci	if (!net_eq(net, &init_net))
10148c2ecf20Sopenharmony_ci		return -EAFNOSUPPORT;
10158c2ecf20Sopenharmony_ci
10168c2ecf20Sopenharmony_ci	switch (sock->type) {
10178c2ecf20Sopenharmony_ci	case SOCK_RAW:
10188c2ecf20Sopenharmony_ci		rc = -EPERM;
10198c2ecf20Sopenharmony_ci		if (!capable(CAP_NET_RAW))
10208c2ecf20Sopenharmony_ci			goto out;
10218c2ecf20Sopenharmony_ci		proto = &ieee802154_raw_prot;
10228c2ecf20Sopenharmony_ci		ops = &ieee802154_raw_ops;
10238c2ecf20Sopenharmony_ci		break;
10248c2ecf20Sopenharmony_ci	case SOCK_DGRAM:
10258c2ecf20Sopenharmony_ci		proto = &ieee802154_dgram_prot;
10268c2ecf20Sopenharmony_ci		ops = &ieee802154_dgram_ops;
10278c2ecf20Sopenharmony_ci		break;
10288c2ecf20Sopenharmony_ci	default:
10298c2ecf20Sopenharmony_ci		rc = -ESOCKTNOSUPPORT;
10308c2ecf20Sopenharmony_ci		goto out;
10318c2ecf20Sopenharmony_ci	}
10328c2ecf20Sopenharmony_ci
10338c2ecf20Sopenharmony_ci	rc = -ENOMEM;
10348c2ecf20Sopenharmony_ci	sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto, kern);
10358c2ecf20Sopenharmony_ci	if (!sk)
10368c2ecf20Sopenharmony_ci		goto out;
10378c2ecf20Sopenharmony_ci	rc = 0;
10388c2ecf20Sopenharmony_ci
10398c2ecf20Sopenharmony_ci	sock->ops = ops;
10408c2ecf20Sopenharmony_ci
10418c2ecf20Sopenharmony_ci	sock_init_data(sock, sk);
10428c2ecf20Sopenharmony_ci	sk->sk_destruct = ieee802154_sock_destruct;
10438c2ecf20Sopenharmony_ci	sk->sk_family = PF_IEEE802154;
10448c2ecf20Sopenharmony_ci
10458c2ecf20Sopenharmony_ci	/* Checksums on by default */
10468c2ecf20Sopenharmony_ci	sock_set_flag(sk, SOCK_ZAPPED);
10478c2ecf20Sopenharmony_ci
10488c2ecf20Sopenharmony_ci	if (sk->sk_prot->hash) {
10498c2ecf20Sopenharmony_ci		rc = sk->sk_prot->hash(sk);
10508c2ecf20Sopenharmony_ci		if (rc) {
10518c2ecf20Sopenharmony_ci			sk_common_release(sk);
10528c2ecf20Sopenharmony_ci			goto out;
10538c2ecf20Sopenharmony_ci		}
10548c2ecf20Sopenharmony_ci	}
10558c2ecf20Sopenharmony_ci
10568c2ecf20Sopenharmony_ci	if (sk->sk_prot->init) {
10578c2ecf20Sopenharmony_ci		rc = sk->sk_prot->init(sk);
10588c2ecf20Sopenharmony_ci		if (rc)
10598c2ecf20Sopenharmony_ci			sk_common_release(sk);
10608c2ecf20Sopenharmony_ci	}
10618c2ecf20Sopenharmony_ciout:
10628c2ecf20Sopenharmony_ci	return rc;
10638c2ecf20Sopenharmony_ci}
10648c2ecf20Sopenharmony_ci
10658c2ecf20Sopenharmony_cistatic const struct net_proto_family ieee802154_family_ops = {
10668c2ecf20Sopenharmony_ci	.family		= PF_IEEE802154,
10678c2ecf20Sopenharmony_ci	.create		= ieee802154_create,
10688c2ecf20Sopenharmony_ci	.owner		= THIS_MODULE,
10698c2ecf20Sopenharmony_ci};
10708c2ecf20Sopenharmony_ci
10718c2ecf20Sopenharmony_cistatic int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev,
10728c2ecf20Sopenharmony_ci			  struct packet_type *pt, struct net_device *orig_dev)
10738c2ecf20Sopenharmony_ci{
10748c2ecf20Sopenharmony_ci	if (!netif_running(dev))
10758c2ecf20Sopenharmony_ci		goto drop;
10768c2ecf20Sopenharmony_ci	pr_debug("got frame, type %d, dev %p\n", dev->type, dev);
10778c2ecf20Sopenharmony_ci#ifdef DEBUG
10788c2ecf20Sopenharmony_ci	print_hex_dump_bytes("ieee802154_rcv ",
10798c2ecf20Sopenharmony_ci			     DUMP_PREFIX_NONE, skb->data, skb->len);
10808c2ecf20Sopenharmony_ci#endif
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	if (!net_eq(dev_net(dev), &init_net))
10838c2ecf20Sopenharmony_ci		goto drop;
10848c2ecf20Sopenharmony_ci
10858c2ecf20Sopenharmony_ci	ieee802154_raw_deliver(dev, skb);
10868c2ecf20Sopenharmony_ci
10878c2ecf20Sopenharmony_ci	if (dev->type != ARPHRD_IEEE802154)
10888c2ecf20Sopenharmony_ci		goto drop;
10898c2ecf20Sopenharmony_ci
10908c2ecf20Sopenharmony_ci	if (skb->pkt_type != PACKET_OTHERHOST)
10918c2ecf20Sopenharmony_ci		return ieee802154_dgram_deliver(dev, skb);
10928c2ecf20Sopenharmony_ci
10938c2ecf20Sopenharmony_cidrop:
10948c2ecf20Sopenharmony_ci	kfree_skb(skb);
10958c2ecf20Sopenharmony_ci	return NET_RX_DROP;
10968c2ecf20Sopenharmony_ci}
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_cistatic struct packet_type ieee802154_packet_type = {
10998c2ecf20Sopenharmony_ci	.type = htons(ETH_P_IEEE802154),
11008c2ecf20Sopenharmony_ci	.func = ieee802154_rcv,
11018c2ecf20Sopenharmony_ci};
11028c2ecf20Sopenharmony_ci
11038c2ecf20Sopenharmony_cistatic int __init af_ieee802154_init(void)
11048c2ecf20Sopenharmony_ci{
11058c2ecf20Sopenharmony_ci	int rc;
11068c2ecf20Sopenharmony_ci
11078c2ecf20Sopenharmony_ci	rc = proto_register(&ieee802154_raw_prot, 1);
11088c2ecf20Sopenharmony_ci	if (rc)
11098c2ecf20Sopenharmony_ci		goto out;
11108c2ecf20Sopenharmony_ci
11118c2ecf20Sopenharmony_ci	rc = proto_register(&ieee802154_dgram_prot, 1);
11128c2ecf20Sopenharmony_ci	if (rc)
11138c2ecf20Sopenharmony_ci		goto err_dgram;
11148c2ecf20Sopenharmony_ci
11158c2ecf20Sopenharmony_ci	/* Tell SOCKET that we are alive */
11168c2ecf20Sopenharmony_ci	rc = sock_register(&ieee802154_family_ops);
11178c2ecf20Sopenharmony_ci	if (rc)
11188c2ecf20Sopenharmony_ci		goto err_sock;
11198c2ecf20Sopenharmony_ci	dev_add_pack(&ieee802154_packet_type);
11208c2ecf20Sopenharmony_ci
11218c2ecf20Sopenharmony_ci	rc = 0;
11228c2ecf20Sopenharmony_ci	goto out;
11238c2ecf20Sopenharmony_ci
11248c2ecf20Sopenharmony_cierr_sock:
11258c2ecf20Sopenharmony_ci	proto_unregister(&ieee802154_dgram_prot);
11268c2ecf20Sopenharmony_cierr_dgram:
11278c2ecf20Sopenharmony_ci	proto_unregister(&ieee802154_raw_prot);
11288c2ecf20Sopenharmony_ciout:
11298c2ecf20Sopenharmony_ci	return rc;
11308c2ecf20Sopenharmony_ci}
11318c2ecf20Sopenharmony_ci
11328c2ecf20Sopenharmony_cistatic void __exit af_ieee802154_remove(void)
11338c2ecf20Sopenharmony_ci{
11348c2ecf20Sopenharmony_ci	dev_remove_pack(&ieee802154_packet_type);
11358c2ecf20Sopenharmony_ci	sock_unregister(PF_IEEE802154);
11368c2ecf20Sopenharmony_ci	proto_unregister(&ieee802154_dgram_prot);
11378c2ecf20Sopenharmony_ci	proto_unregister(&ieee802154_raw_prot);
11388c2ecf20Sopenharmony_ci}
11398c2ecf20Sopenharmony_ci
11408c2ecf20Sopenharmony_cimodule_init(af_ieee802154_init);
11418c2ecf20Sopenharmony_cimodule_exit(af_ieee802154_remove);
11428c2ecf20Sopenharmony_ci
11438c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
11448c2ecf20Sopenharmony_ciMODULE_ALIAS_NETPROTO(PF_IEEE802154);
1145