1157 lines · 23.5 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * IEEE802154.4 socket interface * * Copyright 2007, 2008 Siemens AG * * Written by: * Sergey Lapin <slapin@ossfans.org> * Maxim Gorbachyov <maxim.gorbachev@siemens.com> */ #include <linux/net.h>#include <linux/capability.h>#include <linux/module.h>#include <linux/if_arp.h>#include <linux/if.h>#include <linux/termios.h>	/* For TIOCOUTQ/INQ */#include <linux/list.h>#include <linux/slab.h>#include <linux/socket.h>#include <net/datalink.h>#include <net/psnap.h>#include <net/sock.h>#include <net/tcp_states.h>#include <net/route.h> #include <net/af_ieee802154.h>#include <net/ieee802154_netdev.h> /* Utility function for families */static struct net_device*ieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr){	struct net_device *dev = NULL;	struct net_device *tmp;	__le16 pan_id, short_addr;	u8 hwaddr[IEEE802154_ADDR_LEN]; 	switch (addr->mode) {	case IEEE802154_ADDR_LONG:		ieee802154_devaddr_to_raw(hwaddr, addr->extended_addr);		rcu_read_lock();		dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, hwaddr);		dev_hold(dev);		rcu_read_unlock();		break;	case IEEE802154_ADDR_SHORT:		if (addr->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST) ||		    addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) ||		    addr->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST))			break; 		rtnl_lock(); 		for_each_netdev(net, tmp) {			if (tmp->type != ARPHRD_IEEE802154)				continue; 			pan_id = tmp->ieee802154_ptr->pan_id;			short_addr = tmp->ieee802154_ptr->short_addr;			if (pan_id == addr->pan_id &&			    short_addr == addr->short_addr) {				dev = tmp;				dev_hold(dev);				break;			}		} 		rtnl_unlock();		break;	default:		pr_warn("Unsupported ieee802154 address type: %d\n",			addr->mode);		break;	} 	return dev;} static int ieee802154_sock_release(struct socket *sock){	struct sock *sk = sock->sk; 	if (sk) {		sock->sk = NULL;		sk->sk_prot->close(sk, 0);	}	return 0;} static int ieee802154_sock_sendmsg(struct socket *sock, struct msghdr *msg,				   size_t len){	struct sock *sk = sock->sk; 	return sk->sk_prot->sendmsg(sk, msg, len);} static int ieee802154_sock_bind(struct socket *sock, struct sockaddr_unsized *uaddr,				int addr_len){	struct sock *sk = sock->sk; 	if (sk->sk_prot->bind)		return sk->sk_prot->bind(sk, uaddr, addr_len); 	return sock_no_bind(sock, uaddr, addr_len);} static int ieee802154_sock_connect(struct socket *sock, struct sockaddr_unsized *uaddr,				   int addr_len, int flags){	struct sock *sk = sock->sk; 	if (addr_len < sizeof(uaddr->sa_family))		return -EINVAL; 	if (uaddr->sa_family == AF_UNSPEC)		return sk->sk_prot->disconnect(sk, flags); 	return sk->sk_prot->connect(sk, uaddr, addr_len);} static int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg,				unsigned int cmd){	struct ifreq ifr;	int ret = -ENOIOCTLCMD;	struct net_device *dev; 	if (get_user_ifreq(&ifr, NULL, arg))		return -EFAULT; 	ifr.ifr_name[IFNAMSIZ-1] = 0; 	dev_load(sock_net(sk), ifr.ifr_name);	dev = dev_get_by_name(sock_net(sk), ifr.ifr_name); 	if (!dev)		return -ENODEV; 	if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl)		ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd); 	if (!ret && put_user_ifreq(&ifr, arg))		ret = -EFAULT;	dev_put(dev); 	return ret;} static int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd,				 unsigned long arg){	struct sock *sk = sock->sk; 	switch (cmd) {	case SIOCGIFADDR:	case SIOCSIFADDR:		return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg,				cmd);	default:		if (!sk->sk_prot->ioctl)			return -ENOIOCTLCMD;		return sk_ioctl(sk, cmd, (void __user *)arg);	}} /* RAW Sockets (802.15.4 created in userspace) */static HLIST_HEAD(raw_head);static DEFINE_RWLOCK(raw_lock); static int raw_hash(struct sock *sk){	write_lock_bh(&raw_lock);	sk_add_node(sk, &raw_head);	write_unlock_bh(&raw_lock);	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 	return 0;} static void raw_unhash(struct sock *sk){	write_lock_bh(&raw_lock);	if (sk_del_node_init(sk))		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);	write_unlock_bh(&raw_lock);} static void raw_close(struct sock *sk, long timeout){	sk_common_release(sk);} static int raw_bind(struct sock *sk, struct sockaddr_unsized *_uaddr, int len){	struct ieee802154_addr addr;	struct sockaddr_ieee802154 *uaddr = (struct sockaddr_ieee802154 *)_uaddr;	int err = 0;	struct net_device *dev = NULL; 	err = ieee802154_sockaddr_check_size(uaddr, len);	if (err < 0)		return err; 	uaddr = (struct sockaddr_ieee802154 *)_uaddr;	if (uaddr->family != AF_IEEE802154)		return -EINVAL; 	lock_sock(sk); 	ieee802154_addr_from_sa(&addr, &uaddr->addr);	dev = ieee802154_get_dev(sock_net(sk), &addr);	if (!dev) {		err = -ENODEV;		goto out;	} 	sk->sk_bound_dev_if = dev->ifindex;	sk_dst_reset(sk); 	dev_put(dev);out:	release_sock(sk); 	return err;} static int raw_connect(struct sock *sk, struct sockaddr_unsized *uaddr,		       int addr_len){	return -ENOTSUPP;} static int raw_disconnect(struct sock *sk, int flags){	return 0;} static int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size){	struct net_device *dev;	unsigned int mtu;	struct sk_buff *skb;	int hlen, tlen;	int err; 	if (msg->msg_flags & MSG_OOB) {		pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags);		return -EOPNOTSUPP;	} 	lock_sock(sk);	if (!sk->sk_bound_dev_if)		dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154);	else		dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if);	release_sock(sk); 	if (!dev) {		pr_debug("no dev\n");		err = -ENXIO;		goto out;	} 	mtu = IEEE802154_MTU;	pr_debug("name = %s, mtu = %u\n", dev->name, mtu); 	if (size > mtu) {		pr_debug("size = %zu, mtu = %u\n", size, mtu);		err = -EMSGSIZE;		goto out_dev;	}	if (!size) {		err = 0;		goto out_dev;	} 	hlen = LL_RESERVED_SPACE(dev);	tlen = dev->needed_tailroom;	skb = sock_alloc_send_skb(sk, hlen + tlen + size,				  msg->msg_flags & MSG_DONTWAIT, &err);	if (!skb)		goto out_dev; 	skb_reserve(skb, hlen); 	skb_reset_mac_header(skb);	skb_reset_network_header(skb); 	err = memcpy_from_msg(skb_put(skb, size), msg, size);	if (err < 0)		goto out_skb; 	skb->dev = dev;	skb->protocol = htons(ETH_P_IEEE802154); 	err = dev_queue_xmit(skb);	if (err > 0)		err = net_xmit_errno(err); 	dev_put(dev); 	return err ?: size; out_skb:	kfree_skb(skb);out_dev:	dev_put(dev);out:	return err;} static int raw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len,		       int flags){	size_t copied = 0;	int err = -EOPNOTSUPP;	struct sk_buff *skb; 	skb = skb_recv_datagram(sk, flags, &err);	if (!skb)		goto out; 	copied = skb->len;	if (len < copied) {		msg->msg_flags |= MSG_TRUNC;		copied = len;	} 	err = skb_copy_datagram_msg(skb, 0, msg, copied);	if (err)		goto done; 	sock_recv_cmsgs(msg, sk, skb); 	if (flags & MSG_TRUNC)		copied = skb->len;done:	skb_free_datagram(sk, skb);out:	if (err)		return err;	return copied;} static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb){	skb = skb_share_check(skb, GFP_ATOMIC);	if (!skb)		return NET_RX_DROP; 	if (sock_queue_rcv_skb(sk, skb) < 0) {		kfree_skb(skb);		return NET_RX_DROP;	} 	return NET_RX_SUCCESS;} static void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb){	struct sock *sk; 	read_lock(&raw_lock);	sk_for_each(sk, &raw_head) {		bh_lock_sock(sk);		if (!sk->sk_bound_dev_if ||		    sk->sk_bound_dev_if == dev->ifindex) {			struct sk_buff *clone; 			clone = skb_clone(skb, GFP_ATOMIC);			if (clone)				raw_rcv_skb(sk, clone);		}		bh_unlock_sock(sk);	}	read_unlock(&raw_lock);} static int raw_getsockopt(struct sock *sk, int level, int optname,			  char __user *optval, int __user *optlen){	return -EOPNOTSUPP;} static int raw_setsockopt(struct sock *sk, int level, int optname,			  sockptr_t optval, unsigned int optlen){	return -EOPNOTSUPP;} static struct proto ieee802154_raw_prot = {	.name		= "IEEE-802.15.4-RAW",	.owner		= THIS_MODULE,	.obj_size	= sizeof(struct sock),	.close		= raw_close,	.bind		= raw_bind,	.sendmsg	= raw_sendmsg,	.recvmsg	= raw_recvmsg,	.hash		= raw_hash,	.unhash		= raw_unhash,	.connect	= raw_connect,	.disconnect	= raw_disconnect,	.getsockopt	= raw_getsockopt,	.setsockopt	= raw_setsockopt,}; static const struct proto_ops ieee802154_raw_ops = {	.family		   = PF_IEEE802154,	.owner		   = THIS_MODULE,	.release	   = ieee802154_sock_release,	.bind		   = ieee802154_sock_bind,	.connect	   = ieee802154_sock_connect,	.socketpair	   = sock_no_socketpair,	.accept		   = sock_no_accept,	.getname	   = sock_no_getname,	.poll		   = datagram_poll,	.ioctl		   = ieee802154_sock_ioctl,	.gettstamp	   = sock_gettstamp,	.listen		   = sock_no_listen,	.shutdown	   = sock_no_shutdown,	.setsockopt	   = sock_common_setsockopt,	.getsockopt	   = sock_common_getsockopt,	.sendmsg	   = ieee802154_sock_sendmsg,	.recvmsg	   = sock_common_recvmsg,	.mmap		   = sock_no_mmap,}; /* DGRAM Sockets (802.15.4 dataframes) */static HLIST_HEAD(dgram_head);static DEFINE_RWLOCK(dgram_lock); struct dgram_sock {	struct sock sk; 	struct ieee802154_addr src_addr;	struct ieee802154_addr dst_addr; 	unsigned int bound:1;	unsigned int connected:1;	unsigned int want_ack:1;	unsigned int want_lqi:1;	unsigned int secen:1;	unsigned int secen_override:1;	unsigned int seclevel:3;	unsigned int seclevel_override:1;}; static inline struct dgram_sock *dgram_sk(const struct sock *sk){	return container_of(sk, struct dgram_sock, sk);} static int dgram_hash(struct sock *sk){	write_lock_bh(&dgram_lock);	sk_add_node(sk, &dgram_head);	write_unlock_bh(&dgram_lock);	sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 	return 0;} static void dgram_unhash(struct sock *sk){	write_lock_bh(&dgram_lock);	if (sk_del_node_init(sk))		sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);	write_unlock_bh(&dgram_lock);} static int dgram_init(struct sock *sk){	struct dgram_sock *ro = dgram_sk(sk); 	ro->want_ack = 1;	ro->want_lqi = 0;	return 0;} static void dgram_close(struct sock *sk, long timeout){	sk_common_release(sk);} static int dgram_bind(struct sock *sk, struct sockaddr_unsized *uaddr, int len){	struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr;	struct ieee802154_addr haddr;	struct dgram_sock *ro = dgram_sk(sk);	int err = -EINVAL;	struct net_device *dev; 	lock_sock(sk); 	ro->bound = 0; 	err = ieee802154_sockaddr_check_size(addr, len);

Lines 1–500 of 1157.