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