1/* 2 * Raw IEEE 802.15.4 sockets 3 * 4 * Copyright 2007, 2008 Siemens AG 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 8 * as published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License along 16 * with this program; if not, write to the Free Software Foundation, Inc., 17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Written by: 20 * Sergey Lapin <slapin@ossfans.org> 21 * Dmitry Eremin-Solenikov <dbaryshkov@gmail.com> 22 */ 23 24#include <linux/net.h> 25#include <linux/module.h> 26#include <linux/if_arp.h> 27#include <linux/list.h> 28#include <linux/slab.h> 29#include <net/sock.h> 30#include <net/af_ieee802154.h> 31 32#include "af802154.h" 33 34static HLIST_HEAD(raw_head); 35static DEFINE_RWLOCK(raw_lock); 36 37static void raw_hash(struct sock *sk) 38{ 39 write_lock_bh(&raw_lock); 40 sk_add_node(sk, &raw_head); 41 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1); 42 write_unlock_bh(&raw_lock); 43} 44 45static void raw_unhash(struct sock *sk) 46{ 47 write_lock_bh(&raw_lock); 48 if (sk_del_node_init(sk)) 49 sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1); 50 write_unlock_bh(&raw_lock); 51} 52 53static void raw_close(struct sock *sk, long timeout) 54{ 55 sk_common_release(sk); 56} 57 58static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int len) 59{ 60 struct sockaddr_ieee802154 *addr = (struct sockaddr_ieee802154 *)uaddr; 61 int err = 0; 62 struct net_device *dev = NULL; 63 64 if (len < sizeof(*addr)) 65 return -EINVAL; 66 67 if (addr->family != AF_IEEE802154) 68 return -EINVAL; 69 70 lock_sock(sk); 71 72 dev = ieee802154_get_dev(sock_net(sk), &addr->addr); 73 if (!dev) { 74 err = -ENODEV; 75 goto out; 76 } 77 78 if (dev->type != ARPHRD_IEEE802154) { 79 err = -ENODEV; 80 goto out_put; 81 } 82 83 sk->sk_bound_dev_if = dev->ifindex; 84 sk_dst_reset(sk); 85 86out_put: 87 dev_put(dev); 88out: 89 release_sock(sk); 90 91 return err; 92} 93 94static int raw_connect(struct sock *sk, struct sockaddr *uaddr, 95 int addr_len) 96{ 97 return -ENOTSUPP; 98} 99 100static int raw_disconnect(struct sock *sk, int flags) 101{ 102 return 0; 103} 104 105static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 106 size_t size) 107{ 108 struct net_device *dev; 109 unsigned mtu; 110 struct sk_buff *skb; 111 int err; 112 113 if (msg->msg_flags & MSG_OOB) { 114 pr_debug("msg->msg_flags = 0x%x\n", msg->msg_flags); 115 return -EOPNOTSUPP; 116 } 117 118 lock_sock(sk); 119 if (!sk->sk_bound_dev_if) 120 dev = dev_getfirstbyhwtype(sock_net(sk), ARPHRD_IEEE802154); 121 else 122 dev = dev_get_by_index(sock_net(sk), sk->sk_bound_dev_if); 123 release_sock(sk); 124 125 if (!dev) { 126 pr_debug("no dev\n"); 127 err = -ENXIO; 128 goto out; 129 } 130 131 mtu = dev->mtu; 132 pr_debug("name = %s, mtu = %u\n", dev->name, mtu); 133 134 if (size > mtu) { 135 pr_debug("size = %Zu, mtu = %u\n", size, mtu); 136 err = -EINVAL; 137 goto out_dev; 138 } 139 140 skb = sock_alloc_send_skb(sk, LL_ALLOCATED_SPACE(dev) + size, 141 msg->msg_flags & MSG_DONTWAIT, &err); 142 if (!skb) 143 goto out_dev; 144 145 skb_reserve(skb, LL_RESERVED_SPACE(dev)); 146 147 skb_reset_mac_header(skb); 148 skb_reset_network_header(skb); 149 150 err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size); 151 if (err < 0) 152 goto out_skb; 153 154 skb->dev = dev; 155 skb->sk = sk; 156 skb->protocol = htons(ETH_P_IEEE802154); 157 158 dev_put(dev); 159 160 err = dev_queue_xmit(skb); 161 if (err > 0) 162 err = net_xmit_errno(err); 163 164 return err ?: size; 165 166out_skb: 167 kfree_skb(skb); 168out_dev: 169 dev_put(dev); 170out: 171 return err; 172} 173 174static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, 175 size_t len, int noblock, int flags, int *addr_len) 176{ 177 size_t copied = 0; 178 int err = -EOPNOTSUPP; 179 struct sk_buff *skb; 180 181 skb = skb_recv_datagram(sk, flags, noblock, &err); 182 if (!skb) 183 goto out; 184 185 copied = skb->len; 186 if (len < copied) { 187 msg->msg_flags |= MSG_TRUNC; 188 copied = len; 189 } 190 191 err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); 192 if (err) 193 goto done; 194 195 sock_recv_ts_and_drops(msg, sk, skb); 196 197 if (flags & MSG_TRUNC) 198 copied = skb->len; 199done: 200 skb_free_datagram(sk, skb); 201out: 202 if (err) 203 return err; 204 return copied; 205} 206 207static int raw_rcv_skb(struct sock *sk, struct sk_buff *skb) 208{ 209 if (sock_queue_rcv_skb(sk, skb) < 0) { 210 kfree_skb(skb); 211 return NET_RX_DROP; 212 } 213 214 return NET_RX_SUCCESS; 215} 216 217 218void ieee802154_raw_deliver(struct net_device *dev, struct sk_buff *skb) 219{ 220 struct sock *sk; 221 struct hlist_node *node; 222 223 read_lock(&raw_lock); 224 sk_for_each(sk, node, &raw_head) { 225 bh_lock_sock(sk); 226 if (!sk->sk_bound_dev_if || 227 sk->sk_bound_dev_if == dev->ifindex) { 228 229 struct sk_buff *clone; 230 231 clone = skb_clone(skb, GFP_ATOMIC); 232 if (clone) 233 raw_rcv_skb(sk, clone); 234 } 235 bh_unlock_sock(sk); 236 } 237 read_unlock(&raw_lock); 238} 239 240static int raw_getsockopt(struct sock *sk, int level, int optname, 241 char __user *optval, int __user *optlen) 242{ 243 return -EOPNOTSUPP; 244} 245 246static int raw_setsockopt(struct sock *sk, int level, int optname, 247 char __user *optval, unsigned int optlen) 248{ 249 return -EOPNOTSUPP; 250} 251 252struct proto ieee802154_raw_prot = { 253 .name = "IEEE-802.15.4-RAW", 254 .owner = THIS_MODULE, 255 .obj_size = sizeof(struct sock), 256 .close = raw_close, 257 .bind = raw_bind, 258 .sendmsg = raw_sendmsg, 259 .recvmsg = raw_recvmsg, 260 .hash = raw_hash, 261 .unhash = raw_unhash, 262 .connect = raw_connect, 263 .disconnect = raw_disconnect, 264 .getsockopt = raw_getsockopt, 265 .setsockopt = raw_setsockopt, 266}; 267