18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * File: pep-gprs.c
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * GPRS over Phonet pipe end point socket
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Copyright (C) 2008 Nokia Corporation.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * Author: Rémi Denis-Courmont
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/kernel.h>
138c2ecf20Sopenharmony_ci#include <linux/netdevice.h>
148c2ecf20Sopenharmony_ci#include <linux/if_ether.h>
158c2ecf20Sopenharmony_ci#include <linux/if_arp.h>
168c2ecf20Sopenharmony_ci#include <net/sock.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include <linux/if_phonet.h>
198c2ecf20Sopenharmony_ci#include <net/tcp_states.h>
208c2ecf20Sopenharmony_ci#include <net/phonet/gprs.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#define GPRS_DEFAULT_MTU 1400
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_cistruct gprs_dev {
258c2ecf20Sopenharmony_ci	struct sock		*sk;
268c2ecf20Sopenharmony_ci	void			(*old_state_change)(struct sock *);
278c2ecf20Sopenharmony_ci	void			(*old_data_ready)(struct sock *);
288c2ecf20Sopenharmony_ci	void			(*old_write_space)(struct sock *);
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	struct net_device	*dev;
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_cistatic __be16 gprs_type_trans(struct sk_buff *skb)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	const u8 *pvfc;
368c2ecf20Sopenharmony_ci	u8 buf;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci	pvfc = skb_header_pointer(skb, 0, 1, &buf);
398c2ecf20Sopenharmony_ci	if (!pvfc)
408c2ecf20Sopenharmony_ci		return htons(0);
418c2ecf20Sopenharmony_ci	/* Look at IP version field */
428c2ecf20Sopenharmony_ci	switch (*pvfc >> 4) {
438c2ecf20Sopenharmony_ci	case 4:
448c2ecf20Sopenharmony_ci		return htons(ETH_P_IP);
458c2ecf20Sopenharmony_ci	case 6:
468c2ecf20Sopenharmony_ci		return htons(ETH_P_IPV6);
478c2ecf20Sopenharmony_ci	}
488c2ecf20Sopenharmony_ci	return htons(0);
498c2ecf20Sopenharmony_ci}
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cistatic void gprs_writeable(struct gprs_dev *gp)
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	struct net_device *dev = gp->dev;
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	if (pep_writeable(gp->sk))
568c2ecf20Sopenharmony_ci		netif_wake_queue(dev);
578c2ecf20Sopenharmony_ci}
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_ci/*
608c2ecf20Sopenharmony_ci * Socket callbacks
618c2ecf20Sopenharmony_ci */
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic void gprs_state_change(struct sock *sk)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct gprs_dev *gp = sk->sk_user_data;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	if (sk->sk_state == TCP_CLOSE_WAIT) {
688c2ecf20Sopenharmony_ci		struct net_device *dev = gp->dev;
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci		netif_stop_queue(dev);
718c2ecf20Sopenharmony_ci		netif_carrier_off(dev);
728c2ecf20Sopenharmony_ci	}
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_cistatic int gprs_recv(struct gprs_dev *gp, struct sk_buff *skb)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	struct net_device *dev = gp->dev;
788c2ecf20Sopenharmony_ci	int err = 0;
798c2ecf20Sopenharmony_ci	__be16 protocol = gprs_type_trans(skb);
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	if (!protocol) {
828c2ecf20Sopenharmony_ci		err = -EINVAL;
838c2ecf20Sopenharmony_ci		goto drop;
848c2ecf20Sopenharmony_ci	}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci	if (skb_headroom(skb) & 3) {
878c2ecf20Sopenharmony_ci		struct sk_buff *rskb, *fs;
888c2ecf20Sopenharmony_ci		int flen = 0;
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci		/* Phonet Pipe data header may be misaligned (3 bytes),
918c2ecf20Sopenharmony_ci		 * so wrap the IP packet as a single fragment of an head-less
928c2ecf20Sopenharmony_ci		 * socket buffer. The network stack will pull what it needs,
938c2ecf20Sopenharmony_ci		 * but at least, the whole IP payload is not memcpy'd. */
948c2ecf20Sopenharmony_ci		rskb = netdev_alloc_skb(dev, 0);
958c2ecf20Sopenharmony_ci		if (!rskb) {
968c2ecf20Sopenharmony_ci			err = -ENOBUFS;
978c2ecf20Sopenharmony_ci			goto drop;
988c2ecf20Sopenharmony_ci		}
998c2ecf20Sopenharmony_ci		skb_shinfo(rskb)->frag_list = skb;
1008c2ecf20Sopenharmony_ci		rskb->len += skb->len;
1018c2ecf20Sopenharmony_ci		rskb->data_len += rskb->len;
1028c2ecf20Sopenharmony_ci		rskb->truesize += rskb->len;
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci		/* Avoid nested fragments */
1058c2ecf20Sopenharmony_ci		skb_walk_frags(skb, fs)
1068c2ecf20Sopenharmony_ci			flen += fs->len;
1078c2ecf20Sopenharmony_ci		skb->next = skb_shinfo(skb)->frag_list;
1088c2ecf20Sopenharmony_ci		skb_frag_list_init(skb);
1098c2ecf20Sopenharmony_ci		skb->len -= flen;
1108c2ecf20Sopenharmony_ci		skb->data_len -= flen;
1118c2ecf20Sopenharmony_ci		skb->truesize -= flen;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci		skb = rskb;
1148c2ecf20Sopenharmony_ci	}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	skb->protocol = protocol;
1178c2ecf20Sopenharmony_ci	skb_reset_mac_header(skb);
1188c2ecf20Sopenharmony_ci	skb->dev = dev;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	if (likely(dev->flags & IFF_UP)) {
1218c2ecf20Sopenharmony_ci		dev->stats.rx_packets++;
1228c2ecf20Sopenharmony_ci		dev->stats.rx_bytes += skb->len;
1238c2ecf20Sopenharmony_ci		netif_rx(skb);
1248c2ecf20Sopenharmony_ci		skb = NULL;
1258c2ecf20Sopenharmony_ci	} else
1268c2ecf20Sopenharmony_ci		err = -ENODEV;
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cidrop:
1298c2ecf20Sopenharmony_ci	if (skb) {
1308c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
1318c2ecf20Sopenharmony_ci		dev->stats.rx_dropped++;
1328c2ecf20Sopenharmony_ci	}
1338c2ecf20Sopenharmony_ci	return err;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic void gprs_data_ready(struct sock *sk)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct gprs_dev *gp = sk->sk_user_data;
1398c2ecf20Sopenharmony_ci	struct sk_buff *skb;
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_ci	while ((skb = pep_read(sk)) != NULL) {
1428c2ecf20Sopenharmony_ci		skb_orphan(skb);
1438c2ecf20Sopenharmony_ci		gprs_recv(gp, skb);
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci}
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_cistatic void gprs_write_space(struct sock *sk)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	struct gprs_dev *gp = sk->sk_user_data;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if (netif_running(gp->dev))
1528c2ecf20Sopenharmony_ci		gprs_writeable(gp);
1538c2ecf20Sopenharmony_ci}
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci/*
1568c2ecf20Sopenharmony_ci * Network device callbacks
1578c2ecf20Sopenharmony_ci */
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic int gprs_open(struct net_device *dev)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	struct gprs_dev *gp = netdev_priv(dev);
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	gprs_writeable(gp);
1648c2ecf20Sopenharmony_ci	return 0;
1658c2ecf20Sopenharmony_ci}
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic int gprs_close(struct net_device *dev)
1688c2ecf20Sopenharmony_ci{
1698c2ecf20Sopenharmony_ci	netif_stop_queue(dev);
1708c2ecf20Sopenharmony_ci	return 0;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic netdev_tx_t gprs_xmit(struct sk_buff *skb, struct net_device *dev)
1748c2ecf20Sopenharmony_ci{
1758c2ecf20Sopenharmony_ci	struct gprs_dev *gp = netdev_priv(dev);
1768c2ecf20Sopenharmony_ci	struct sock *sk = gp->sk;
1778c2ecf20Sopenharmony_ci	int len, err;
1788c2ecf20Sopenharmony_ci
1798c2ecf20Sopenharmony_ci	switch (skb->protocol) {
1808c2ecf20Sopenharmony_ci	case  htons(ETH_P_IP):
1818c2ecf20Sopenharmony_ci	case  htons(ETH_P_IPV6):
1828c2ecf20Sopenharmony_ci		break;
1838c2ecf20Sopenharmony_ci	default:
1848c2ecf20Sopenharmony_ci		dev_kfree_skb(skb);
1858c2ecf20Sopenharmony_ci		return NETDEV_TX_OK;
1868c2ecf20Sopenharmony_ci	}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci	skb_orphan(skb);
1898c2ecf20Sopenharmony_ci	skb_set_owner_w(skb, sk);
1908c2ecf20Sopenharmony_ci	len = skb->len;
1918c2ecf20Sopenharmony_ci	err = pep_write(sk, skb);
1928c2ecf20Sopenharmony_ci	if (err) {
1938c2ecf20Sopenharmony_ci		net_dbg_ratelimited("%s: TX error (%d)\n", dev->name, err);
1948c2ecf20Sopenharmony_ci		dev->stats.tx_aborted_errors++;
1958c2ecf20Sopenharmony_ci		dev->stats.tx_errors++;
1968c2ecf20Sopenharmony_ci	} else {
1978c2ecf20Sopenharmony_ci		dev->stats.tx_packets++;
1988c2ecf20Sopenharmony_ci		dev->stats.tx_bytes += len;
1998c2ecf20Sopenharmony_ci	}
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_ci	netif_stop_queue(dev);
2028c2ecf20Sopenharmony_ci	if (pep_writeable(sk))
2038c2ecf20Sopenharmony_ci		netif_wake_queue(dev);
2048c2ecf20Sopenharmony_ci	return NETDEV_TX_OK;
2058c2ecf20Sopenharmony_ci}
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_cistatic const struct net_device_ops gprs_netdev_ops = {
2088c2ecf20Sopenharmony_ci	.ndo_open	= gprs_open,
2098c2ecf20Sopenharmony_ci	.ndo_stop	= gprs_close,
2108c2ecf20Sopenharmony_ci	.ndo_start_xmit	= gprs_xmit,
2118c2ecf20Sopenharmony_ci};
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_cistatic void gprs_setup(struct net_device *dev)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	dev->features		= NETIF_F_FRAGLIST;
2168c2ecf20Sopenharmony_ci	dev->type		= ARPHRD_PHONET_PIPE;
2178c2ecf20Sopenharmony_ci	dev->flags		= IFF_POINTOPOINT | IFF_NOARP;
2188c2ecf20Sopenharmony_ci	dev->mtu		= GPRS_DEFAULT_MTU;
2198c2ecf20Sopenharmony_ci	dev->min_mtu		= 576;
2208c2ecf20Sopenharmony_ci	dev->max_mtu		= (PHONET_MAX_MTU - 11);
2218c2ecf20Sopenharmony_ci	dev->hard_header_len	= 0;
2228c2ecf20Sopenharmony_ci	dev->addr_len		= 0;
2238c2ecf20Sopenharmony_ci	dev->tx_queue_len	= 10;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci	dev->netdev_ops		= &gprs_netdev_ops;
2268c2ecf20Sopenharmony_ci	dev->needs_free_netdev	= true;
2278c2ecf20Sopenharmony_ci}
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci/*
2308c2ecf20Sopenharmony_ci * External interface
2318c2ecf20Sopenharmony_ci */
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci/*
2348c2ecf20Sopenharmony_ci * Attach a GPRS interface to a datagram socket.
2358c2ecf20Sopenharmony_ci * Returns the interface index on success, negative error code on error.
2368c2ecf20Sopenharmony_ci */
2378c2ecf20Sopenharmony_ciint gprs_attach(struct sock *sk)
2388c2ecf20Sopenharmony_ci{
2398c2ecf20Sopenharmony_ci	static const char ifname[] = "gprs%d";
2408c2ecf20Sopenharmony_ci	struct gprs_dev *gp;
2418c2ecf20Sopenharmony_ci	struct net_device *dev;
2428c2ecf20Sopenharmony_ci	int err;
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	if (unlikely(sk->sk_type == SOCK_STREAM))
2458c2ecf20Sopenharmony_ci		return -EINVAL; /* need packet boundaries */
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	/* Create net device */
2488c2ecf20Sopenharmony_ci	dev = alloc_netdev(sizeof(*gp), ifname, NET_NAME_UNKNOWN, gprs_setup);
2498c2ecf20Sopenharmony_ci	if (!dev)
2508c2ecf20Sopenharmony_ci		return -ENOMEM;
2518c2ecf20Sopenharmony_ci	gp = netdev_priv(dev);
2528c2ecf20Sopenharmony_ci	gp->sk = sk;
2538c2ecf20Sopenharmony_ci	gp->dev = dev;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	netif_stop_queue(dev);
2568c2ecf20Sopenharmony_ci	err = register_netdev(dev);
2578c2ecf20Sopenharmony_ci	if (err) {
2588c2ecf20Sopenharmony_ci		free_netdev(dev);
2598c2ecf20Sopenharmony_ci		return err;
2608c2ecf20Sopenharmony_ci	}
2618c2ecf20Sopenharmony_ci
2628c2ecf20Sopenharmony_ci	lock_sock(sk);
2638c2ecf20Sopenharmony_ci	if (unlikely(sk->sk_user_data)) {
2648c2ecf20Sopenharmony_ci		err = -EBUSY;
2658c2ecf20Sopenharmony_ci		goto out_rel;
2668c2ecf20Sopenharmony_ci	}
2678c2ecf20Sopenharmony_ci	if (unlikely((1 << sk->sk_state & (TCPF_CLOSE|TCPF_LISTEN)) ||
2688c2ecf20Sopenharmony_ci			sock_flag(sk, SOCK_DEAD))) {
2698c2ecf20Sopenharmony_ci		err = -EINVAL;
2708c2ecf20Sopenharmony_ci		goto out_rel;
2718c2ecf20Sopenharmony_ci	}
2728c2ecf20Sopenharmony_ci	sk->sk_user_data	= gp;
2738c2ecf20Sopenharmony_ci	gp->old_state_change	= sk->sk_state_change;
2748c2ecf20Sopenharmony_ci	gp->old_data_ready	= sk->sk_data_ready;
2758c2ecf20Sopenharmony_ci	gp->old_write_space	= sk->sk_write_space;
2768c2ecf20Sopenharmony_ci	sk->sk_state_change	= gprs_state_change;
2778c2ecf20Sopenharmony_ci	sk->sk_data_ready	= gprs_data_ready;
2788c2ecf20Sopenharmony_ci	sk->sk_write_space	= gprs_write_space;
2798c2ecf20Sopenharmony_ci	release_sock(sk);
2808c2ecf20Sopenharmony_ci	sock_hold(sk);
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	printk(KERN_DEBUG"%s: attached\n", dev->name);
2838c2ecf20Sopenharmony_ci	return dev->ifindex;
2848c2ecf20Sopenharmony_ci
2858c2ecf20Sopenharmony_ciout_rel:
2868c2ecf20Sopenharmony_ci	release_sock(sk);
2878c2ecf20Sopenharmony_ci	unregister_netdev(dev);
2888c2ecf20Sopenharmony_ci	return err;
2898c2ecf20Sopenharmony_ci}
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_civoid gprs_detach(struct sock *sk)
2928c2ecf20Sopenharmony_ci{
2938c2ecf20Sopenharmony_ci	struct gprs_dev *gp = sk->sk_user_data;
2948c2ecf20Sopenharmony_ci	struct net_device *dev = gp->dev;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	lock_sock(sk);
2978c2ecf20Sopenharmony_ci	sk->sk_user_data	= NULL;
2988c2ecf20Sopenharmony_ci	sk->sk_state_change	= gp->old_state_change;
2998c2ecf20Sopenharmony_ci	sk->sk_data_ready	= gp->old_data_ready;
3008c2ecf20Sopenharmony_ci	sk->sk_write_space	= gp->old_write_space;
3018c2ecf20Sopenharmony_ci	release_sock(sk);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_ci	printk(KERN_DEBUG"%s: detached\n", dev->name);
3048c2ecf20Sopenharmony_ci	unregister_netdev(dev);
3058c2ecf20Sopenharmony_ci	sock_put(sk);
3068c2ecf20Sopenharmony_ci}
307