162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * File: pep-gprs.c
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * GPRS over Phonet pipe end point socket
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation.
862306a36Sopenharmony_ci *
962306a36Sopenharmony_ci * Author: Rémi Denis-Courmont
1062306a36Sopenharmony_ci */
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <linux/kernel.h>
1362306a36Sopenharmony_ci#include <linux/netdevice.h>
1462306a36Sopenharmony_ci#include <linux/if_ether.h>
1562306a36Sopenharmony_ci#include <linux/if_arp.h>
1662306a36Sopenharmony_ci#include <net/sock.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include <linux/if_phonet.h>
1962306a36Sopenharmony_ci#include <net/tcp_states.h>
2062306a36Sopenharmony_ci#include <net/phonet/gprs.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <trace/events/sock.h>
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci#define GPRS_DEFAULT_MTU 1400
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_cistruct gprs_dev {
2762306a36Sopenharmony_ci	struct sock		*sk;
2862306a36Sopenharmony_ci	void			(*old_state_change)(struct sock *);
2962306a36Sopenharmony_ci	void			(*old_data_ready)(struct sock *);
3062306a36Sopenharmony_ci	void			(*old_write_space)(struct sock *);
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci	struct net_device	*dev;
3362306a36Sopenharmony_ci};
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_cistatic __be16 gprs_type_trans(struct sk_buff *skb)
3662306a36Sopenharmony_ci{
3762306a36Sopenharmony_ci	const u8 *pvfc;
3862306a36Sopenharmony_ci	u8 buf;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	pvfc = skb_header_pointer(skb, 0, 1, &buf);
4162306a36Sopenharmony_ci	if (!pvfc)
4262306a36Sopenharmony_ci		return htons(0);
4362306a36Sopenharmony_ci	/* Look at IP version field */
4462306a36Sopenharmony_ci	switch (*pvfc >> 4) {
4562306a36Sopenharmony_ci	case 4:
4662306a36Sopenharmony_ci		return htons(ETH_P_IP);
4762306a36Sopenharmony_ci	case 6:
4862306a36Sopenharmony_ci		return htons(ETH_P_IPV6);
4962306a36Sopenharmony_ci	}
5062306a36Sopenharmony_ci	return htons(0);
5162306a36Sopenharmony_ci}
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistatic void gprs_writeable(struct gprs_dev *gp)
5462306a36Sopenharmony_ci{
5562306a36Sopenharmony_ci	struct net_device *dev = gp->dev;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	if (pep_writeable(gp->sk))
5862306a36Sopenharmony_ci		netif_wake_queue(dev);
5962306a36Sopenharmony_ci}
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci/*
6262306a36Sopenharmony_ci * Socket callbacks
6362306a36Sopenharmony_ci */
6462306a36Sopenharmony_ci
6562306a36Sopenharmony_cistatic void gprs_state_change(struct sock *sk)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	struct gprs_dev *gp = sk->sk_user_data;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if (sk->sk_state == TCP_CLOSE_WAIT) {
7062306a36Sopenharmony_ci		struct net_device *dev = gp->dev;
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_ci		netif_stop_queue(dev);
7362306a36Sopenharmony_ci		netif_carrier_off(dev);
7462306a36Sopenharmony_ci	}
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistatic int gprs_recv(struct gprs_dev *gp, struct sk_buff *skb)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	struct net_device *dev = gp->dev;
8062306a36Sopenharmony_ci	int err = 0;
8162306a36Sopenharmony_ci	__be16 protocol = gprs_type_trans(skb);
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	if (!protocol) {
8462306a36Sopenharmony_ci		err = -EINVAL;
8562306a36Sopenharmony_ci		goto drop;
8662306a36Sopenharmony_ci	}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_ci	if (skb_headroom(skb) & 3) {
8962306a36Sopenharmony_ci		struct sk_buff *rskb, *fs;
9062306a36Sopenharmony_ci		int flen = 0;
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci		/* Phonet Pipe data header may be misaligned (3 bytes),
9362306a36Sopenharmony_ci		 * so wrap the IP packet as a single fragment of an head-less
9462306a36Sopenharmony_ci		 * socket buffer. The network stack will pull what it needs,
9562306a36Sopenharmony_ci		 * but at least, the whole IP payload is not memcpy'd. */
9662306a36Sopenharmony_ci		rskb = netdev_alloc_skb(dev, 0);
9762306a36Sopenharmony_ci		if (!rskb) {
9862306a36Sopenharmony_ci			err = -ENOBUFS;
9962306a36Sopenharmony_ci			goto drop;
10062306a36Sopenharmony_ci		}
10162306a36Sopenharmony_ci		skb_shinfo(rskb)->frag_list = skb;
10262306a36Sopenharmony_ci		rskb->len += skb->len;
10362306a36Sopenharmony_ci		rskb->data_len += rskb->len;
10462306a36Sopenharmony_ci		rskb->truesize += rskb->len;
10562306a36Sopenharmony_ci
10662306a36Sopenharmony_ci		/* Avoid nested fragments */
10762306a36Sopenharmony_ci		skb_walk_frags(skb, fs)
10862306a36Sopenharmony_ci			flen += fs->len;
10962306a36Sopenharmony_ci		skb->next = skb_shinfo(skb)->frag_list;
11062306a36Sopenharmony_ci		skb_frag_list_init(skb);
11162306a36Sopenharmony_ci		skb->len -= flen;
11262306a36Sopenharmony_ci		skb->data_len -= flen;
11362306a36Sopenharmony_ci		skb->truesize -= flen;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci		skb = rskb;
11662306a36Sopenharmony_ci	}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	skb->protocol = protocol;
11962306a36Sopenharmony_ci	skb_reset_mac_header(skb);
12062306a36Sopenharmony_ci	skb->dev = dev;
12162306a36Sopenharmony_ci
12262306a36Sopenharmony_ci	if (likely(dev->flags & IFF_UP)) {
12362306a36Sopenharmony_ci		dev->stats.rx_packets++;
12462306a36Sopenharmony_ci		dev->stats.rx_bytes += skb->len;
12562306a36Sopenharmony_ci		netif_rx(skb);
12662306a36Sopenharmony_ci		skb = NULL;
12762306a36Sopenharmony_ci	} else
12862306a36Sopenharmony_ci		err = -ENODEV;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_cidrop:
13162306a36Sopenharmony_ci	if (skb) {
13262306a36Sopenharmony_ci		dev_kfree_skb(skb);
13362306a36Sopenharmony_ci		dev->stats.rx_dropped++;
13462306a36Sopenharmony_ci	}
13562306a36Sopenharmony_ci	return err;
13662306a36Sopenharmony_ci}
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_cistatic void gprs_data_ready(struct sock *sk)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	struct gprs_dev *gp = sk->sk_user_data;
14162306a36Sopenharmony_ci	struct sk_buff *skb;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	trace_sk_data_ready(sk);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	while ((skb = pep_read(sk)) != NULL) {
14662306a36Sopenharmony_ci		skb_orphan(skb);
14762306a36Sopenharmony_ci		gprs_recv(gp, skb);
14862306a36Sopenharmony_ci	}
14962306a36Sopenharmony_ci}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_cistatic void gprs_write_space(struct sock *sk)
15262306a36Sopenharmony_ci{
15362306a36Sopenharmony_ci	struct gprs_dev *gp = sk->sk_user_data;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	if (netif_running(gp->dev))
15662306a36Sopenharmony_ci		gprs_writeable(gp);
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci/*
16062306a36Sopenharmony_ci * Network device callbacks
16162306a36Sopenharmony_ci */
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic int gprs_open(struct net_device *dev)
16462306a36Sopenharmony_ci{
16562306a36Sopenharmony_ci	struct gprs_dev *gp = netdev_priv(dev);
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	gprs_writeable(gp);
16862306a36Sopenharmony_ci	return 0;
16962306a36Sopenharmony_ci}
17062306a36Sopenharmony_ci
17162306a36Sopenharmony_cistatic int gprs_close(struct net_device *dev)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	netif_stop_queue(dev);
17462306a36Sopenharmony_ci	return 0;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic netdev_tx_t gprs_xmit(struct sk_buff *skb, struct net_device *dev)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct gprs_dev *gp = netdev_priv(dev);
18062306a36Sopenharmony_ci	struct sock *sk = gp->sk;
18162306a36Sopenharmony_ci	int len, err;
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci	switch (skb->protocol) {
18462306a36Sopenharmony_ci	case  htons(ETH_P_IP):
18562306a36Sopenharmony_ci	case  htons(ETH_P_IPV6):
18662306a36Sopenharmony_ci		break;
18762306a36Sopenharmony_ci	default:
18862306a36Sopenharmony_ci		dev_kfree_skb(skb);
18962306a36Sopenharmony_ci		return NETDEV_TX_OK;
19062306a36Sopenharmony_ci	}
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	skb_orphan(skb);
19362306a36Sopenharmony_ci	skb_set_owner_w(skb, sk);
19462306a36Sopenharmony_ci	len = skb->len;
19562306a36Sopenharmony_ci	err = pep_write(sk, skb);
19662306a36Sopenharmony_ci	if (err) {
19762306a36Sopenharmony_ci		net_dbg_ratelimited("%s: TX error (%d)\n", dev->name, err);
19862306a36Sopenharmony_ci		dev->stats.tx_aborted_errors++;
19962306a36Sopenharmony_ci		dev->stats.tx_errors++;
20062306a36Sopenharmony_ci	} else {
20162306a36Sopenharmony_ci		dev->stats.tx_packets++;
20262306a36Sopenharmony_ci		dev->stats.tx_bytes += len;
20362306a36Sopenharmony_ci	}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_ci	netif_stop_queue(dev);
20662306a36Sopenharmony_ci	if (pep_writeable(sk))
20762306a36Sopenharmony_ci		netif_wake_queue(dev);
20862306a36Sopenharmony_ci	return NETDEV_TX_OK;
20962306a36Sopenharmony_ci}
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_cistatic const struct net_device_ops gprs_netdev_ops = {
21262306a36Sopenharmony_ci	.ndo_open	= gprs_open,
21362306a36Sopenharmony_ci	.ndo_stop	= gprs_close,
21462306a36Sopenharmony_ci	.ndo_start_xmit	= gprs_xmit,
21562306a36Sopenharmony_ci};
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_cistatic void gprs_setup(struct net_device *dev)
21862306a36Sopenharmony_ci{
21962306a36Sopenharmony_ci	dev->features		= NETIF_F_FRAGLIST;
22062306a36Sopenharmony_ci	dev->type		= ARPHRD_PHONET_PIPE;
22162306a36Sopenharmony_ci	dev->flags		= IFF_POINTOPOINT | IFF_NOARP;
22262306a36Sopenharmony_ci	dev->mtu		= GPRS_DEFAULT_MTU;
22362306a36Sopenharmony_ci	dev->min_mtu		= 576;
22462306a36Sopenharmony_ci	dev->max_mtu		= (PHONET_MAX_MTU - 11);
22562306a36Sopenharmony_ci	dev->hard_header_len	= 0;
22662306a36Sopenharmony_ci	dev->addr_len		= 0;
22762306a36Sopenharmony_ci	dev->tx_queue_len	= 10;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	dev->netdev_ops		= &gprs_netdev_ops;
23062306a36Sopenharmony_ci	dev->needs_free_netdev	= true;
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci/*
23462306a36Sopenharmony_ci * External interface
23562306a36Sopenharmony_ci */
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci/*
23862306a36Sopenharmony_ci * Attach a GPRS interface to a datagram socket.
23962306a36Sopenharmony_ci * Returns the interface index on success, negative error code on error.
24062306a36Sopenharmony_ci */
24162306a36Sopenharmony_ciint gprs_attach(struct sock *sk)
24262306a36Sopenharmony_ci{
24362306a36Sopenharmony_ci	static const char ifname[] = "gprs%d";
24462306a36Sopenharmony_ci	struct gprs_dev *gp;
24562306a36Sopenharmony_ci	struct net_device *dev;
24662306a36Sopenharmony_ci	int err;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (unlikely(sk->sk_type == SOCK_STREAM))
24962306a36Sopenharmony_ci		return -EINVAL; /* need packet boundaries */
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* Create net device */
25262306a36Sopenharmony_ci	dev = alloc_netdev(sizeof(*gp), ifname, NET_NAME_UNKNOWN, gprs_setup);
25362306a36Sopenharmony_ci	if (!dev)
25462306a36Sopenharmony_ci		return -ENOMEM;
25562306a36Sopenharmony_ci	gp = netdev_priv(dev);
25662306a36Sopenharmony_ci	gp->sk = sk;
25762306a36Sopenharmony_ci	gp->dev = dev;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	netif_stop_queue(dev);
26062306a36Sopenharmony_ci	err = register_netdev(dev);
26162306a36Sopenharmony_ci	if (err) {
26262306a36Sopenharmony_ci		free_netdev(dev);
26362306a36Sopenharmony_ci		return err;
26462306a36Sopenharmony_ci	}
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	lock_sock(sk);
26762306a36Sopenharmony_ci	if (unlikely(sk->sk_user_data)) {
26862306a36Sopenharmony_ci		err = -EBUSY;
26962306a36Sopenharmony_ci		goto out_rel;
27062306a36Sopenharmony_ci	}
27162306a36Sopenharmony_ci	if (unlikely((1 << sk->sk_state & (TCPF_CLOSE|TCPF_LISTEN)) ||
27262306a36Sopenharmony_ci			sock_flag(sk, SOCK_DEAD))) {
27362306a36Sopenharmony_ci		err = -EINVAL;
27462306a36Sopenharmony_ci		goto out_rel;
27562306a36Sopenharmony_ci	}
27662306a36Sopenharmony_ci	sk->sk_user_data	= gp;
27762306a36Sopenharmony_ci	gp->old_state_change	= sk->sk_state_change;
27862306a36Sopenharmony_ci	gp->old_data_ready	= sk->sk_data_ready;
27962306a36Sopenharmony_ci	gp->old_write_space	= sk->sk_write_space;
28062306a36Sopenharmony_ci	sk->sk_state_change	= gprs_state_change;
28162306a36Sopenharmony_ci	sk->sk_data_ready	= gprs_data_ready;
28262306a36Sopenharmony_ci	sk->sk_write_space	= gprs_write_space;
28362306a36Sopenharmony_ci	release_sock(sk);
28462306a36Sopenharmony_ci	sock_hold(sk);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	printk(KERN_DEBUG"%s: attached\n", dev->name);
28762306a36Sopenharmony_ci	return dev->ifindex;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ciout_rel:
29062306a36Sopenharmony_ci	release_sock(sk);
29162306a36Sopenharmony_ci	unregister_netdev(dev);
29262306a36Sopenharmony_ci	return err;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_civoid gprs_detach(struct sock *sk)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct gprs_dev *gp = sk->sk_user_data;
29862306a36Sopenharmony_ci	struct net_device *dev = gp->dev;
29962306a36Sopenharmony_ci
30062306a36Sopenharmony_ci	lock_sock(sk);
30162306a36Sopenharmony_ci	sk->sk_user_data	= NULL;
30262306a36Sopenharmony_ci	sk->sk_state_change	= gp->old_state_change;
30362306a36Sopenharmony_ci	sk->sk_data_ready	= gp->old_data_ready;
30462306a36Sopenharmony_ci	sk->sk_write_space	= gp->old_write_space;
30562306a36Sopenharmony_ci	release_sock(sk);
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci	printk(KERN_DEBUG"%s: detached\n", dev->name);
30862306a36Sopenharmony_ci	unregister_netdev(dev);
30962306a36Sopenharmony_ci	sock_put(sk);
31062306a36Sopenharmony_ci}
311