162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * IEEE802154.4 socket interface 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2007, 2008 Siemens AG 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Written by: 862306a36Sopenharmony_ci * Sergey Lapin <slapin@ossfans.org> 962306a36Sopenharmony_ci * Maxim Gorbachyov <maxim.gorbachev@siemens.com> 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/net.h> 1362306a36Sopenharmony_ci#include <linux/capability.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci#include <linux/if_arp.h> 1662306a36Sopenharmony_ci#include <linux/if.h> 1762306a36Sopenharmony_ci#include <linux/termios.h> /* For TIOCOUTQ/INQ */ 1862306a36Sopenharmony_ci#include <linux/list.h> 1962306a36Sopenharmony_ci#include <linux/slab.h> 2062306a36Sopenharmony_ci#include <linux/socket.h> 2162306a36Sopenharmony_ci#include <net/datalink.h> 2262306a36Sopenharmony_ci#include <net/psnap.h> 2362306a36Sopenharmony_ci#include <net/sock.h> 2462306a36Sopenharmony_ci#include <net/tcp_states.h> 2562306a36Sopenharmony_ci#include <net/route.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include <net/af_ieee802154.h> 2862306a36Sopenharmony_ci#include <net/ieee802154_netdev.h> 2962306a36Sopenharmony_ci 3062306a36Sopenharmony_ci/* Utility function for families */ 3162306a36Sopenharmony_cistatic struct net_device* 3262306a36Sopenharmony_ciieee802154_get_dev(struct net *net, const struct ieee802154_addr *addr) 3362306a36Sopenharmony_ci{ 3462306a36Sopenharmony_ci struct net_device *dev = NULL; 3562306a36Sopenharmony_ci struct net_device *tmp; 3662306a36Sopenharmony_ci __le16 pan_id, short_addr; 3762306a36Sopenharmony_ci u8 hwaddr[IEEE802154_ADDR_LEN]; 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci switch (addr->mode) { 4062306a36Sopenharmony_ci case IEEE802154_ADDR_LONG: 4162306a36Sopenharmony_ci ieee802154_devaddr_to_raw(hwaddr, addr->extended_addr); 4262306a36Sopenharmony_ci rcu_read_lock(); 4362306a36Sopenharmony_ci dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, hwaddr); 4462306a36Sopenharmony_ci dev_hold(dev); 4562306a36Sopenharmony_ci rcu_read_unlock(); 4662306a36Sopenharmony_ci break; 4762306a36Sopenharmony_ci case IEEE802154_ADDR_SHORT: 4862306a36Sopenharmony_ci if (addr->pan_id == cpu_to_le16(IEEE802154_PANID_BROADCAST) || 4962306a36Sopenharmony_ci addr->short_addr == cpu_to_le16(IEEE802154_ADDR_UNDEF) || 5062306a36Sopenharmony_ci addr->short_addr == cpu_to_le16(IEEE802154_ADDR_BROADCAST)) 5162306a36Sopenharmony_ci break; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci rtnl_lock(); 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci for_each_netdev(net, tmp) { 5662306a36Sopenharmony_ci if (tmp->type != ARPHRD_IEEE802154) 5762306a36Sopenharmony_ci continue; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci pan_id = tmp->ieee802154_ptr->pan_id; 6062306a36Sopenharmony_ci short_addr = tmp->ieee802154_ptr->short_addr; 6162306a36Sopenharmony_ci if (pan_id == addr->pan_id && 6262306a36Sopenharmony_ci short_addr == addr->short_addr) { 6362306a36Sopenharmony_ci dev = tmp; 6462306a36Sopenharmony_ci dev_hold(dev); 6562306a36Sopenharmony_ci break; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci } 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci rtnl_unlock(); 7062306a36Sopenharmony_ci break; 7162306a36Sopenharmony_ci default: 7262306a36Sopenharmony_ci pr_warn("Unsupported ieee802154 address type: %d\n", 7362306a36Sopenharmony_ci addr->mode); 7462306a36Sopenharmony_ci break; 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci return dev; 7862306a36Sopenharmony_ci} 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_cistatic int ieee802154_sock_release(struct socket *sock) 8162306a36Sopenharmony_ci{ 8262306a36Sopenharmony_ci struct sock *sk = sock->sk; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci if (sk) { 8562306a36Sopenharmony_ci sock->sk = NULL; 8662306a36Sopenharmony_ci sk->sk_prot->close(sk, 0); 8762306a36Sopenharmony_ci } 8862306a36Sopenharmony_ci return 0; 8962306a36Sopenharmony_ci} 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_cistatic int ieee802154_sock_sendmsg(struct socket *sock, struct msghdr *msg, 9262306a36Sopenharmony_ci size_t len) 9362306a36Sopenharmony_ci{ 9462306a36Sopenharmony_ci struct sock *sk = sock->sk; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci return sk->sk_prot->sendmsg(sk, msg, len); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic int ieee802154_sock_bind(struct socket *sock, struct sockaddr *uaddr, 10062306a36Sopenharmony_ci int addr_len) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci struct sock *sk = sock->sk; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (sk->sk_prot->bind) 10562306a36Sopenharmony_ci return sk->sk_prot->bind(sk, uaddr, addr_len); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci return sock_no_bind(sock, uaddr, addr_len); 10862306a36Sopenharmony_ci} 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_cistatic int ieee802154_sock_connect(struct socket *sock, struct sockaddr *uaddr, 11162306a36Sopenharmony_ci int addr_len, int flags) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct sock *sk = sock->sk; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci if (addr_len < sizeof(uaddr->sa_family)) 11662306a36Sopenharmony_ci return -EINVAL; 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci if (uaddr->sa_family == AF_UNSPEC) 11962306a36Sopenharmony_ci return sk->sk_prot->disconnect(sk, flags); 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci return sk->sk_prot->connect(sk, uaddr, addr_len); 12262306a36Sopenharmony_ci} 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_cistatic int ieee802154_dev_ioctl(struct sock *sk, struct ifreq __user *arg, 12562306a36Sopenharmony_ci unsigned int cmd) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct ifreq ifr; 12862306a36Sopenharmony_ci int ret = -ENOIOCTLCMD; 12962306a36Sopenharmony_ci struct net_device *dev; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (get_user_ifreq(&ifr, NULL, arg)) 13262306a36Sopenharmony_ci return -EFAULT; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci ifr.ifr_name[IFNAMSIZ-1] = 0; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci dev_load(sock_net(sk), ifr.ifr_name); 13762306a36Sopenharmony_ci dev = dev_get_by_name(sock_net(sk), ifr.ifr_name); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if (!dev) 14062306a36Sopenharmony_ci return -ENODEV; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (dev->type == ARPHRD_IEEE802154 && dev->netdev_ops->ndo_do_ioctl) 14362306a36Sopenharmony_ci ret = dev->netdev_ops->ndo_do_ioctl(dev, &ifr, cmd); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci if (!ret && put_user_ifreq(&ifr, arg)) 14662306a36Sopenharmony_ci ret = -EFAULT; 14762306a36Sopenharmony_ci dev_put(dev); 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci return ret; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_cistatic int ieee802154_sock_ioctl(struct socket *sock, unsigned int cmd, 15362306a36Sopenharmony_ci unsigned long arg) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci struct sock *sk = sock->sk; 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci switch (cmd) { 15862306a36Sopenharmony_ci case SIOCGIFADDR: 15962306a36Sopenharmony_ci case SIOCSIFADDR: 16062306a36Sopenharmony_ci return ieee802154_dev_ioctl(sk, (struct ifreq __user *)arg, 16162306a36Sopenharmony_ci cmd); 16262306a36Sopenharmony_ci default: 16362306a36Sopenharmony_ci if (!sk->sk_prot->ioctl) 16462306a36Sopenharmony_ci return -ENOIOCTLCMD; 16562306a36Sopenharmony_ci return sk_ioctl(sk, cmd, (void __user *)arg); 16662306a36Sopenharmony_ci } 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/* RAW Sockets (802.15.4 created in userspace) */ 17062306a36Sopenharmony_cistatic HLIST_HEAD(raw_head); 17162306a36Sopenharmony_cistatic DEFINE_RWLOCK(raw_lock); 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_cistatic int raw_hash(struct sock *sk) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci write_lock_bh(&raw_lock); 17662306a36Sopenharmony_ci sk_add_node(sk, &raw_head); 17762306a36Sopenharmony_ci write_unlock_bh(&raw_lock); 17862306a36Sopenharmony_ci sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_ci return 0; 18162306a36Sopenharmony_ci} 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_cistatic void raw_unhash(struct sock *sk) 18462306a36Sopenharmony_ci{ 18562306a36Sopenharmony_ci write_lock_bh(&raw_lock); 18662306a36Sopenharmony_ci if (sk_del_node_init(sk)) 18762306a36Sopenharmony_ci sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 18862306a36Sopenharmony_ci write_unlock_bh(&raw_lock); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_cistatic void raw_close(struct sock *sk, long timeout) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci sk_common_release(sk); 19462306a36Sopenharmony_ci} 19562306a36Sopenharmony_ci 19662306a36Sopenharmony_cistatic int raw_bind(struct sock *sk, struct sockaddr *_uaddr, int len) 19762306a36Sopenharmony_ci{ 19862306a36Sopenharmony_ci struct ieee802154_addr addr; 19962306a36Sopenharmony_ci struct sockaddr_ieee802154 *uaddr = (struct sockaddr_ieee802154 *)_uaddr; 20062306a36Sopenharmony_ci int err = 0; 20162306a36Sopenharmony_ci struct net_device *dev = NULL; 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ci err = ieee802154_sockaddr_check_size(uaddr, len); 20462306a36Sopenharmony_ci if (err < 0) 20562306a36Sopenharmony_ci return err; 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci uaddr = (struct sockaddr_ieee802154 *)_uaddr; 20862306a36Sopenharmony_ci if (uaddr->family != AF_IEEE802154) 20962306a36Sopenharmony_ci return -EINVAL; 21062306a36Sopenharmony_ci 21162306a36Sopenharmony_ci lock_sock(sk); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci ieee802154_addr_from_sa(&addr, &uaddr->addr); 21462306a36Sopenharmony_ci dev = ieee802154_get_dev(sock_net(sk), &addr); 21562306a36Sopenharmony_ci if (!dev) { 21662306a36Sopenharmony_ci err = -ENODEV; 21762306a36Sopenharmony_ci goto out; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci sk->sk_bound_dev_if = dev->ifindex; 22162306a36Sopenharmony_ci sk_dst_reset(sk); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci dev_put(dev); 22462306a36Sopenharmony_ciout: 22562306a36Sopenharmony_ci release_sock(sk); 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci return err; 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_cistatic int raw_connect(struct sock *sk, struct sockaddr *uaddr, 23162306a36Sopenharmony_ci int addr_len) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci return -ENOTSUPP; 23462306a36Sopenharmony_ci} 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_cistatic int raw_disconnect(struct sock *sk, int flags) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci return 0; 23962306a36Sopenharmony_ci} 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_cistatic int raw_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) 24262306a36Sopenharmony_ci{ 24362306a36Sopenharmony_ci struct net_device *dev; 24462306a36Sopenharmony_ci unsigned int mtu; 24562306a36Sopenharmony_ci struct sk_buff *skb; 24662306a36Sopenharmony_ci int hlen, tlen; 24762306a36Sopenharmony_ci int err; 24862306a36Sopenharmony_ci 24962306a36Sopenharmony_ci if (msg->msg_flags & MSG_OOB) { 25062306a36Sopenharmony_ci pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags); 25162306a36Sopenharmony_ci return -EOPNOTSUPP; 25262306a36Sopenharmony_ci } 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci lock_sock(sk); 25562306a36Sopenharmony_ci if (!sk->sk_bound_dev_if) 25662306a36Sopenharmony_ci dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154); 25762306a36Sopenharmony_ci else 25862306a36Sopenharmony_ci dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if); 25962306a36Sopenharmony_ci release_sock(sk); 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci if (!dev) { 26262306a36Sopenharmony_ci pr_debug("no dev\n"); 26362306a36Sopenharmony_ci err = -ENXIO; 26462306a36Sopenharmony_ci goto out; 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci mtu = IEEE802154_MTU; 26862306a36Sopenharmony_ci pr_debug("name = %s, mtu = %u\n", dev->name, mtu); 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_ci if (size > mtu) { 27162306a36Sopenharmony_ci pr_debug("size = %zu, mtu = %u\n", size, mtu); 27262306a36Sopenharmony_ci err = -EMSGSIZE; 27362306a36Sopenharmony_ci goto out_dev; 27462306a36Sopenharmony_ci } 27562306a36Sopenharmony_ci if (!size) { 27662306a36Sopenharmony_ci err = 0; 27762306a36Sopenharmony_ci goto out_dev; 27862306a36Sopenharmony_ci } 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_ci hlen = LL_RESERVED_SPACE(dev); 28162306a36Sopenharmony_ci tlen = dev->needed_tailroom; 28262306a36Sopenharmony_ci skb = sock_alloc_send_skb(sk, hlen + tlen + size, 28362306a36Sopenharmony_ci msg->msg_flags & MSG_DONTWAIT, &err); 28462306a36Sopenharmony_ci if (!skb) 28562306a36Sopenharmony_ci goto out_dev; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci skb_reserve(skb, hlen); 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci skb_reset_mac_header(skb); 29062306a36Sopenharmony_ci skb_reset_network_header(skb); 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci err = memcpy_from_msg(skb_put(skb, size), msg, size); 29362306a36Sopenharmony_ci if (err < 0) 29462306a36Sopenharmony_ci goto out_skb; 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci skb->dev = dev; 29762306a36Sopenharmony_ci skb->protocol = htons(ETH_P_IEEE802154); 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci err = dev_queue_xmit(skb); 30062306a36Sopenharmony_ci if (err > 0) 30162306a36Sopenharmony_ci err = net_xmit_errno(err); 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci dev_put(dev); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return err ?: size; 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciout_skb: 30862306a36Sopenharmony_ci kfree_skb(skb); 30962306a36Sopenharmony_ciout_dev: 31062306a36Sopenharmony_ci dev_put(dev); 31162306a36Sopenharmony_ciout: 31262306a36Sopenharmony_ci return err; 31362306a36Sopenharmony_ci} 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic int raw_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, 31662306a36Sopenharmony_ci int flags, int *addr_len) 31762306a36Sopenharmony_ci{ 31862306a36Sopenharmony_ci size_t copied = 0; 31962306a36Sopenharmony_ci int err = -EOPNOTSUPP; 32062306a36Sopenharmony_ci struct sk_buff *skb; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci skb = skb_recv_datagram(sk, flags, &err); 32362306a36Sopenharmony_ci if (!skb) 32462306a36Sopenharmony_ci goto out; 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci copied = skb->len; 32762306a36Sopenharmony_ci if (len < copied) { 32862306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 32962306a36Sopenharmony_ci copied = len; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci 33262306a36Sopenharmony_ci err = skb_copy_datagram_msg(skb, 0, msg, copied); 33362306a36Sopenharmony_ci if (err) 33462306a36Sopenharmony_ci goto done; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci sock_recv_cmsgs(msg, sk, skb); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci if (flags & MSG_TRUNC) 33962306a36Sopenharmony_ci copied = skb->len; 34062306a36Sopenharmony_cidone: 34162306a36Sopenharmony_ci skb_free_datagram(sk, skb); 34262306a36Sopenharmony_ciout: 34362306a36Sopenharmony_ci if (err) 34462306a36Sopenharmony_ci return err; 34562306a36Sopenharmony_ci return copied; 34662306a36Sopenharmony_ci} 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_cistatic int raw_rcv_skb(struct sock *sk, struct sk_buff *skb) 34962306a36Sopenharmony_ci{ 35062306a36Sopenharmony_ci skb = skb_share_check(skb, GFP_ATOMIC); 35162306a36Sopenharmony_ci if (!skb) 35262306a36Sopenharmony_ci return NET_RX_DROP; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_ci if (sock_queue_rcv_skb(sk, skb) < 0) { 35562306a36Sopenharmony_ci kfree_skb(skb); 35662306a36Sopenharmony_ci return NET_RX_DROP; 35762306a36Sopenharmony_ci } 35862306a36Sopenharmony_ci 35962306a36Sopenharmony_ci return NET_RX_SUCCESS; 36062306a36Sopenharmony_ci} 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_cistatic void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb) 36362306a36Sopenharmony_ci{ 36462306a36Sopenharmony_ci struct sock *sk; 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci read_lock(&raw_lock); 36762306a36Sopenharmony_ci sk_for_each(sk, &raw_head) { 36862306a36Sopenharmony_ci bh_lock_sock(sk); 36962306a36Sopenharmony_ci if (!sk->sk_bound_dev_if || 37062306a36Sopenharmony_ci sk->sk_bound_dev_if == dev->ifindex) { 37162306a36Sopenharmony_ci struct sk_buff *clone; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_ci clone = skb_clone(skb, GFP_ATOMIC); 37462306a36Sopenharmony_ci if (clone) 37562306a36Sopenharmony_ci raw_rcv_skb(sk, clone); 37662306a36Sopenharmony_ci } 37762306a36Sopenharmony_ci bh_unlock_sock(sk); 37862306a36Sopenharmony_ci } 37962306a36Sopenharmony_ci read_unlock(&raw_lock); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_cistatic int raw_getsockopt(struct sock *sk, int level, int optname, 38362306a36Sopenharmony_ci char __user *optval, int __user *optlen) 38462306a36Sopenharmony_ci{ 38562306a36Sopenharmony_ci return -EOPNOTSUPP; 38662306a36Sopenharmony_ci} 38762306a36Sopenharmony_ci 38862306a36Sopenharmony_cistatic int raw_setsockopt(struct sock *sk, int level, int optname, 38962306a36Sopenharmony_ci sockptr_t optval, unsigned int optlen) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci return -EOPNOTSUPP; 39262306a36Sopenharmony_ci} 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_cistatic struct proto ieee802154_raw_prot = { 39562306a36Sopenharmony_ci .name = "IEEE-802.15.4-RAW", 39662306a36Sopenharmony_ci .owner = THIS_MODULE, 39762306a36Sopenharmony_ci .obj_size = sizeof(struct sock), 39862306a36Sopenharmony_ci .close = raw_close, 39962306a36Sopenharmony_ci .bind = raw_bind, 40062306a36Sopenharmony_ci .sendmsg = raw_sendmsg, 40162306a36Sopenharmony_ci .recvmsg = raw_recvmsg, 40262306a36Sopenharmony_ci .hash = raw_hash, 40362306a36Sopenharmony_ci .unhash = raw_unhash, 40462306a36Sopenharmony_ci .connect = raw_connect, 40562306a36Sopenharmony_ci .disconnect = raw_disconnect, 40662306a36Sopenharmony_ci .getsockopt = raw_getsockopt, 40762306a36Sopenharmony_ci .setsockopt = raw_setsockopt, 40862306a36Sopenharmony_ci}; 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic const struct proto_ops ieee802154_raw_ops = { 41162306a36Sopenharmony_ci .family = PF_IEEE802154, 41262306a36Sopenharmony_ci .owner = THIS_MODULE, 41362306a36Sopenharmony_ci .release = ieee802154_sock_release, 41462306a36Sopenharmony_ci .bind = ieee802154_sock_bind, 41562306a36Sopenharmony_ci .connect = ieee802154_sock_connect, 41662306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 41762306a36Sopenharmony_ci .accept = sock_no_accept, 41862306a36Sopenharmony_ci .getname = sock_no_getname, 41962306a36Sopenharmony_ci .poll = datagram_poll, 42062306a36Sopenharmony_ci .ioctl = ieee802154_sock_ioctl, 42162306a36Sopenharmony_ci .gettstamp = sock_gettstamp, 42262306a36Sopenharmony_ci .listen = sock_no_listen, 42362306a36Sopenharmony_ci .shutdown = sock_no_shutdown, 42462306a36Sopenharmony_ci .setsockopt = sock_common_setsockopt, 42562306a36Sopenharmony_ci .getsockopt = sock_common_getsockopt, 42662306a36Sopenharmony_ci .sendmsg = ieee802154_sock_sendmsg, 42762306a36Sopenharmony_ci .recvmsg = sock_common_recvmsg, 42862306a36Sopenharmony_ci .mmap = sock_no_mmap, 42962306a36Sopenharmony_ci}; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci/* DGRAM Sockets (802.15.4 dataframes) */ 43262306a36Sopenharmony_cistatic HLIST_HEAD(dgram_head); 43362306a36Sopenharmony_cistatic DEFINE_RWLOCK(dgram_lock); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_cistruct dgram_sock { 43662306a36Sopenharmony_ci struct sock sk; 43762306a36Sopenharmony_ci 43862306a36Sopenharmony_ci struct ieee802154_addr src_addr; 43962306a36Sopenharmony_ci struct ieee802154_addr dst_addr; 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci unsigned int bound:1; 44262306a36Sopenharmony_ci unsigned int connected:1; 44362306a36Sopenharmony_ci unsigned int want_ack:1; 44462306a36Sopenharmony_ci unsigned int want_lqi:1; 44562306a36Sopenharmony_ci unsigned int secen:1; 44662306a36Sopenharmony_ci unsigned int secen_override:1; 44762306a36Sopenharmony_ci unsigned int seclevel:3; 44862306a36Sopenharmony_ci unsigned int seclevel_override:1; 44962306a36Sopenharmony_ci}; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_cistatic inline struct dgram_sock *dgram_sk(const struct sock *sk) 45262306a36Sopenharmony_ci{ 45362306a36Sopenharmony_ci return container_of(sk, struct dgram_sock, sk); 45462306a36Sopenharmony_ci} 45562306a36Sopenharmony_ci 45662306a36Sopenharmony_cistatic int dgram_hash(struct sock *sk) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci write_lock_bh(&dgram_lock); 45962306a36Sopenharmony_ci sk_add_node(sk, &dgram_head); 46062306a36Sopenharmony_ci write_unlock_bh(&dgram_lock); 46162306a36Sopenharmony_ci sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci return 0; 46462306a36Sopenharmony_ci} 46562306a36Sopenharmony_ci 46662306a36Sopenharmony_cistatic void dgram_unhash(struct sock *sk) 46762306a36Sopenharmony_ci{ 46862306a36Sopenharmony_ci write_lock_bh(&dgram_lock); 46962306a36Sopenharmony_ci if (sk_del_node_init(sk)) 47062306a36Sopenharmony_ci sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 47162306a36Sopenharmony_ci write_unlock_bh(&dgram_lock); 47262306a36Sopenharmony_ci} 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_cistatic int dgram_init(struct sock *sk) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci struct dgram_sock *ro = dgram_sk(sk); 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci ro->want_ack = 1; 47962306a36Sopenharmony_ci ro->want_lqi = 0; 48062306a36Sopenharmony_ci return 0; 48162306a36Sopenharmony_ci} 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_cistatic void dgram_close(struct sock *sk, long timeout) 48462306a36Sopenharmony_ci{ 48562306a36Sopenharmony_ci sk_common_release(sk); 48662306a36Sopenharmony_ci} 48762306a36Sopenharmony_ci 48862306a36Sopenharmony_cistatic int dgram_bind(struct sock *sk, struct sockaddr *uaddr, int len) 48962306a36Sopenharmony_ci{ 49062306a36Sopenharmony_ci struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; 49162306a36Sopenharmony_ci struct ieee802154_addr haddr; 49262306a36Sopenharmony_ci struct dgram_sock *ro = dgram_sk(sk); 49362306a36Sopenharmony_ci int err = -EINVAL; 49462306a36Sopenharmony_ci struct net_device *dev; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci lock_sock(sk); 49762306a36Sopenharmony_ci 49862306a36Sopenharmony_ci ro->bound = 0; 49962306a36Sopenharmony_ci 50062306a36Sopenharmony_ci err = ieee802154_sockaddr_check_size(addr, len); 50162306a36Sopenharmony_ci if (err < 0) 50262306a36Sopenharmony_ci goto out; 50362306a36Sopenharmony_ci 50462306a36Sopenharmony_ci if (addr->family != AF_IEEE802154) { 50562306a36Sopenharmony_ci err = -EINVAL; 50662306a36Sopenharmony_ci goto out; 50762306a36Sopenharmony_ci } 50862306a36Sopenharmony_ci 50962306a36Sopenharmony_ci ieee802154_addr_from_sa(&haddr, &addr->addr); 51062306a36Sopenharmony_ci dev = ieee802154_get_dev(sock_net(sk), &haddr); 51162306a36Sopenharmony_ci if (!dev) { 51262306a36Sopenharmony_ci err = -ENODEV; 51362306a36Sopenharmony_ci goto out; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci if (dev->type != ARPHRD_IEEE802154) { 51762306a36Sopenharmony_ci err = -ENODEV; 51862306a36Sopenharmony_ci goto out_put; 51962306a36Sopenharmony_ci } 52062306a36Sopenharmony_ci 52162306a36Sopenharmony_ci ro->src_addr = haddr; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci ro->bound = 1; 52462306a36Sopenharmony_ci err = 0; 52562306a36Sopenharmony_ciout_put: 52662306a36Sopenharmony_ci dev_put(dev); 52762306a36Sopenharmony_ciout: 52862306a36Sopenharmony_ci release_sock(sk); 52962306a36Sopenharmony_ci 53062306a36Sopenharmony_ci return err; 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_cistatic int dgram_ioctl(struct sock *sk, int cmd, int *karg) 53462306a36Sopenharmony_ci{ 53562306a36Sopenharmony_ci switch (cmd) { 53662306a36Sopenharmony_ci case SIOCOUTQ: 53762306a36Sopenharmony_ci { 53862306a36Sopenharmony_ci *karg = sk_wmem_alloc_get(sk); 53962306a36Sopenharmony_ci 54062306a36Sopenharmony_ci return 0; 54162306a36Sopenharmony_ci } 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci case SIOCINQ: 54462306a36Sopenharmony_ci { 54562306a36Sopenharmony_ci struct sk_buff *skb; 54662306a36Sopenharmony_ci 54762306a36Sopenharmony_ci *karg = 0; 54862306a36Sopenharmony_ci spin_lock_bh(&sk->sk_receive_queue.lock); 54962306a36Sopenharmony_ci skb = skb_peek(&sk->sk_receive_queue); 55062306a36Sopenharmony_ci if (skb) { 55162306a36Sopenharmony_ci /* We will only return the amount 55262306a36Sopenharmony_ci * of this packet since that is all 55362306a36Sopenharmony_ci * that will be read. 55462306a36Sopenharmony_ci */ 55562306a36Sopenharmony_ci *karg = skb->len - ieee802154_hdr_length(skb); 55662306a36Sopenharmony_ci } 55762306a36Sopenharmony_ci spin_unlock_bh(&sk->sk_receive_queue.lock); 55862306a36Sopenharmony_ci return 0; 55962306a36Sopenharmony_ci } 56062306a36Sopenharmony_ci } 56162306a36Sopenharmony_ci 56262306a36Sopenharmony_ci return -ENOIOCTLCMD; 56362306a36Sopenharmony_ci} 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_ci/* FIXME: autobind */ 56662306a36Sopenharmony_cistatic int dgram_connect(struct sock *sk, struct sockaddr *uaddr, 56762306a36Sopenharmony_ci int len) 56862306a36Sopenharmony_ci{ 56962306a36Sopenharmony_ci struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; 57062306a36Sopenharmony_ci struct dgram_sock *ro = dgram_sk(sk); 57162306a36Sopenharmony_ci int err = 0; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci err = ieee802154_sockaddr_check_size(addr, len); 57462306a36Sopenharmony_ci if (err < 0) 57562306a36Sopenharmony_ci return err; 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci if (addr->family != AF_IEEE802154) 57862306a36Sopenharmony_ci return -EINVAL; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci lock_sock(sk); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci if (!ro->bound) { 58362306a36Sopenharmony_ci err = -ENETUNREACH; 58462306a36Sopenharmony_ci goto out; 58562306a36Sopenharmony_ci } 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_ci ieee802154_addr_from_sa(&ro->dst_addr, &addr->addr); 58862306a36Sopenharmony_ci ro->connected = 1; 58962306a36Sopenharmony_ci 59062306a36Sopenharmony_ciout: 59162306a36Sopenharmony_ci release_sock(sk); 59262306a36Sopenharmony_ci return err; 59362306a36Sopenharmony_ci} 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_cistatic int dgram_disconnect(struct sock *sk, int flags) 59662306a36Sopenharmony_ci{ 59762306a36Sopenharmony_ci struct dgram_sock *ro = dgram_sk(sk); 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci lock_sock(sk); 60062306a36Sopenharmony_ci ro->connected = 0; 60162306a36Sopenharmony_ci release_sock(sk); 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ci return 0; 60462306a36Sopenharmony_ci} 60562306a36Sopenharmony_ci 60662306a36Sopenharmony_cistatic int dgram_sendmsg(struct sock *sk, struct msghdr *msg, size_t size) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci struct net_device *dev; 60962306a36Sopenharmony_ci unsigned int mtu; 61062306a36Sopenharmony_ci struct sk_buff *skb; 61162306a36Sopenharmony_ci struct ieee802154_mac_cb *cb; 61262306a36Sopenharmony_ci struct dgram_sock *ro = dgram_sk(sk); 61362306a36Sopenharmony_ci struct ieee802154_addr dst_addr; 61462306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_ieee802154*, daddr, msg->msg_name); 61562306a36Sopenharmony_ci int hlen, tlen; 61662306a36Sopenharmony_ci int err; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci if (msg->msg_flags & MSG_OOB) { 61962306a36Sopenharmony_ci pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags); 62062306a36Sopenharmony_ci return -EOPNOTSUPP; 62162306a36Sopenharmony_ci } 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci if (msg->msg_name) { 62462306a36Sopenharmony_ci if (ro->connected) 62562306a36Sopenharmony_ci return -EISCONN; 62662306a36Sopenharmony_ci if (msg->msg_namelen < IEEE802154_MIN_NAMELEN) 62762306a36Sopenharmony_ci return -EINVAL; 62862306a36Sopenharmony_ci err = ieee802154_sockaddr_check_size(daddr, msg->msg_namelen); 62962306a36Sopenharmony_ci if (err < 0) 63062306a36Sopenharmony_ci return err; 63162306a36Sopenharmony_ci ieee802154_addr_from_sa(&dst_addr, &daddr->addr); 63262306a36Sopenharmony_ci } else { 63362306a36Sopenharmony_ci if (!ro->connected) 63462306a36Sopenharmony_ci return -EDESTADDRREQ; 63562306a36Sopenharmony_ci dst_addr = ro->dst_addr; 63662306a36Sopenharmony_ci } 63762306a36Sopenharmony_ci 63862306a36Sopenharmony_ci if (!ro->bound) 63962306a36Sopenharmony_ci dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154); 64062306a36Sopenharmony_ci else 64162306a36Sopenharmony_ci dev = ieee802154_get_dev(sock_net(sk), &ro->src_addr); 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci if (!dev) { 64462306a36Sopenharmony_ci pr_debug("no dev\n"); 64562306a36Sopenharmony_ci err = -ENXIO; 64662306a36Sopenharmony_ci goto out; 64762306a36Sopenharmony_ci } 64862306a36Sopenharmony_ci mtu = IEEE802154_MTU; 64962306a36Sopenharmony_ci pr_debug("name = %s, mtu = %u\n", dev->name, mtu); 65062306a36Sopenharmony_ci 65162306a36Sopenharmony_ci if (size > mtu) { 65262306a36Sopenharmony_ci pr_debug("size = %zu, mtu = %u\n", size, mtu); 65362306a36Sopenharmony_ci err = -EMSGSIZE; 65462306a36Sopenharmony_ci goto out_dev; 65562306a36Sopenharmony_ci } 65662306a36Sopenharmony_ci 65762306a36Sopenharmony_ci hlen = LL_RESERVED_SPACE(dev); 65862306a36Sopenharmony_ci tlen = dev->needed_tailroom; 65962306a36Sopenharmony_ci skb = sock_alloc_send_skb(sk, hlen + tlen + size, 66062306a36Sopenharmony_ci msg->msg_flags & MSG_DONTWAIT, 66162306a36Sopenharmony_ci &err); 66262306a36Sopenharmony_ci if (!skb) 66362306a36Sopenharmony_ci goto out_dev; 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_ci skb_reserve(skb, hlen); 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci skb_reset_network_header(skb); 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci cb = mac_cb_init(skb); 67062306a36Sopenharmony_ci cb->type = IEEE802154_FC_TYPE_DATA; 67162306a36Sopenharmony_ci cb->ackreq = ro->want_ack; 67262306a36Sopenharmony_ci cb->secen = ro->secen; 67362306a36Sopenharmony_ci cb->secen_override = ro->secen_override; 67462306a36Sopenharmony_ci cb->seclevel = ro->seclevel; 67562306a36Sopenharmony_ci cb->seclevel_override = ro->seclevel_override; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci err = wpan_dev_hard_header(skb, dev, &dst_addr, 67862306a36Sopenharmony_ci ro->bound ? &ro->src_addr : NULL, size); 67962306a36Sopenharmony_ci if (err < 0) 68062306a36Sopenharmony_ci goto out_skb; 68162306a36Sopenharmony_ci 68262306a36Sopenharmony_ci err = memcpy_from_msg(skb_put(skb, size), msg, size); 68362306a36Sopenharmony_ci if (err < 0) 68462306a36Sopenharmony_ci goto out_skb; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci skb->dev = dev; 68762306a36Sopenharmony_ci skb->protocol = htons(ETH_P_IEEE802154); 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci err = dev_queue_xmit(skb); 69062306a36Sopenharmony_ci if (err > 0) 69162306a36Sopenharmony_ci err = net_xmit_errno(err); 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci dev_put(dev); 69462306a36Sopenharmony_ci 69562306a36Sopenharmony_ci return err ?: size; 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ciout_skb: 69862306a36Sopenharmony_ci kfree_skb(skb); 69962306a36Sopenharmony_ciout_dev: 70062306a36Sopenharmony_ci dev_put(dev); 70162306a36Sopenharmony_ciout: 70262306a36Sopenharmony_ci return err; 70362306a36Sopenharmony_ci} 70462306a36Sopenharmony_ci 70562306a36Sopenharmony_cistatic int dgram_recvmsg(struct sock *sk, struct msghdr *msg, size_t len, 70662306a36Sopenharmony_ci int flags, int *addr_len) 70762306a36Sopenharmony_ci{ 70862306a36Sopenharmony_ci size_t copied = 0; 70962306a36Sopenharmony_ci int err = -EOPNOTSUPP; 71062306a36Sopenharmony_ci struct sk_buff *skb; 71162306a36Sopenharmony_ci struct dgram_sock *ro = dgram_sk(sk); 71262306a36Sopenharmony_ci DECLARE_SOCKADDR(struct sockaddr_ieee802154 *, saddr, msg->msg_name); 71362306a36Sopenharmony_ci 71462306a36Sopenharmony_ci skb = skb_recv_datagram(sk, flags, &err); 71562306a36Sopenharmony_ci if (!skb) 71662306a36Sopenharmony_ci goto out; 71762306a36Sopenharmony_ci 71862306a36Sopenharmony_ci copied = skb->len; 71962306a36Sopenharmony_ci if (len < copied) { 72062306a36Sopenharmony_ci msg->msg_flags |= MSG_TRUNC; 72162306a36Sopenharmony_ci copied = len; 72262306a36Sopenharmony_ci } 72362306a36Sopenharmony_ci 72462306a36Sopenharmony_ci /* FIXME: skip headers if necessary ?! */ 72562306a36Sopenharmony_ci err = skb_copy_datagram_msg(skb, 0, msg, copied); 72662306a36Sopenharmony_ci if (err) 72762306a36Sopenharmony_ci goto done; 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci sock_recv_cmsgs(msg, sk, skb); 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (saddr) { 73262306a36Sopenharmony_ci /* Clear the implicit padding in struct sockaddr_ieee802154 73362306a36Sopenharmony_ci * (16 bits between 'family' and 'addr') and in struct 73462306a36Sopenharmony_ci * ieee802154_addr_sa (16 bits at the end of the structure). 73562306a36Sopenharmony_ci */ 73662306a36Sopenharmony_ci memset(saddr, 0, sizeof(*saddr)); 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_ci saddr->family = AF_IEEE802154; 73962306a36Sopenharmony_ci ieee802154_addr_to_sa(&saddr->addr, &mac_cb(skb)->source); 74062306a36Sopenharmony_ci *addr_len = sizeof(*saddr); 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci if (ro->want_lqi) { 74462306a36Sopenharmony_ci err = put_cmsg(msg, SOL_IEEE802154, WPAN_WANTLQI, 74562306a36Sopenharmony_ci sizeof(uint8_t), &(mac_cb(skb)->lqi)); 74662306a36Sopenharmony_ci if (err) 74762306a36Sopenharmony_ci goto done; 74862306a36Sopenharmony_ci } 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci if (flags & MSG_TRUNC) 75162306a36Sopenharmony_ci copied = skb->len; 75262306a36Sopenharmony_cidone: 75362306a36Sopenharmony_ci skb_free_datagram(sk, skb); 75462306a36Sopenharmony_ciout: 75562306a36Sopenharmony_ci if (err) 75662306a36Sopenharmony_ci return err; 75762306a36Sopenharmony_ci return copied; 75862306a36Sopenharmony_ci} 75962306a36Sopenharmony_ci 76062306a36Sopenharmony_cistatic int dgram_rcv_skb(struct sock *sk, struct sk_buff *skb) 76162306a36Sopenharmony_ci{ 76262306a36Sopenharmony_ci skb = skb_share_check(skb, GFP_ATOMIC); 76362306a36Sopenharmony_ci if (!skb) 76462306a36Sopenharmony_ci return NET_RX_DROP; 76562306a36Sopenharmony_ci 76662306a36Sopenharmony_ci if (sock_queue_rcv_skb(sk, skb) < 0) { 76762306a36Sopenharmony_ci kfree_skb(skb); 76862306a36Sopenharmony_ci return NET_RX_DROP; 76962306a36Sopenharmony_ci } 77062306a36Sopenharmony_ci 77162306a36Sopenharmony_ci return NET_RX_SUCCESS; 77262306a36Sopenharmony_ci} 77362306a36Sopenharmony_ci 77462306a36Sopenharmony_cistatic inline bool 77562306a36Sopenharmony_ciieee802154_match_sock(__le64 hw_addr, __le16 pan_id, __le16 short_addr, 77662306a36Sopenharmony_ci struct dgram_sock *ro) 77762306a36Sopenharmony_ci{ 77862306a36Sopenharmony_ci if (!ro->bound) 77962306a36Sopenharmony_ci return true; 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci if (ro->src_addr.mode == IEEE802154_ADDR_LONG && 78262306a36Sopenharmony_ci hw_addr == ro->src_addr.extended_addr) 78362306a36Sopenharmony_ci return true; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (ro->src_addr.mode == IEEE802154_ADDR_SHORT && 78662306a36Sopenharmony_ci pan_id == ro->src_addr.pan_id && 78762306a36Sopenharmony_ci short_addr == ro->src_addr.short_addr) 78862306a36Sopenharmony_ci return true; 78962306a36Sopenharmony_ci 79062306a36Sopenharmony_ci return false; 79162306a36Sopenharmony_ci} 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_cistatic int ieee802154_dgram_deliver(struct net_device *dev, struct sk_buff *skb) 79462306a36Sopenharmony_ci{ 79562306a36Sopenharmony_ci struct sock *sk, *prev = NULL; 79662306a36Sopenharmony_ci int ret = NET_RX_SUCCESS; 79762306a36Sopenharmony_ci __le16 pan_id, short_addr; 79862306a36Sopenharmony_ci __le64 hw_addr; 79962306a36Sopenharmony_ci 80062306a36Sopenharmony_ci /* Data frame processing */ 80162306a36Sopenharmony_ci BUG_ON(dev->type != ARPHRD_IEEE802154); 80262306a36Sopenharmony_ci 80362306a36Sopenharmony_ci pan_id = dev->ieee802154_ptr->pan_id; 80462306a36Sopenharmony_ci short_addr = dev->ieee802154_ptr->short_addr; 80562306a36Sopenharmony_ci hw_addr = dev->ieee802154_ptr->extended_addr; 80662306a36Sopenharmony_ci 80762306a36Sopenharmony_ci read_lock(&dgram_lock); 80862306a36Sopenharmony_ci sk_for_each(sk, &dgram_head) { 80962306a36Sopenharmony_ci if (ieee802154_match_sock(hw_addr, pan_id, short_addr, 81062306a36Sopenharmony_ci dgram_sk(sk))) { 81162306a36Sopenharmony_ci if (prev) { 81262306a36Sopenharmony_ci struct sk_buff *clone; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci clone = skb_clone(skb, GFP_ATOMIC); 81562306a36Sopenharmony_ci if (clone) 81662306a36Sopenharmony_ci dgram_rcv_skb(prev, clone); 81762306a36Sopenharmony_ci } 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci prev = sk; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci } 82262306a36Sopenharmony_ci 82362306a36Sopenharmony_ci if (prev) { 82462306a36Sopenharmony_ci dgram_rcv_skb(prev, skb); 82562306a36Sopenharmony_ci } else { 82662306a36Sopenharmony_ci kfree_skb(skb); 82762306a36Sopenharmony_ci ret = NET_RX_DROP; 82862306a36Sopenharmony_ci } 82962306a36Sopenharmony_ci read_unlock(&dgram_lock); 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci return ret; 83262306a36Sopenharmony_ci} 83362306a36Sopenharmony_ci 83462306a36Sopenharmony_cistatic int dgram_getsockopt(struct sock *sk, int level, int optname, 83562306a36Sopenharmony_ci char __user *optval, int __user *optlen) 83662306a36Sopenharmony_ci{ 83762306a36Sopenharmony_ci struct dgram_sock *ro = dgram_sk(sk); 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci int val, len; 84062306a36Sopenharmony_ci 84162306a36Sopenharmony_ci if (level != SOL_IEEE802154) 84262306a36Sopenharmony_ci return -EOPNOTSUPP; 84362306a36Sopenharmony_ci 84462306a36Sopenharmony_ci if (get_user(len, optlen)) 84562306a36Sopenharmony_ci return -EFAULT; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci len = min_t(unsigned int, len, sizeof(int)); 84862306a36Sopenharmony_ci 84962306a36Sopenharmony_ci switch (optname) { 85062306a36Sopenharmony_ci case WPAN_WANTACK: 85162306a36Sopenharmony_ci val = ro->want_ack; 85262306a36Sopenharmony_ci break; 85362306a36Sopenharmony_ci case WPAN_WANTLQI: 85462306a36Sopenharmony_ci val = ro->want_lqi; 85562306a36Sopenharmony_ci break; 85662306a36Sopenharmony_ci case WPAN_SECURITY: 85762306a36Sopenharmony_ci if (!ro->secen_override) 85862306a36Sopenharmony_ci val = WPAN_SECURITY_DEFAULT; 85962306a36Sopenharmony_ci else if (ro->secen) 86062306a36Sopenharmony_ci val = WPAN_SECURITY_ON; 86162306a36Sopenharmony_ci else 86262306a36Sopenharmony_ci val = WPAN_SECURITY_OFF; 86362306a36Sopenharmony_ci break; 86462306a36Sopenharmony_ci case WPAN_SECURITY_LEVEL: 86562306a36Sopenharmony_ci if (!ro->seclevel_override) 86662306a36Sopenharmony_ci val = WPAN_SECURITY_LEVEL_DEFAULT; 86762306a36Sopenharmony_ci else 86862306a36Sopenharmony_ci val = ro->seclevel; 86962306a36Sopenharmony_ci break; 87062306a36Sopenharmony_ci default: 87162306a36Sopenharmony_ci return -ENOPROTOOPT; 87262306a36Sopenharmony_ci } 87362306a36Sopenharmony_ci 87462306a36Sopenharmony_ci if (put_user(len, optlen)) 87562306a36Sopenharmony_ci return -EFAULT; 87662306a36Sopenharmony_ci if (copy_to_user(optval, &val, len)) 87762306a36Sopenharmony_ci return -EFAULT; 87862306a36Sopenharmony_ci return 0; 87962306a36Sopenharmony_ci} 88062306a36Sopenharmony_ci 88162306a36Sopenharmony_cistatic int dgram_setsockopt(struct sock *sk, int level, int optname, 88262306a36Sopenharmony_ci sockptr_t optval, unsigned int optlen) 88362306a36Sopenharmony_ci{ 88462306a36Sopenharmony_ci struct dgram_sock *ro = dgram_sk(sk); 88562306a36Sopenharmony_ci struct net *net = sock_net(sk); 88662306a36Sopenharmony_ci int val; 88762306a36Sopenharmony_ci int err = 0; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci if (optlen < sizeof(int)) 89062306a36Sopenharmony_ci return -EINVAL; 89162306a36Sopenharmony_ci 89262306a36Sopenharmony_ci if (copy_from_sockptr(&val, optval, sizeof(int))) 89362306a36Sopenharmony_ci return -EFAULT; 89462306a36Sopenharmony_ci 89562306a36Sopenharmony_ci lock_sock(sk); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci switch (optname) { 89862306a36Sopenharmony_ci case WPAN_WANTACK: 89962306a36Sopenharmony_ci ro->want_ack = !!val; 90062306a36Sopenharmony_ci break; 90162306a36Sopenharmony_ci case WPAN_WANTLQI: 90262306a36Sopenharmony_ci ro->want_lqi = !!val; 90362306a36Sopenharmony_ci break; 90462306a36Sopenharmony_ci case WPAN_SECURITY: 90562306a36Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN) && 90662306a36Sopenharmony_ci !ns_capable(net->user_ns, CAP_NET_RAW)) { 90762306a36Sopenharmony_ci err = -EPERM; 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci } 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci switch (val) { 91262306a36Sopenharmony_ci case WPAN_SECURITY_DEFAULT: 91362306a36Sopenharmony_ci ro->secen_override = 0; 91462306a36Sopenharmony_ci break; 91562306a36Sopenharmony_ci case WPAN_SECURITY_ON: 91662306a36Sopenharmony_ci ro->secen_override = 1; 91762306a36Sopenharmony_ci ro->secen = 1; 91862306a36Sopenharmony_ci break; 91962306a36Sopenharmony_ci case WPAN_SECURITY_OFF: 92062306a36Sopenharmony_ci ro->secen_override = 1; 92162306a36Sopenharmony_ci ro->secen = 0; 92262306a36Sopenharmony_ci break; 92362306a36Sopenharmony_ci default: 92462306a36Sopenharmony_ci err = -EINVAL; 92562306a36Sopenharmony_ci break; 92662306a36Sopenharmony_ci } 92762306a36Sopenharmony_ci break; 92862306a36Sopenharmony_ci case WPAN_SECURITY_LEVEL: 92962306a36Sopenharmony_ci if (!ns_capable(net->user_ns, CAP_NET_ADMIN) && 93062306a36Sopenharmony_ci !ns_capable(net->user_ns, CAP_NET_RAW)) { 93162306a36Sopenharmony_ci err = -EPERM; 93262306a36Sopenharmony_ci break; 93362306a36Sopenharmony_ci } 93462306a36Sopenharmony_ci 93562306a36Sopenharmony_ci if (val < WPAN_SECURITY_LEVEL_DEFAULT || 93662306a36Sopenharmony_ci val > IEEE802154_SCF_SECLEVEL_ENC_MIC128) { 93762306a36Sopenharmony_ci err = -EINVAL; 93862306a36Sopenharmony_ci } else if (val == WPAN_SECURITY_LEVEL_DEFAULT) { 93962306a36Sopenharmony_ci ro->seclevel_override = 0; 94062306a36Sopenharmony_ci } else { 94162306a36Sopenharmony_ci ro->seclevel_override = 1; 94262306a36Sopenharmony_ci ro->seclevel = val; 94362306a36Sopenharmony_ci } 94462306a36Sopenharmony_ci break; 94562306a36Sopenharmony_ci default: 94662306a36Sopenharmony_ci err = -ENOPROTOOPT; 94762306a36Sopenharmony_ci break; 94862306a36Sopenharmony_ci } 94962306a36Sopenharmony_ci 95062306a36Sopenharmony_ci release_sock(sk); 95162306a36Sopenharmony_ci return err; 95262306a36Sopenharmony_ci} 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_cistatic struct proto ieee802154_dgram_prot = { 95562306a36Sopenharmony_ci .name = "IEEE-802.15.4-MAC", 95662306a36Sopenharmony_ci .owner = THIS_MODULE, 95762306a36Sopenharmony_ci .obj_size = sizeof(struct dgram_sock), 95862306a36Sopenharmony_ci .init = dgram_init, 95962306a36Sopenharmony_ci .close = dgram_close, 96062306a36Sopenharmony_ci .bind = dgram_bind, 96162306a36Sopenharmony_ci .sendmsg = dgram_sendmsg, 96262306a36Sopenharmony_ci .recvmsg = dgram_recvmsg, 96362306a36Sopenharmony_ci .hash = dgram_hash, 96462306a36Sopenharmony_ci .unhash = dgram_unhash, 96562306a36Sopenharmony_ci .connect = dgram_connect, 96662306a36Sopenharmony_ci .disconnect = dgram_disconnect, 96762306a36Sopenharmony_ci .ioctl = dgram_ioctl, 96862306a36Sopenharmony_ci .getsockopt = dgram_getsockopt, 96962306a36Sopenharmony_ci .setsockopt = dgram_setsockopt, 97062306a36Sopenharmony_ci}; 97162306a36Sopenharmony_ci 97262306a36Sopenharmony_cistatic const struct proto_ops ieee802154_dgram_ops = { 97362306a36Sopenharmony_ci .family = PF_IEEE802154, 97462306a36Sopenharmony_ci .owner = THIS_MODULE, 97562306a36Sopenharmony_ci .release = ieee802154_sock_release, 97662306a36Sopenharmony_ci .bind = ieee802154_sock_bind, 97762306a36Sopenharmony_ci .connect = ieee802154_sock_connect, 97862306a36Sopenharmony_ci .socketpair = sock_no_socketpair, 97962306a36Sopenharmony_ci .accept = sock_no_accept, 98062306a36Sopenharmony_ci .getname = sock_no_getname, 98162306a36Sopenharmony_ci .poll = datagram_poll, 98262306a36Sopenharmony_ci .ioctl = ieee802154_sock_ioctl, 98362306a36Sopenharmony_ci .gettstamp = sock_gettstamp, 98462306a36Sopenharmony_ci .listen = sock_no_listen, 98562306a36Sopenharmony_ci .shutdown = sock_no_shutdown, 98662306a36Sopenharmony_ci .setsockopt = sock_common_setsockopt, 98762306a36Sopenharmony_ci .getsockopt = sock_common_getsockopt, 98862306a36Sopenharmony_ci .sendmsg = ieee802154_sock_sendmsg, 98962306a36Sopenharmony_ci .recvmsg = sock_common_recvmsg, 99062306a36Sopenharmony_ci .mmap = sock_no_mmap, 99162306a36Sopenharmony_ci}; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_cistatic void ieee802154_sock_destruct(struct sock *sk) 99462306a36Sopenharmony_ci{ 99562306a36Sopenharmony_ci skb_queue_purge(&sk->sk_receive_queue); 99662306a36Sopenharmony_ci} 99762306a36Sopenharmony_ci 99862306a36Sopenharmony_ci/* Create a socket. Initialise the socket, blank the addresses 99962306a36Sopenharmony_ci * set the state. 100062306a36Sopenharmony_ci */ 100162306a36Sopenharmony_cistatic int ieee802154_create(struct net *net, struct socket *sock, 100262306a36Sopenharmony_ci int protocol, int kern) 100362306a36Sopenharmony_ci{ 100462306a36Sopenharmony_ci struct sock *sk; 100562306a36Sopenharmony_ci int rc; 100662306a36Sopenharmony_ci struct proto *proto; 100762306a36Sopenharmony_ci const struct proto_ops *ops; 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_ci if (!net_eq(net, &init_net)) 101062306a36Sopenharmony_ci return -EAFNOSUPPORT; 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci switch (sock->type) { 101362306a36Sopenharmony_ci case SOCK_RAW: 101462306a36Sopenharmony_ci rc = -EPERM; 101562306a36Sopenharmony_ci if (!capable(CAP_NET_RAW)) 101662306a36Sopenharmony_ci goto out; 101762306a36Sopenharmony_ci proto = &ieee802154_raw_prot; 101862306a36Sopenharmony_ci ops = &ieee802154_raw_ops; 101962306a36Sopenharmony_ci break; 102062306a36Sopenharmony_ci case SOCK_DGRAM: 102162306a36Sopenharmony_ci proto = &ieee802154_dgram_prot; 102262306a36Sopenharmony_ci ops = &ieee802154_dgram_ops; 102362306a36Sopenharmony_ci break; 102462306a36Sopenharmony_ci default: 102562306a36Sopenharmony_ci rc = -ESOCKTNOSUPPORT; 102662306a36Sopenharmony_ci goto out; 102762306a36Sopenharmony_ci } 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci rc = -ENOMEM; 103062306a36Sopenharmony_ci sk = sk_alloc(net, PF_IEEE802154, GFP_KERNEL, proto, kern); 103162306a36Sopenharmony_ci if (!sk) 103262306a36Sopenharmony_ci goto out; 103362306a36Sopenharmony_ci rc = 0; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci sock->ops = ops; 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci sock_init_data(sock, sk); 103862306a36Sopenharmony_ci sk->sk_destruct = ieee802154_sock_destruct; 103962306a36Sopenharmony_ci sk->sk_family = PF_IEEE802154; 104062306a36Sopenharmony_ci 104162306a36Sopenharmony_ci /* Checksums on by default */ 104262306a36Sopenharmony_ci sock_set_flag(sk, SOCK_ZAPPED); 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_ci if (sk->sk_prot->hash) { 104562306a36Sopenharmony_ci rc = sk->sk_prot->hash(sk); 104662306a36Sopenharmony_ci if (rc) { 104762306a36Sopenharmony_ci sk_common_release(sk); 104862306a36Sopenharmony_ci goto out; 104962306a36Sopenharmony_ci } 105062306a36Sopenharmony_ci } 105162306a36Sopenharmony_ci 105262306a36Sopenharmony_ci if (sk->sk_prot->init) { 105362306a36Sopenharmony_ci rc = sk->sk_prot->init(sk); 105462306a36Sopenharmony_ci if (rc) 105562306a36Sopenharmony_ci sk_common_release(sk); 105662306a36Sopenharmony_ci } 105762306a36Sopenharmony_ciout: 105862306a36Sopenharmony_ci return rc; 105962306a36Sopenharmony_ci} 106062306a36Sopenharmony_ci 106162306a36Sopenharmony_cistatic const struct net_proto_family ieee802154_family_ops = { 106262306a36Sopenharmony_ci .family = PF_IEEE802154, 106362306a36Sopenharmony_ci .create = ieee802154_create, 106462306a36Sopenharmony_ci .owner = THIS_MODULE, 106562306a36Sopenharmony_ci}; 106662306a36Sopenharmony_ci 106762306a36Sopenharmony_cistatic int ieee802154_rcv(struct sk_buff *skb, struct net_device *dev, 106862306a36Sopenharmony_ci struct packet_type *pt, struct net_device *orig_dev) 106962306a36Sopenharmony_ci{ 107062306a36Sopenharmony_ci if (!netif_running(dev)) 107162306a36Sopenharmony_ci goto drop; 107262306a36Sopenharmony_ci pr_debug("got frame, type %d, dev %p\n", dev->type, dev); 107362306a36Sopenharmony_ci#ifdef DEBUG 107462306a36Sopenharmony_ci print_hex_dump_bytes("ieee802154_rcv ", 107562306a36Sopenharmony_ci DUMP_PREFIX_NONE, skb->data, skb->len); 107662306a36Sopenharmony_ci#endif 107762306a36Sopenharmony_ci 107862306a36Sopenharmony_ci if (!net_eq(dev_net(dev), &init_net)) 107962306a36Sopenharmony_ci goto drop; 108062306a36Sopenharmony_ci 108162306a36Sopenharmony_ci ieee802154_raw_deliver(dev, skb); 108262306a36Sopenharmony_ci 108362306a36Sopenharmony_ci if (dev->type != ARPHRD_IEEE802154) 108462306a36Sopenharmony_ci goto drop; 108562306a36Sopenharmony_ci 108662306a36Sopenharmony_ci if (skb->pkt_type != PACKET_OTHERHOST) 108762306a36Sopenharmony_ci return ieee802154_dgram_deliver(dev, skb); 108862306a36Sopenharmony_ci 108962306a36Sopenharmony_cidrop: 109062306a36Sopenharmony_ci kfree_skb(skb); 109162306a36Sopenharmony_ci return NET_RX_DROP; 109262306a36Sopenharmony_ci} 109362306a36Sopenharmony_ci 109462306a36Sopenharmony_cistatic struct packet_type ieee802154_packet_type = { 109562306a36Sopenharmony_ci .type = htons(ETH_P_IEEE802154), 109662306a36Sopenharmony_ci .func = ieee802154_rcv, 109762306a36Sopenharmony_ci}; 109862306a36Sopenharmony_ci 109962306a36Sopenharmony_cistatic int __init af_ieee802154_init(void) 110062306a36Sopenharmony_ci{ 110162306a36Sopenharmony_ci int rc; 110262306a36Sopenharmony_ci 110362306a36Sopenharmony_ci rc = proto_register(&ieee802154_raw_prot, 1); 110462306a36Sopenharmony_ci if (rc) 110562306a36Sopenharmony_ci goto out; 110662306a36Sopenharmony_ci 110762306a36Sopenharmony_ci rc = proto_register(&ieee802154_dgram_prot, 1); 110862306a36Sopenharmony_ci if (rc) 110962306a36Sopenharmony_ci goto err_dgram; 111062306a36Sopenharmony_ci 111162306a36Sopenharmony_ci /* Tell SOCKET that we are alive */ 111262306a36Sopenharmony_ci rc = sock_register(&ieee802154_family_ops); 111362306a36Sopenharmony_ci if (rc) 111462306a36Sopenharmony_ci goto err_sock; 111562306a36Sopenharmony_ci dev_add_pack(&ieee802154_packet_type); 111662306a36Sopenharmony_ci 111762306a36Sopenharmony_ci rc = 0; 111862306a36Sopenharmony_ci goto out; 111962306a36Sopenharmony_ci 112062306a36Sopenharmony_cierr_sock: 112162306a36Sopenharmony_ci proto_unregister(&ieee802154_dgram_prot); 112262306a36Sopenharmony_cierr_dgram: 112362306a36Sopenharmony_ci proto_unregister(&ieee802154_raw_prot); 112462306a36Sopenharmony_ciout: 112562306a36Sopenharmony_ci return rc; 112662306a36Sopenharmony_ci} 112762306a36Sopenharmony_ci 112862306a36Sopenharmony_cistatic void __exit af_ieee802154_remove(void) 112962306a36Sopenharmony_ci{ 113062306a36Sopenharmony_ci dev_remove_pack(&ieee802154_packet_type); 113162306a36Sopenharmony_ci sock_unregister(PF_IEEE802154); 113262306a36Sopenharmony_ci proto_unregister(&ieee802154_dgram_prot); 113362306a36Sopenharmony_ci proto_unregister(&ieee802154_raw_prot); 113462306a36Sopenharmony_ci} 113562306a36Sopenharmony_ci 113662306a36Sopenharmony_cimodule_init(af_ieee802154_init); 113762306a36Sopenharmony_cimodule_exit(af_ieee802154_remove); 113862306a36Sopenharmony_ci 113962306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 114062306a36Sopenharmony_ciMODULE_ALIAS_NETPROTO(PF_IEEE802154); 1141