162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* L2TPv3 ethernet pseudowire driver 362306a36Sopenharmony_ci * 462306a36Sopenharmony_ci * Copyright (c) 2008,2009,2010 Katalix Systems Ltd 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/module.h> 1062306a36Sopenharmony_ci#include <linux/skbuff.h> 1162306a36Sopenharmony_ci#include <linux/socket.h> 1262306a36Sopenharmony_ci#include <linux/hash.h> 1362306a36Sopenharmony_ci#include <linux/l2tp.h> 1462306a36Sopenharmony_ci#include <linux/in.h> 1562306a36Sopenharmony_ci#include <linux/etherdevice.h> 1662306a36Sopenharmony_ci#include <linux/spinlock.h> 1762306a36Sopenharmony_ci#include <net/sock.h> 1862306a36Sopenharmony_ci#include <net/ip.h> 1962306a36Sopenharmony_ci#include <net/icmp.h> 2062306a36Sopenharmony_ci#include <net/udp.h> 2162306a36Sopenharmony_ci#include <net/inet_common.h> 2262306a36Sopenharmony_ci#include <net/inet_hashtables.h> 2362306a36Sopenharmony_ci#include <net/tcp_states.h> 2462306a36Sopenharmony_ci#include <net/protocol.h> 2562306a36Sopenharmony_ci#include <net/xfrm.h> 2662306a36Sopenharmony_ci#include <net/net_namespace.h> 2762306a36Sopenharmony_ci#include <net/netns/generic.h> 2862306a36Sopenharmony_ci#include <linux/ip.h> 2962306a36Sopenharmony_ci#include <linux/ipv6.h> 3062306a36Sopenharmony_ci#include <linux/udp.h> 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci#include "l2tp_core.h" 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci/* Default device name. May be overridden by name specified by user */ 3562306a36Sopenharmony_ci#define L2TP_ETH_DEV_NAME "l2tpeth%d" 3662306a36Sopenharmony_ci 3762306a36Sopenharmony_ci/* via netdev_priv() */ 3862306a36Sopenharmony_cistruct l2tp_eth { 3962306a36Sopenharmony_ci struct l2tp_session *session; 4062306a36Sopenharmony_ci atomic_long_t tx_bytes; 4162306a36Sopenharmony_ci atomic_long_t tx_packets; 4262306a36Sopenharmony_ci atomic_long_t tx_dropped; 4362306a36Sopenharmony_ci atomic_long_t rx_bytes; 4462306a36Sopenharmony_ci atomic_long_t rx_packets; 4562306a36Sopenharmony_ci atomic_long_t rx_errors; 4662306a36Sopenharmony_ci}; 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci/* via l2tp_session_priv() */ 4962306a36Sopenharmony_cistruct l2tp_eth_sess { 5062306a36Sopenharmony_ci struct net_device __rcu *dev; 5162306a36Sopenharmony_ci}; 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_cistatic int l2tp_eth_dev_init(struct net_device *dev) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci eth_hw_addr_random(dev); 5662306a36Sopenharmony_ci eth_broadcast_addr(dev->broadcast); 5762306a36Sopenharmony_ci netdev_lockdep_set_classes(dev); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci return 0; 6062306a36Sopenharmony_ci} 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_cistatic void l2tp_eth_dev_uninit(struct net_device *dev) 6362306a36Sopenharmony_ci{ 6462306a36Sopenharmony_ci struct l2tp_eth *priv = netdev_priv(dev); 6562306a36Sopenharmony_ci struct l2tp_eth_sess *spriv; 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci spriv = l2tp_session_priv(priv->session); 6862306a36Sopenharmony_ci RCU_INIT_POINTER(spriv->dev, NULL); 6962306a36Sopenharmony_ci /* No need for synchronize_net() here. We're called by 7062306a36Sopenharmony_ci * unregister_netdev*(), which does the synchronisation for us. 7162306a36Sopenharmony_ci */ 7262306a36Sopenharmony_ci} 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_cistatic netdev_tx_t l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct l2tp_eth *priv = netdev_priv(dev); 7762306a36Sopenharmony_ci struct l2tp_session *session = priv->session; 7862306a36Sopenharmony_ci unsigned int len = skb->len; 7962306a36Sopenharmony_ci int ret = l2tp_xmit_skb(session, skb); 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci if (likely(ret == NET_XMIT_SUCCESS)) { 8262306a36Sopenharmony_ci atomic_long_add(len, &priv->tx_bytes); 8362306a36Sopenharmony_ci atomic_long_inc(&priv->tx_packets); 8462306a36Sopenharmony_ci } else { 8562306a36Sopenharmony_ci atomic_long_inc(&priv->tx_dropped); 8662306a36Sopenharmony_ci } 8762306a36Sopenharmony_ci return NETDEV_TX_OK; 8862306a36Sopenharmony_ci} 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_cistatic void l2tp_eth_get_stats64(struct net_device *dev, 9162306a36Sopenharmony_ci struct rtnl_link_stats64 *stats) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct l2tp_eth *priv = netdev_priv(dev); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci stats->tx_bytes = (unsigned long)atomic_long_read(&priv->tx_bytes); 9662306a36Sopenharmony_ci stats->tx_packets = (unsigned long)atomic_long_read(&priv->tx_packets); 9762306a36Sopenharmony_ci stats->tx_dropped = (unsigned long)atomic_long_read(&priv->tx_dropped); 9862306a36Sopenharmony_ci stats->rx_bytes = (unsigned long)atomic_long_read(&priv->rx_bytes); 9962306a36Sopenharmony_ci stats->rx_packets = (unsigned long)atomic_long_read(&priv->rx_packets); 10062306a36Sopenharmony_ci stats->rx_errors = (unsigned long)atomic_long_read(&priv->rx_errors); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic const struct net_device_ops l2tp_eth_netdev_ops = { 10462306a36Sopenharmony_ci .ndo_init = l2tp_eth_dev_init, 10562306a36Sopenharmony_ci .ndo_uninit = l2tp_eth_dev_uninit, 10662306a36Sopenharmony_ci .ndo_start_xmit = l2tp_eth_dev_xmit, 10762306a36Sopenharmony_ci .ndo_get_stats64 = l2tp_eth_get_stats64, 10862306a36Sopenharmony_ci .ndo_set_mac_address = eth_mac_addr, 10962306a36Sopenharmony_ci}; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_cistatic struct device_type l2tpeth_type = { 11262306a36Sopenharmony_ci .name = "l2tpeth", 11362306a36Sopenharmony_ci}; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_cistatic void l2tp_eth_dev_setup(struct net_device *dev) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci SET_NETDEV_DEVTYPE(dev, &l2tpeth_type); 11862306a36Sopenharmony_ci ether_setup(dev); 11962306a36Sopenharmony_ci dev->priv_flags &= ~IFF_TX_SKB_SHARING; 12062306a36Sopenharmony_ci dev->features |= NETIF_F_LLTX; 12162306a36Sopenharmony_ci dev->netdev_ops = &l2tp_eth_netdev_ops; 12262306a36Sopenharmony_ci dev->needs_free_netdev = true; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len) 12662306a36Sopenharmony_ci{ 12762306a36Sopenharmony_ci struct l2tp_eth_sess *spriv = l2tp_session_priv(session); 12862306a36Sopenharmony_ci struct net_device *dev; 12962306a36Sopenharmony_ci struct l2tp_eth *priv; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci if (!pskb_may_pull(skb, ETH_HLEN)) 13262306a36Sopenharmony_ci goto error; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci secpath_reset(skb); 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci /* checksums verified by L2TP */ 13762306a36Sopenharmony_ci skb->ip_summed = CHECKSUM_NONE; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci skb_dst_drop(skb); 14062306a36Sopenharmony_ci nf_reset_ct(skb); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci rcu_read_lock(); 14362306a36Sopenharmony_ci dev = rcu_dereference(spriv->dev); 14462306a36Sopenharmony_ci if (!dev) 14562306a36Sopenharmony_ci goto error_rcu; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci priv = netdev_priv(dev); 14862306a36Sopenharmony_ci if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) { 14962306a36Sopenharmony_ci atomic_long_inc(&priv->rx_packets); 15062306a36Sopenharmony_ci atomic_long_add(data_len, &priv->rx_bytes); 15162306a36Sopenharmony_ci } else { 15262306a36Sopenharmony_ci atomic_long_inc(&priv->rx_errors); 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci rcu_read_unlock(); 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci return; 15762306a36Sopenharmony_ci 15862306a36Sopenharmony_cierror_rcu: 15962306a36Sopenharmony_ci rcu_read_unlock(); 16062306a36Sopenharmony_cierror: 16162306a36Sopenharmony_ci kfree_skb(skb); 16262306a36Sopenharmony_ci} 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_cistatic void l2tp_eth_delete(struct l2tp_session *session) 16562306a36Sopenharmony_ci{ 16662306a36Sopenharmony_ci struct l2tp_eth_sess *spriv; 16762306a36Sopenharmony_ci struct net_device *dev; 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci if (session) { 17062306a36Sopenharmony_ci spriv = l2tp_session_priv(session); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci rtnl_lock(); 17362306a36Sopenharmony_ci dev = rtnl_dereference(spriv->dev); 17462306a36Sopenharmony_ci if (dev) { 17562306a36Sopenharmony_ci unregister_netdevice(dev); 17662306a36Sopenharmony_ci rtnl_unlock(); 17762306a36Sopenharmony_ci module_put(THIS_MODULE); 17862306a36Sopenharmony_ci } else { 17962306a36Sopenharmony_ci rtnl_unlock(); 18062306a36Sopenharmony_ci } 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic void l2tp_eth_show(struct seq_file *m, void *arg) 18562306a36Sopenharmony_ci{ 18662306a36Sopenharmony_ci struct l2tp_session *session = arg; 18762306a36Sopenharmony_ci struct l2tp_eth_sess *spriv = l2tp_session_priv(session); 18862306a36Sopenharmony_ci struct net_device *dev; 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci rcu_read_lock(); 19162306a36Sopenharmony_ci dev = rcu_dereference(spriv->dev); 19262306a36Sopenharmony_ci if (!dev) { 19362306a36Sopenharmony_ci rcu_read_unlock(); 19462306a36Sopenharmony_ci return; 19562306a36Sopenharmony_ci } 19662306a36Sopenharmony_ci dev_hold(dev); 19762306a36Sopenharmony_ci rcu_read_unlock(); 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_ci seq_printf(m, " interface %s\n", dev->name); 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci dev_put(dev); 20262306a36Sopenharmony_ci} 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic void l2tp_eth_adjust_mtu(struct l2tp_tunnel *tunnel, 20562306a36Sopenharmony_ci struct l2tp_session *session, 20662306a36Sopenharmony_ci struct net_device *dev) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci unsigned int overhead = 0; 20962306a36Sopenharmony_ci u32 l3_overhead = 0; 21062306a36Sopenharmony_ci u32 mtu; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* if the encap is UDP, account for UDP header size */ 21362306a36Sopenharmony_ci if (tunnel->encap == L2TP_ENCAPTYPE_UDP) { 21462306a36Sopenharmony_ci overhead += sizeof(struct udphdr); 21562306a36Sopenharmony_ci dev->needed_headroom += sizeof(struct udphdr); 21662306a36Sopenharmony_ci } 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci lock_sock(tunnel->sock); 21962306a36Sopenharmony_ci l3_overhead = kernel_sock_ip_overhead(tunnel->sock); 22062306a36Sopenharmony_ci release_sock(tunnel->sock); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (l3_overhead == 0) { 22362306a36Sopenharmony_ci /* L3 Overhead couldn't be identified, this could be 22462306a36Sopenharmony_ci * because tunnel->sock was NULL or the socket's 22562306a36Sopenharmony_ci * address family was not IPv4 or IPv6, 22662306a36Sopenharmony_ci * dev mtu stays at 1500. 22762306a36Sopenharmony_ci */ 22862306a36Sopenharmony_ci return; 22962306a36Sopenharmony_ci } 23062306a36Sopenharmony_ci /* Adjust MTU, factor overhead - underlay L3, overlay L2 hdr 23162306a36Sopenharmony_ci * UDP overhead, if any, was already factored in above. 23262306a36Sopenharmony_ci */ 23362306a36Sopenharmony_ci overhead += session->hdr_len + ETH_HLEN + l3_overhead; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci mtu = l2tp_tunnel_dst_mtu(tunnel) - overhead; 23662306a36Sopenharmony_ci if (mtu < dev->min_mtu || mtu > dev->max_mtu) 23762306a36Sopenharmony_ci dev->mtu = ETH_DATA_LEN - overhead; 23862306a36Sopenharmony_ci else 23962306a36Sopenharmony_ci dev->mtu = mtu; 24062306a36Sopenharmony_ci 24162306a36Sopenharmony_ci dev->needed_headroom += session->hdr_len; 24262306a36Sopenharmony_ci} 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_cistatic int l2tp_eth_create(struct net *net, struct l2tp_tunnel *tunnel, 24562306a36Sopenharmony_ci u32 session_id, u32 peer_session_id, 24662306a36Sopenharmony_ci struct l2tp_session_cfg *cfg) 24762306a36Sopenharmony_ci{ 24862306a36Sopenharmony_ci unsigned char name_assign_type; 24962306a36Sopenharmony_ci struct net_device *dev; 25062306a36Sopenharmony_ci char name[IFNAMSIZ]; 25162306a36Sopenharmony_ci struct l2tp_session *session; 25262306a36Sopenharmony_ci struct l2tp_eth *priv; 25362306a36Sopenharmony_ci struct l2tp_eth_sess *spriv; 25462306a36Sopenharmony_ci int rc; 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (cfg->ifname) { 25762306a36Sopenharmony_ci strscpy(name, cfg->ifname, IFNAMSIZ); 25862306a36Sopenharmony_ci name_assign_type = NET_NAME_USER; 25962306a36Sopenharmony_ci } else { 26062306a36Sopenharmony_ci strcpy(name, L2TP_ETH_DEV_NAME); 26162306a36Sopenharmony_ci name_assign_type = NET_NAME_ENUM; 26262306a36Sopenharmony_ci } 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci session = l2tp_session_create(sizeof(*spriv), tunnel, session_id, 26562306a36Sopenharmony_ci peer_session_id, cfg); 26662306a36Sopenharmony_ci if (IS_ERR(session)) { 26762306a36Sopenharmony_ci rc = PTR_ERR(session); 26862306a36Sopenharmony_ci goto err; 26962306a36Sopenharmony_ci } 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci dev = alloc_netdev(sizeof(*priv), name, name_assign_type, 27262306a36Sopenharmony_ci l2tp_eth_dev_setup); 27362306a36Sopenharmony_ci if (!dev) { 27462306a36Sopenharmony_ci rc = -ENOMEM; 27562306a36Sopenharmony_ci goto err_sess; 27662306a36Sopenharmony_ci } 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci dev_net_set(dev, net); 27962306a36Sopenharmony_ci dev->min_mtu = 0; 28062306a36Sopenharmony_ci dev->max_mtu = ETH_MAX_MTU; 28162306a36Sopenharmony_ci l2tp_eth_adjust_mtu(tunnel, session, dev); 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci priv = netdev_priv(dev); 28462306a36Sopenharmony_ci priv->session = session; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci session->recv_skb = l2tp_eth_dev_recv; 28762306a36Sopenharmony_ci session->session_close = l2tp_eth_delete; 28862306a36Sopenharmony_ci if (IS_ENABLED(CONFIG_L2TP_DEBUGFS)) 28962306a36Sopenharmony_ci session->show = l2tp_eth_show; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci spriv = l2tp_session_priv(session); 29262306a36Sopenharmony_ci 29362306a36Sopenharmony_ci l2tp_session_inc_refcount(session); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci rtnl_lock(); 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci /* Register both device and session while holding the rtnl lock. This 29862306a36Sopenharmony_ci * ensures that l2tp_eth_delete() will see that there's a device to 29962306a36Sopenharmony_ci * unregister, even if it happened to run before we assign spriv->dev. 30062306a36Sopenharmony_ci */ 30162306a36Sopenharmony_ci rc = l2tp_session_register(session, tunnel); 30262306a36Sopenharmony_ci if (rc < 0) { 30362306a36Sopenharmony_ci rtnl_unlock(); 30462306a36Sopenharmony_ci goto err_sess_dev; 30562306a36Sopenharmony_ci } 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ci rc = register_netdevice(dev); 30862306a36Sopenharmony_ci if (rc < 0) { 30962306a36Sopenharmony_ci rtnl_unlock(); 31062306a36Sopenharmony_ci l2tp_session_delete(session); 31162306a36Sopenharmony_ci l2tp_session_dec_refcount(session); 31262306a36Sopenharmony_ci free_netdev(dev); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci return rc; 31562306a36Sopenharmony_ci } 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_ci strscpy(session->ifname, dev->name, IFNAMSIZ); 31862306a36Sopenharmony_ci rcu_assign_pointer(spriv->dev, dev); 31962306a36Sopenharmony_ci 32062306a36Sopenharmony_ci rtnl_unlock(); 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci l2tp_session_dec_refcount(session); 32362306a36Sopenharmony_ci 32462306a36Sopenharmony_ci __module_get(THIS_MODULE); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci return 0; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cierr_sess_dev: 32962306a36Sopenharmony_ci l2tp_session_dec_refcount(session); 33062306a36Sopenharmony_ci free_netdev(dev); 33162306a36Sopenharmony_cierr_sess: 33262306a36Sopenharmony_ci kfree(session); 33362306a36Sopenharmony_cierr: 33462306a36Sopenharmony_ci return rc; 33562306a36Sopenharmony_ci} 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_cistatic const struct l2tp_nl_cmd_ops l2tp_eth_nl_cmd_ops = { 33862306a36Sopenharmony_ci .session_create = l2tp_eth_create, 33962306a36Sopenharmony_ci .session_delete = l2tp_session_delete, 34062306a36Sopenharmony_ci}; 34162306a36Sopenharmony_ci 34262306a36Sopenharmony_cistatic int __init l2tp_eth_init(void) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci int err = 0; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci err = l2tp_nl_register_ops(L2TP_PWTYPE_ETH, &l2tp_eth_nl_cmd_ops); 34762306a36Sopenharmony_ci if (err) 34862306a36Sopenharmony_ci goto err; 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci pr_info("L2TP ethernet pseudowire support (L2TPv3)\n"); 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci return 0; 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cierr: 35562306a36Sopenharmony_ci return err; 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic void __exit l2tp_eth_exit(void) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci l2tp_nl_unregister_ops(L2TP_PWTYPE_ETH); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cimodule_init(l2tp_eth_init); 36462306a36Sopenharmony_cimodule_exit(l2tp_eth_exit); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 36762306a36Sopenharmony_ciMODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); 36862306a36Sopenharmony_ciMODULE_DESCRIPTION("L2TP ethernet pseudowire driver"); 36962306a36Sopenharmony_ciMODULE_VERSION("1.0"); 37062306a36Sopenharmony_ciMODULE_ALIAS_L2TP_PWTYPE(5); 371