12b27bdccSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 202a47617SRémi Denis-Courmont /* 302a47617SRémi Denis-Courmont * File: pep-gprs.c 402a47617SRémi Denis-Courmont * 502a47617SRémi Denis-Courmont * GPRS over Phonet pipe end point socket 602a47617SRémi Denis-Courmont * 702a47617SRémi Denis-Courmont * Copyright (C) 2008 Nokia Corporation. 802a47617SRémi Denis-Courmont * 931fdc555SRémi Denis-Courmont * Author: Rémi Denis-Courmont 1002a47617SRémi Denis-Courmont */ 1102a47617SRémi Denis-Courmont 1202a47617SRémi Denis-Courmont #include <linux/kernel.h> 1302a47617SRémi Denis-Courmont #include <linux/netdevice.h> 1402a47617SRémi Denis-Courmont #include <linux/if_ether.h> 1502a47617SRémi Denis-Courmont #include <linux/if_arp.h> 1602a47617SRémi Denis-Courmont #include <net/sock.h> 1702a47617SRémi Denis-Courmont 1802a47617SRémi Denis-Courmont #include <linux/if_phonet.h> 1902a47617SRémi Denis-Courmont #include <net/tcp_states.h> 2002a47617SRémi Denis-Courmont #include <net/phonet/gprs.h> 2102a47617SRémi Denis-Courmont 22*40e0b090SPeilin Ye #include <trace/events/sock.h> 23*40e0b090SPeilin Ye 2402a47617SRémi Denis-Courmont #define GPRS_DEFAULT_MTU 1400 2502a47617SRémi Denis-Courmont 2602a47617SRémi Denis-Courmont struct gprs_dev { 2702a47617SRémi Denis-Courmont struct sock *sk; 2802a47617SRémi Denis-Courmont void (*old_state_change)(struct sock *); 29676d2369SDavid S. Miller void (*old_data_ready)(struct sock *); 3002a47617SRémi Denis-Courmont void (*old_write_space)(struct sock *); 3102a47617SRémi Denis-Courmont 3209a2c3c0SRémi Denis-Courmont struct net_device *dev; 3302a47617SRémi Denis-Courmont }; 3402a47617SRémi Denis-Courmont 355c7f0333SHarvey Harrison static __be16 gprs_type_trans(struct sk_buff *skb) 3602a47617SRémi Denis-Courmont { 3702a47617SRémi Denis-Courmont const u8 *pvfc; 3802a47617SRémi Denis-Courmont u8 buf; 3902a47617SRémi Denis-Courmont 4002a47617SRémi Denis-Courmont pvfc = skb_header_pointer(skb, 0, 1, &buf); 4102a47617SRémi Denis-Courmont if (!pvfc) 425c7f0333SHarvey Harrison return htons(0); 4302a47617SRémi Denis-Courmont /* Look at IP version field */ 4402a47617SRémi Denis-Courmont switch (*pvfc >> 4) { 4502a47617SRémi Denis-Courmont case 4: 4602a47617SRémi Denis-Courmont return htons(ETH_P_IP); 4702a47617SRémi Denis-Courmont case 6: 4802a47617SRémi Denis-Courmont return htons(ETH_P_IPV6); 4902a47617SRémi Denis-Courmont } 505c7f0333SHarvey Harrison return htons(0); 5102a47617SRémi Denis-Courmont } 5202a47617SRémi Denis-Courmont 53893873f3SRémi Denis-Courmont static void gprs_writeable(struct gprs_dev *gp) 54893873f3SRémi Denis-Courmont { 55893873f3SRémi Denis-Courmont struct net_device *dev = gp->dev; 56893873f3SRémi Denis-Courmont 57893873f3SRémi Denis-Courmont if (pep_writeable(gp->sk)) 58893873f3SRémi Denis-Courmont netif_wake_queue(dev); 59893873f3SRémi Denis-Courmont } 60893873f3SRémi Denis-Courmont 6102a47617SRémi Denis-Courmont /* 6202a47617SRémi Denis-Courmont * Socket callbacks 6302a47617SRémi Denis-Courmont */ 6402a47617SRémi Denis-Courmont 6502a47617SRémi Denis-Courmont static void gprs_state_change(struct sock *sk) 6602a47617SRémi Denis-Courmont { 6709a2c3c0SRémi Denis-Courmont struct gprs_dev *gp = sk->sk_user_data; 6802a47617SRémi Denis-Courmont 6902a47617SRémi Denis-Courmont if (sk->sk_state == TCP_CLOSE_WAIT) { 7009a2c3c0SRémi Denis-Courmont struct net_device *dev = gp->dev; 7109a2c3c0SRémi Denis-Courmont 7209a2c3c0SRémi Denis-Courmont netif_stop_queue(dev); 7309a2c3c0SRémi Denis-Courmont netif_carrier_off(dev); 7402a47617SRémi Denis-Courmont } 7502a47617SRémi Denis-Courmont } 7602a47617SRémi Denis-Courmont 7709a2c3c0SRémi Denis-Courmont static int gprs_recv(struct gprs_dev *gp, struct sk_buff *skb) 7802a47617SRémi Denis-Courmont { 7909a2c3c0SRémi Denis-Courmont struct net_device *dev = gp->dev; 8002a47617SRémi Denis-Courmont int err = 0; 815c7f0333SHarvey Harrison __be16 protocol = gprs_type_trans(skb); 8202a47617SRémi Denis-Courmont 8302a47617SRémi Denis-Courmont if (!protocol) { 8402a47617SRémi Denis-Courmont err = -EINVAL; 8502a47617SRémi Denis-Courmont goto drop; 8602a47617SRémi Denis-Courmont } 8702a47617SRémi Denis-Courmont 88fc6a1107SRémi Denis-Courmont if (skb_headroom(skb) & 3) { 8902a47617SRémi Denis-Courmont struct sk_buff *rskb, *fs; 9002a47617SRémi Denis-Courmont int flen = 0; 9102a47617SRémi Denis-Courmont 92fc6a1107SRémi Denis-Courmont /* Phonet Pipe data header may be misaligned (3 bytes), 9302a47617SRémi Denis-Courmont * so wrap the IP packet as a single fragment of an head-less 9402a47617SRémi Denis-Courmont * socket buffer. The network stack will pull what it needs, 9502a47617SRémi Denis-Courmont * but at least, the whole IP payload is not memcpy'd. */ 9609a2c3c0SRémi Denis-Courmont rskb = netdev_alloc_skb(dev, 0); 9702a47617SRémi Denis-Courmont if (!rskb) { 9802a47617SRémi Denis-Courmont err = -ENOBUFS; 9902a47617SRémi Denis-Courmont goto drop; 10002a47617SRémi Denis-Courmont } 10102a47617SRémi Denis-Courmont skb_shinfo(rskb)->frag_list = skb; 10202a47617SRémi Denis-Courmont rskb->len += skb->len; 10302a47617SRémi Denis-Courmont rskb->data_len += rskb->len; 10402a47617SRémi Denis-Courmont rskb->truesize += rskb->len; 10502a47617SRémi Denis-Courmont 10602a47617SRémi Denis-Courmont /* Avoid nested fragments */ 1075c313e9aSDavid S. Miller skb_walk_frags(skb, fs) 10802a47617SRémi Denis-Courmont flen += fs->len; 10902a47617SRémi Denis-Courmont skb->next = skb_shinfo(skb)->frag_list; 1105c313e9aSDavid S. Miller skb_frag_list_init(skb); 11102a47617SRémi Denis-Courmont skb->len -= flen; 11202a47617SRémi Denis-Courmont skb->data_len -= flen; 11302a47617SRémi Denis-Courmont skb->truesize -= flen; 11402a47617SRémi Denis-Courmont 11502a47617SRémi Denis-Courmont skb = rskb; 11602a47617SRémi Denis-Courmont } 11702a47617SRémi Denis-Courmont 11802a47617SRémi Denis-Courmont skb->protocol = protocol; 11902a47617SRémi Denis-Courmont skb_reset_mac_header(skb); 12009a2c3c0SRémi Denis-Courmont skb->dev = dev; 12102a47617SRémi Denis-Courmont 12209a2c3c0SRémi Denis-Courmont if (likely(dev->flags & IFF_UP)) { 12309a2c3c0SRémi Denis-Courmont dev->stats.rx_packets++; 12409a2c3c0SRémi Denis-Courmont dev->stats.rx_bytes += skb->len; 12502a47617SRémi Denis-Courmont netif_rx(skb); 12602a47617SRémi Denis-Courmont skb = NULL; 12702a47617SRémi Denis-Courmont } else 12802a47617SRémi Denis-Courmont err = -ENODEV; 12902a47617SRémi Denis-Courmont 13002a47617SRémi Denis-Courmont drop: 13102a47617SRémi Denis-Courmont if (skb) { 13202a47617SRémi Denis-Courmont dev_kfree_skb(skb); 13309a2c3c0SRémi Denis-Courmont dev->stats.rx_dropped++; 13402a47617SRémi Denis-Courmont } 13502a47617SRémi Denis-Courmont return err; 13602a47617SRémi Denis-Courmont } 13702a47617SRémi Denis-Courmont 138676d2369SDavid S. Miller static void gprs_data_ready(struct sock *sk) 13902a47617SRémi Denis-Courmont { 14009a2c3c0SRémi Denis-Courmont struct gprs_dev *gp = sk->sk_user_data; 14102a47617SRémi Denis-Courmont struct sk_buff *skb; 14202a47617SRémi Denis-Courmont 143*40e0b090SPeilin Ye trace_sk_data_ready(sk); 144*40e0b090SPeilin Ye 14502a47617SRémi Denis-Courmont while ((skb = pep_read(sk)) != NULL) { 14602a47617SRémi Denis-Courmont skb_orphan(skb); 14709a2c3c0SRémi Denis-Courmont gprs_recv(gp, skb); 14802a47617SRémi Denis-Courmont } 14902a47617SRémi Denis-Courmont } 15002a47617SRémi Denis-Courmont 15102a47617SRémi Denis-Courmont static void gprs_write_space(struct sock *sk) 15202a47617SRémi Denis-Courmont { 15309a2c3c0SRémi Denis-Courmont struct gprs_dev *gp = sk->sk_user_data; 15402a47617SRémi Denis-Courmont 155893873f3SRémi Denis-Courmont if (netif_running(gp->dev)) 156893873f3SRémi Denis-Courmont gprs_writeable(gp); 15702a47617SRémi Denis-Courmont } 15802a47617SRémi Denis-Courmont 15902a47617SRémi Denis-Courmont /* 16002a47617SRémi Denis-Courmont * Network device callbacks 16102a47617SRémi Denis-Courmont */ 16202a47617SRémi Denis-Courmont 1634798a2b8SRémi Denis-Courmont static int gprs_open(struct net_device *dev) 1644798a2b8SRémi Denis-Courmont { 1654798a2b8SRémi Denis-Courmont struct gprs_dev *gp = netdev_priv(dev); 1664798a2b8SRémi Denis-Courmont 167893873f3SRémi Denis-Courmont gprs_writeable(gp); 1684798a2b8SRémi Denis-Courmont return 0; 1694798a2b8SRémi Denis-Courmont } 1704798a2b8SRémi Denis-Courmont 1714798a2b8SRémi Denis-Courmont static int gprs_close(struct net_device *dev) 1724798a2b8SRémi Denis-Courmont { 1734798a2b8SRémi Denis-Courmont netif_stop_queue(dev); 1744798a2b8SRémi Denis-Courmont return 0; 1754798a2b8SRémi Denis-Courmont } 1764798a2b8SRémi Denis-Courmont 177424efe9cSStephen Hemminger static netdev_tx_t gprs_xmit(struct sk_buff *skb, struct net_device *dev) 17802a47617SRémi Denis-Courmont { 17909a2c3c0SRémi Denis-Courmont struct gprs_dev *gp = netdev_priv(dev); 180893873f3SRémi Denis-Courmont struct sock *sk = gp->sk; 181893873f3SRémi Denis-Courmont int len, err; 18202a47617SRémi Denis-Courmont 18302a47617SRémi Denis-Courmont switch (skb->protocol) { 18402a47617SRémi Denis-Courmont case htons(ETH_P_IP): 18502a47617SRémi Denis-Courmont case htons(ETH_P_IPV6): 18602a47617SRémi Denis-Courmont break; 18702a47617SRémi Denis-Courmont default: 18802a47617SRémi Denis-Courmont dev_kfree_skb(skb); 1896ed10654SPatrick McHardy return NETDEV_TX_OK; 19002a47617SRémi Denis-Courmont } 19102a47617SRémi Denis-Courmont 19202a47617SRémi Denis-Courmont skb_orphan(skb); 19302a47617SRémi Denis-Courmont skb_set_owner_w(skb, sk); 194893873f3SRémi Denis-Courmont len = skb->len; 19502a47617SRémi Denis-Courmont err = pep_write(sk, skb); 19602a47617SRémi Denis-Courmont if (err) { 197ba7a46f1SJoe Perches net_dbg_ratelimited("%s: TX error (%d)\n", dev->name, err); 19809a2c3c0SRémi Denis-Courmont dev->stats.tx_aborted_errors++; 19909a2c3c0SRémi Denis-Courmont dev->stats.tx_errors++; 200893873f3SRémi Denis-Courmont } else { 201893873f3SRémi Denis-Courmont dev->stats.tx_packets++; 202893873f3SRémi Denis-Courmont dev->stats.tx_bytes += len; 20302a47617SRémi Denis-Courmont } 20402a47617SRémi Denis-Courmont 205893873f3SRémi Denis-Courmont netif_stop_queue(dev); 206bbd5898dSRémi Denis-Courmont if (pep_writeable(sk)) 207bbd5898dSRémi Denis-Courmont netif_wake_queue(dev); 2086ed10654SPatrick McHardy return NETDEV_TX_OK; 20902a47617SRémi Denis-Courmont } 21002a47617SRémi Denis-Courmont 211ab638e69SStephen Hemminger static const struct net_device_ops gprs_netdev_ops = { 212ab638e69SStephen Hemminger .ndo_open = gprs_open, 213ab638e69SStephen Hemminger .ndo_stop = gprs_close, 214ab638e69SStephen Hemminger .ndo_start_xmit = gprs_xmit, 215ab638e69SStephen Hemminger }; 216ab638e69SStephen Hemminger 21709a2c3c0SRémi Denis-Courmont static void gprs_setup(struct net_device *dev) 21802a47617SRémi Denis-Courmont { 21909a2c3c0SRémi Denis-Courmont dev->features = NETIF_F_FRAGLIST; 22057c81fffSRémi Denis-Courmont dev->type = ARPHRD_PHONET_PIPE; 22109a2c3c0SRémi Denis-Courmont dev->flags = IFF_POINTOPOINT | IFF_NOARP; 22209a2c3c0SRémi Denis-Courmont dev->mtu = GPRS_DEFAULT_MTU; 223b3e3893eSJarod Wilson dev->min_mtu = 576; 224b3e3893eSJarod Wilson dev->max_mtu = (PHONET_MAX_MTU - 11); 22509a2c3c0SRémi Denis-Courmont dev->hard_header_len = 0; 22609a2c3c0SRémi Denis-Courmont dev->addr_len = 0; 22709a2c3c0SRémi Denis-Courmont dev->tx_queue_len = 10; 22802a47617SRémi Denis-Courmont 229ab638e69SStephen Hemminger dev->netdev_ops = &gprs_netdev_ops; 230cf124db5SDavid S. Miller dev->needs_free_netdev = true; 23102a47617SRémi Denis-Courmont } 23202a47617SRémi Denis-Courmont 23302a47617SRémi Denis-Courmont /* 23402a47617SRémi Denis-Courmont * External interface 23502a47617SRémi Denis-Courmont */ 23602a47617SRémi Denis-Courmont 23702a47617SRémi Denis-Courmont /* 23802a47617SRémi Denis-Courmont * Attach a GPRS interface to a datagram socket. 23902a47617SRémi Denis-Courmont * Returns the interface index on success, negative error code on error. 24002a47617SRémi Denis-Courmont */ 24102a47617SRémi Denis-Courmont int gprs_attach(struct sock *sk) 24202a47617SRémi Denis-Courmont { 24302a47617SRémi Denis-Courmont static const char ifname[] = "gprs%d"; 24409a2c3c0SRémi Denis-Courmont struct gprs_dev *gp; 24509a2c3c0SRémi Denis-Courmont struct net_device *dev; 24602a47617SRémi Denis-Courmont int err; 24702a47617SRémi Denis-Courmont 24802a47617SRémi Denis-Courmont if (unlikely(sk->sk_type == SOCK_STREAM)) 24902a47617SRémi Denis-Courmont return -EINVAL; /* need packet boundaries */ 25002a47617SRémi Denis-Courmont 25102a47617SRémi Denis-Courmont /* Create net device */ 252c835a677STom Gundersen dev = alloc_netdev(sizeof(*gp), ifname, NET_NAME_UNKNOWN, gprs_setup); 25309a2c3c0SRémi Denis-Courmont if (!dev) 25402a47617SRémi Denis-Courmont return -ENOMEM; 25509a2c3c0SRémi Denis-Courmont gp = netdev_priv(dev); 256893873f3SRémi Denis-Courmont gp->sk = sk; 25709a2c3c0SRémi Denis-Courmont gp->dev = dev; 25802a47617SRémi Denis-Courmont 25909a2c3c0SRémi Denis-Courmont netif_stop_queue(dev); 26009a2c3c0SRémi Denis-Courmont err = register_netdev(dev); 26102a47617SRémi Denis-Courmont if (err) { 26209a2c3c0SRémi Denis-Courmont free_netdev(dev); 26302a47617SRémi Denis-Courmont return err; 26402a47617SRémi Denis-Courmont } 26502a47617SRémi Denis-Courmont 26602a47617SRémi Denis-Courmont lock_sock(sk); 26702a47617SRémi Denis-Courmont if (unlikely(sk->sk_user_data)) { 26802a47617SRémi Denis-Courmont err = -EBUSY; 26902a47617SRémi Denis-Courmont goto out_rel; 27002a47617SRémi Denis-Courmont } 27102a47617SRémi Denis-Courmont if (unlikely((1 << sk->sk_state & (TCPF_CLOSE|TCPF_LISTEN)) || 27202a47617SRémi Denis-Courmont sock_flag(sk, SOCK_DEAD))) { 27302a47617SRémi Denis-Courmont err = -EINVAL; 27402a47617SRémi Denis-Courmont goto out_rel; 27502a47617SRémi Denis-Courmont } 27609a2c3c0SRémi Denis-Courmont sk->sk_user_data = gp; 27709a2c3c0SRémi Denis-Courmont gp->old_state_change = sk->sk_state_change; 27809a2c3c0SRémi Denis-Courmont gp->old_data_ready = sk->sk_data_ready; 27909a2c3c0SRémi Denis-Courmont gp->old_write_space = sk->sk_write_space; 28002a47617SRémi Denis-Courmont sk->sk_state_change = gprs_state_change; 28102a47617SRémi Denis-Courmont sk->sk_data_ready = gprs_data_ready; 28202a47617SRémi Denis-Courmont sk->sk_write_space = gprs_write_space; 28302a47617SRémi Denis-Courmont release_sock(sk); 28402a47617SRémi Denis-Courmont sock_hold(sk); 28502a47617SRémi Denis-Courmont 28609a2c3c0SRémi Denis-Courmont printk(KERN_DEBUG"%s: attached\n", dev->name); 28709a2c3c0SRémi Denis-Courmont return dev->ifindex; 28802a47617SRémi Denis-Courmont 28902a47617SRémi Denis-Courmont out_rel: 29002a47617SRémi Denis-Courmont release_sock(sk); 29109a2c3c0SRémi Denis-Courmont unregister_netdev(dev); 29202a47617SRémi Denis-Courmont return err; 29302a47617SRémi Denis-Courmont } 29402a47617SRémi Denis-Courmont 29502a47617SRémi Denis-Courmont void gprs_detach(struct sock *sk) 29602a47617SRémi Denis-Courmont { 29709a2c3c0SRémi Denis-Courmont struct gprs_dev *gp = sk->sk_user_data; 29809a2c3c0SRémi Denis-Courmont struct net_device *dev = gp->dev; 29902a47617SRémi Denis-Courmont 30002a47617SRémi Denis-Courmont lock_sock(sk); 30102a47617SRémi Denis-Courmont sk->sk_user_data = NULL; 30209a2c3c0SRémi Denis-Courmont sk->sk_state_change = gp->old_state_change; 30309a2c3c0SRémi Denis-Courmont sk->sk_data_ready = gp->old_data_ready; 30409a2c3c0SRémi Denis-Courmont sk->sk_write_space = gp->old_write_space; 30502a47617SRémi Denis-Courmont release_sock(sk); 30602a47617SRémi Denis-Courmont 30709a2c3c0SRémi Denis-Courmont printk(KERN_DEBUG"%s: detached\n", dev->name); 30809a2c3c0SRémi Denis-Courmont unregister_netdev(dev); 30902a47617SRémi Denis-Courmont sock_put(sk); 31002a47617SRémi Denis-Courmont } 311