| Rémi Denis-Courmont | 02a4761 | 2008-10-05 11:16:16 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * File: pep-gprs.c | 
|  | 3 | * | 
|  | 4 | * GPRS over Phonet pipe end point socket | 
|  | 5 | * | 
|  | 6 | * Copyright (C) 2008 Nokia Corporation. | 
|  | 7 | * | 
|  | 8 | * Author: Rémi Denis-Courmont <remi.denis-courmont@nokia.com> | 
|  | 9 | * | 
|  | 10 | * This program is free software; you can redistribute it and/or | 
|  | 11 | * modify it under the terms of the GNU General Public License | 
|  | 12 | * version 2 as published by the Free Software Foundation. | 
|  | 13 | * | 
|  | 14 | * This program is distributed in the hope that it will be useful, but | 
|  | 15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | 17 | * General Public License for more details. | 
|  | 18 | * | 
|  | 19 | * You should have received a copy of the GNU General Public License | 
|  | 20 | * along with this program; if not, write to the Free Software | 
|  | 21 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA | 
|  | 22 | * 02110-1301 USA | 
|  | 23 | */ | 
|  | 24 |  | 
|  | 25 | #include <linux/kernel.h> | 
|  | 26 | #include <linux/netdevice.h> | 
|  | 27 | #include <linux/if_ether.h> | 
|  | 28 | #include <linux/if_arp.h> | 
|  | 29 | #include <net/sock.h> | 
|  | 30 |  | 
|  | 31 | #include <linux/if_phonet.h> | 
|  | 32 | #include <net/tcp_states.h> | 
|  | 33 | #include <net/phonet/gprs.h> | 
|  | 34 |  | 
|  | 35 | #define GPRS_DEFAULT_MTU 1400 | 
|  | 36 |  | 
|  | 37 | struct gprs_dev { | 
|  | 38 | struct sock		*sk; | 
|  | 39 | void			(*old_state_change)(struct sock *); | 
|  | 40 | void			(*old_data_ready)(struct sock *, int); | 
|  | 41 | void			(*old_write_space)(struct sock *); | 
|  | 42 |  | 
|  | 43 | struct net_device	*net; | 
|  | 44 | struct net_device_stats	stats; | 
|  | 45 |  | 
|  | 46 | struct sk_buff_head	tx_queue; | 
|  | 47 | struct work_struct	tx_work; | 
|  | 48 | spinlock_t		tx_lock; | 
|  | 49 | unsigned		tx_max; | 
|  | 50 | }; | 
|  | 51 |  | 
|  | 52 | static int gprs_type_trans(struct sk_buff *skb) | 
|  | 53 | { | 
|  | 54 | const u8 *pvfc; | 
|  | 55 | u8 buf; | 
|  | 56 |  | 
|  | 57 | pvfc = skb_header_pointer(skb, 0, 1, &buf); | 
|  | 58 | if (!pvfc) | 
|  | 59 | return 0; | 
|  | 60 | /* Look at IP version field */ | 
|  | 61 | switch (*pvfc >> 4) { | 
|  | 62 | case 4: | 
|  | 63 | return htons(ETH_P_IP); | 
|  | 64 | case 6: | 
|  | 65 | return htons(ETH_P_IPV6); | 
|  | 66 | } | 
|  | 67 | return 0; | 
|  | 68 | } | 
|  | 69 |  | 
|  | 70 | /* | 
|  | 71 | * Socket callbacks | 
|  | 72 | */ | 
|  | 73 |  | 
|  | 74 | static void gprs_state_change(struct sock *sk) | 
|  | 75 | { | 
|  | 76 | struct gprs_dev *dev = sk->sk_user_data; | 
|  | 77 |  | 
|  | 78 | if (sk->sk_state == TCP_CLOSE_WAIT) { | 
|  | 79 | netif_stop_queue(dev->net); | 
|  | 80 | netif_carrier_off(dev->net); | 
|  | 81 | } | 
|  | 82 | } | 
|  | 83 |  | 
|  | 84 | static int gprs_recv(struct gprs_dev *dev, struct sk_buff *skb) | 
|  | 85 | { | 
|  | 86 | int err = 0; | 
|  | 87 | u16 protocol = gprs_type_trans(skb); | 
|  | 88 |  | 
|  | 89 | if (!protocol) { | 
|  | 90 | err = -EINVAL; | 
|  | 91 | goto drop; | 
|  | 92 | } | 
|  | 93 |  | 
|  | 94 | if (likely(skb_headroom(skb) & 3)) { | 
|  | 95 | struct sk_buff *rskb, *fs; | 
|  | 96 | int flen = 0; | 
|  | 97 |  | 
|  | 98 | /* Phonet Pipe data header is misaligned (3 bytes), | 
|  | 99 | * so wrap the IP packet as a single fragment of an head-less | 
|  | 100 | * socket buffer. The network stack will pull what it needs, | 
|  | 101 | * but at least, the whole IP payload is not memcpy'd. */ | 
|  | 102 | rskb = netdev_alloc_skb(dev->net, 0); | 
|  | 103 | if (!rskb) { | 
|  | 104 | err = -ENOBUFS; | 
|  | 105 | goto drop; | 
|  | 106 | } | 
|  | 107 | skb_shinfo(rskb)->frag_list = skb; | 
|  | 108 | rskb->len += skb->len; | 
|  | 109 | rskb->data_len += rskb->len; | 
|  | 110 | rskb->truesize += rskb->len; | 
|  | 111 |  | 
|  | 112 | /* Avoid nested fragments */ | 
|  | 113 | for (fs = skb_shinfo(skb)->frag_list; fs; fs = fs->next) | 
|  | 114 | flen += fs->len; | 
|  | 115 | skb->next = skb_shinfo(skb)->frag_list; | 
|  | 116 | skb_shinfo(skb)->frag_list = NULL; | 
|  | 117 | skb->len -= flen; | 
|  | 118 | skb->data_len -= flen; | 
|  | 119 | skb->truesize -= flen; | 
|  | 120 |  | 
|  | 121 | skb = rskb; | 
|  | 122 | } | 
|  | 123 |  | 
|  | 124 | skb->protocol = protocol; | 
|  | 125 | skb_reset_mac_header(skb); | 
|  | 126 | skb->dev = dev->net; | 
|  | 127 |  | 
|  | 128 | if (likely(dev->net->flags & IFF_UP)) { | 
|  | 129 | dev->stats.rx_packets++; | 
|  | 130 | dev->stats.rx_bytes += skb->len; | 
|  | 131 | netif_rx(skb); | 
|  | 132 | skb = NULL; | 
|  | 133 | } else | 
|  | 134 | err = -ENODEV; | 
|  | 135 |  | 
|  | 136 | drop: | 
|  | 137 | if (skb) { | 
|  | 138 | dev_kfree_skb(skb); | 
|  | 139 | dev->stats.rx_dropped++; | 
|  | 140 | } | 
|  | 141 | return err; | 
|  | 142 | } | 
|  | 143 |  | 
|  | 144 | static void gprs_data_ready(struct sock *sk, int len) | 
|  | 145 | { | 
|  | 146 | struct gprs_dev *dev = sk->sk_user_data; | 
|  | 147 | struct sk_buff *skb; | 
|  | 148 |  | 
|  | 149 | while ((skb = pep_read(sk)) != NULL) { | 
|  | 150 | skb_orphan(skb); | 
|  | 151 | gprs_recv(dev, skb); | 
|  | 152 | } | 
|  | 153 | } | 
|  | 154 |  | 
|  | 155 | static void gprs_write_space(struct sock *sk) | 
|  | 156 | { | 
|  | 157 | struct gprs_dev *dev = sk->sk_user_data; | 
|  | 158 | unsigned credits = pep_writeable(sk); | 
|  | 159 |  | 
|  | 160 | spin_lock_bh(&dev->tx_lock); | 
|  | 161 | dev->tx_max = credits; | 
|  | 162 | if (credits > skb_queue_len(&dev->tx_queue)) | 
|  | 163 | netif_wake_queue(dev->net); | 
|  | 164 | spin_unlock_bh(&dev->tx_lock); | 
|  | 165 | } | 
|  | 166 |  | 
|  | 167 | /* | 
|  | 168 | * Network device callbacks | 
|  | 169 | */ | 
|  | 170 |  | 
|  | 171 | static int gprs_xmit(struct sk_buff *skb, struct net_device *net) | 
|  | 172 | { | 
|  | 173 | struct gprs_dev *dev = netdev_priv(net); | 
|  | 174 |  | 
|  | 175 | switch (skb->protocol) { | 
|  | 176 | case  htons(ETH_P_IP): | 
|  | 177 | case  htons(ETH_P_IPV6): | 
|  | 178 | break; | 
|  | 179 | default: | 
|  | 180 | dev_kfree_skb(skb); | 
|  | 181 | return 0; | 
|  | 182 | } | 
|  | 183 |  | 
|  | 184 | spin_lock(&dev->tx_lock); | 
|  | 185 | if (likely(skb_queue_len(&dev->tx_queue) < dev->tx_max)) { | 
|  | 186 | skb_queue_tail(&dev->tx_queue, skb); | 
|  | 187 | skb = NULL; | 
|  | 188 | } | 
|  | 189 | if (skb_queue_len(&dev->tx_queue) >= dev->tx_max) | 
|  | 190 | netif_stop_queue(net); | 
|  | 191 | spin_unlock(&dev->tx_lock); | 
|  | 192 |  | 
|  | 193 | schedule_work(&dev->tx_work); | 
|  | 194 | if (unlikely(skb)) | 
|  | 195 | dev_kfree_skb(skb); | 
|  | 196 | return 0; | 
|  | 197 | } | 
|  | 198 |  | 
|  | 199 | static void gprs_tx(struct work_struct *work) | 
|  | 200 | { | 
|  | 201 | struct gprs_dev *dev = container_of(work, struct gprs_dev, tx_work); | 
|  | 202 | struct sock *sk = dev->sk; | 
|  | 203 | struct sk_buff *skb; | 
|  | 204 |  | 
|  | 205 | while ((skb = skb_dequeue(&dev->tx_queue)) != NULL) { | 
|  | 206 | int err; | 
|  | 207 |  | 
|  | 208 | dev->stats.tx_bytes += skb->len; | 
|  | 209 | dev->stats.tx_packets++; | 
|  | 210 |  | 
|  | 211 | skb_orphan(skb); | 
|  | 212 | skb_set_owner_w(skb, sk); | 
|  | 213 |  | 
|  | 214 | lock_sock(sk); | 
|  | 215 | err = pep_write(sk, skb); | 
|  | 216 | if (err) { | 
|  | 217 | LIMIT_NETDEBUG(KERN_WARNING"%s: TX error (%d)\n", | 
|  | 218 | dev->net->name, err); | 
|  | 219 | dev->stats.tx_aborted_errors++; | 
|  | 220 | dev->stats.tx_errors++; | 
|  | 221 | } | 
|  | 222 | release_sock(sk); | 
|  | 223 | } | 
|  | 224 |  | 
|  | 225 | lock_sock(sk); | 
|  | 226 | gprs_write_space(sk); | 
|  | 227 | release_sock(sk); | 
|  | 228 | } | 
|  | 229 |  | 
|  | 230 | static int gprs_set_mtu(struct net_device *net, int new_mtu) | 
|  | 231 | { | 
|  | 232 | if ((new_mtu < 576) || (new_mtu > (PHONET_MAX_MTU - 11))) | 
|  | 233 | return -EINVAL; | 
|  | 234 |  | 
|  | 235 | net->mtu = new_mtu; | 
|  | 236 | return 0; | 
|  | 237 | } | 
|  | 238 |  | 
|  | 239 | static struct net_device_stats *gprs_get_stats(struct net_device *net) | 
|  | 240 | { | 
|  | 241 | struct gprs_dev *dev = netdev_priv(net); | 
|  | 242 |  | 
|  | 243 | return &dev->stats; | 
|  | 244 | } | 
|  | 245 |  | 
|  | 246 | static void gprs_setup(struct net_device *net) | 
|  | 247 | { | 
|  | 248 | net->features		= NETIF_F_FRAGLIST; | 
|  | 249 | net->type		= ARPHRD_NONE; | 
|  | 250 | net->flags		= IFF_POINTOPOINT | IFF_NOARP; | 
|  | 251 | net->mtu		= GPRS_DEFAULT_MTU; | 
|  | 252 | net->hard_header_len	= 0; | 
|  | 253 | net->addr_len		= 0; | 
|  | 254 | net->tx_queue_len	= 10; | 
|  | 255 |  | 
|  | 256 | net->destructor		= free_netdev; | 
|  | 257 | net->hard_start_xmit	= gprs_xmit; /* mandatory */ | 
|  | 258 | net->change_mtu		= gprs_set_mtu; | 
|  | 259 | net->get_stats		= gprs_get_stats; | 
|  | 260 | } | 
|  | 261 |  | 
|  | 262 | /* | 
|  | 263 | * External interface | 
|  | 264 | */ | 
|  | 265 |  | 
|  | 266 | /* | 
|  | 267 | * Attach a GPRS interface to a datagram socket. | 
|  | 268 | * Returns the interface index on success, negative error code on error. | 
|  | 269 | */ | 
|  | 270 | int gprs_attach(struct sock *sk) | 
|  | 271 | { | 
|  | 272 | static const char ifname[] = "gprs%d"; | 
|  | 273 | struct gprs_dev *dev; | 
|  | 274 | struct net_device *net; | 
|  | 275 | int err; | 
|  | 276 |  | 
|  | 277 | if (unlikely(sk->sk_type == SOCK_STREAM)) | 
|  | 278 | return -EINVAL; /* need packet boundaries */ | 
|  | 279 |  | 
|  | 280 | /* Create net device */ | 
|  | 281 | net = alloc_netdev(sizeof(*dev), ifname, gprs_setup); | 
|  | 282 | if (!net) | 
|  | 283 | return -ENOMEM; | 
|  | 284 | dev = netdev_priv(net); | 
|  | 285 | dev->net = net; | 
|  | 286 | dev->tx_max = 0; | 
|  | 287 | spin_lock_init(&dev->tx_lock); | 
|  | 288 | skb_queue_head_init(&dev->tx_queue); | 
|  | 289 | INIT_WORK(&dev->tx_work, gprs_tx); | 
|  | 290 |  | 
|  | 291 | netif_stop_queue(net); | 
|  | 292 | err = register_netdev(net); | 
|  | 293 | if (err) { | 
|  | 294 | free_netdev(net); | 
|  | 295 | return err; | 
|  | 296 | } | 
|  | 297 |  | 
|  | 298 | lock_sock(sk); | 
|  | 299 | if (unlikely(sk->sk_user_data)) { | 
|  | 300 | err = -EBUSY; | 
|  | 301 | goto out_rel; | 
|  | 302 | } | 
|  | 303 | if (unlikely((1 << sk->sk_state & (TCPF_CLOSE|TCPF_LISTEN)) || | 
|  | 304 | sock_flag(sk, SOCK_DEAD))) { | 
|  | 305 | err = -EINVAL; | 
|  | 306 | goto out_rel; | 
|  | 307 | } | 
|  | 308 | sk->sk_user_data	= dev; | 
|  | 309 | dev->old_state_change	= sk->sk_state_change; | 
|  | 310 | dev->old_data_ready	= sk->sk_data_ready; | 
|  | 311 | dev->old_write_space	= sk->sk_write_space; | 
|  | 312 | sk->sk_state_change	= gprs_state_change; | 
|  | 313 | sk->sk_data_ready	= gprs_data_ready; | 
|  | 314 | sk->sk_write_space	= gprs_write_space; | 
|  | 315 | release_sock(sk); | 
|  | 316 |  | 
|  | 317 | sock_hold(sk); | 
|  | 318 | dev->sk = sk; | 
|  | 319 |  | 
|  | 320 | printk(KERN_DEBUG"%s: attached\n", net->name); | 
|  | 321 | gprs_write_space(sk); /* kick off TX */ | 
|  | 322 | return net->ifindex; | 
|  | 323 |  | 
|  | 324 | out_rel: | 
|  | 325 | release_sock(sk); | 
|  | 326 | unregister_netdev(net); | 
|  | 327 | return err; | 
|  | 328 | } | 
|  | 329 |  | 
|  | 330 | void gprs_detach(struct sock *sk) | 
|  | 331 | { | 
|  | 332 | struct gprs_dev *dev = sk->sk_user_data; | 
|  | 333 | struct net_device *net = dev->net; | 
|  | 334 |  | 
|  | 335 | lock_sock(sk); | 
|  | 336 | sk->sk_user_data	= NULL; | 
|  | 337 | sk->sk_state_change	= dev->old_state_change; | 
|  | 338 | sk->sk_data_ready	= dev->old_data_ready; | 
|  | 339 | sk->sk_write_space	= dev->old_write_space; | 
|  | 340 | release_sock(sk); | 
|  | 341 |  | 
|  | 342 | printk(KERN_DEBUG"%s: detached\n", net->name); | 
|  | 343 | unregister_netdev(net); | 
|  | 344 | flush_scheduled_work(); | 
|  | 345 | sock_put(sk); | 
|  | 346 | skb_queue_purge(&dev->tx_queue); | 
|  | 347 | } |