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
gprs_type_trans(struct sk_buff * skb)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
gprs_writeable(struct gprs_dev * gp)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
gprs_state_change(struct sock * sk)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
gprs_recv(struct gprs_dev * gp,struct sk_buff * skb)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
gprs_data_ready(struct sock * sk)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
gprs_write_space(struct sock * sk)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
gprs_open(struct net_device * dev)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
gprs_close(struct net_device * dev)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
gprs_xmit(struct sk_buff * skb,struct net_device * dev)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
gprs_setup(struct net_device * dev)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 */
gprs_attach(struct sock * sk)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
gprs_detach(struct sock * sk)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