cregit-Linux how code gets into the kernel

Release 4.8 net/l2tp/l2tp_eth.c

Directory: net/l2tp
/*
 * L2TPv3 ethernet pseudowire driver
 *
 * Copyright (c) 2008,2009,2010 Katalix Systems Ltd
 *
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/socket.h>
#include <linux/hash.h>
#include <linux/l2tp.h>
#include <linux/in.h>
#include <linux/etherdevice.h>
#include <linux/spinlock.h>
#include <net/sock.h>
#include <net/ip.h>
#include <net/icmp.h>
#include <net/udp.h>
#include <net/inet_common.h>
#include <net/inet_hashtables.h>
#include <net/tcp_states.h>
#include <net/protocol.h>
#include <net/xfrm.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>

#include "l2tp_core.h"

/* Default device name. May be overridden by name specified by user */

#define L2TP_ETH_DEV_NAME	"l2tpeth%d"

/* via netdev_priv() */

struct l2tp_eth {
	
struct net_device	*dev;
	
struct sock		*tunnel_sock;
	
struct l2tp_session	*session;
	
struct list_head	list;
	
atomic_long_t		tx_bytes;
	
atomic_long_t		tx_packets;
	
atomic_long_t		tx_dropped;
	
atomic_long_t		rx_bytes;
	
atomic_long_t		rx_packets;
	
atomic_long_t		rx_errors;
};

/* via l2tp_session_priv() */

struct l2tp_eth_sess {
	
struct net_device	*dev;
};

/* per-net private data for this module */

static unsigned int l2tp_eth_net_id;

struct l2tp_eth_net {
	
struct list_head l2tp_eth_dev_list;
	
spinlock_t l2tp_eth_lock;
};


static inline struct l2tp_eth_net *l2tp_eth_pernet(struct net *net) { return net_generic(net, l2tp_eth_net_id); }

Contributors

PersonTokensPropCommitsCommitProp
james chapmanjames chapman22100.00%1100.00%
Total22100.00%1100.00%


static int l2tp_eth_dev_init(struct net_device *dev) { struct l2tp_eth *priv = netdev_priv(dev); priv->dev = dev; eth_hw_addr_random(dev); eth_broadcast_addr(dev->broadcast); netdev_lockdep_set_classes(dev); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
james chapmanjames chapman4085.11%116.67%
eric dumazeteric dumazet510.64%350.00%
joe perchesjoe perches12.13%116.67%
danny kukawkadanny kukawka12.13%116.67%
Total47100.00%6100.00%


static void l2tp_eth_dev_uninit(struct net_device *dev) { struct l2tp_eth *priv = netdev_priv(dev); struct l2tp_eth_net *pn = l2tp_eth_pernet(dev_net(dev)); spin_lock(&pn->l2tp_eth_lock); list_del_init(&priv->list); spin_unlock(&pn->l2tp_eth_lock); dev_put(dev); }

Contributors

PersonTokensPropCommitsCommitProp
james chapmanjames chapman63100.00%1100.00%
Total63100.00%1100.00%


static int l2tp_eth_dev_xmit(struct sk_buff *skb, struct net_device *dev) { struct l2tp_eth *priv = netdev_priv(dev); struct l2tp_session *session = priv->session; unsigned int len = skb->len; int ret = l2tp_xmit_skb(session, skb, session->hdr_len); if (likely(ret == NET_XMIT_SUCCESS)) { atomic_long_add(len, &priv->tx_bytes); atomic_long_inc(&priv->tx_packets); } else { atomic_long_inc(&priv->tx_dropped); } return NETDEV_TX_OK; }

Contributors

PersonTokensPropCommitsCommitProp
eric dumazeteric dumazet5656.00%375.00%
james chapmanjames chapman4444.00%125.00%
Total100100.00%4100.00%


static struct rtnl_link_stats64 *l2tp_eth_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) { struct l2tp_eth *priv = netdev_priv(dev); stats->tx_bytes = atomic_long_read(&priv->tx_bytes); stats->tx_packets = atomic_long_read(&priv->tx_packets); stats->tx_dropped = atomic_long_read(&priv->tx_dropped); stats->rx_bytes = atomic_long_read(&priv->rx_bytes); stats->rx_packets = atomic_long_read(&priv->rx_packets); stats->rx_errors = atomic_long_read(&priv->rx_errors); return stats; }

Contributors

PersonTokensPropCommitsCommitProp
eric dumazeteric dumazet103100.00%2100.00%
Total103100.00%2100.00%

static struct net_device_ops l2tp_eth_netdev_ops = { .ndo_init = l2tp_eth_dev_init, .ndo_uninit = l2tp_eth_dev_uninit, .ndo_start_xmit = l2tp_eth_dev_xmit, .ndo_get_stats64 = l2tp_eth_get_stats64, .ndo_set_mac_address = eth_mac_addr, };
static void l2tp_eth_dev_setup(struct net_device *dev) { ether_setup(dev); dev->priv_flags &= ~IFF_TX_SKB_SHARING; dev->features |= NETIF_F_LLTX; dev->netdev_ops = &l2tp_eth_netdev_ops; dev->destructor = free_netdev; }

Contributors

PersonTokensPropCommitsCommitProp
james chapmanjames chapman2969.05%133.33%
neil hormanneil horman716.67%133.33%
eric dumazeteric dumazet614.29%133.33%
Total42100.00%3100.00%


static void l2tp_eth_dev_recv(struct l2tp_session *session, struct sk_buff *skb, int data_len) { struct l2tp_eth_sess *spriv = l2tp_session_priv(session); struct net_device *dev = spriv->dev; struct l2tp_eth *priv = netdev_priv(dev); if (session->debug & L2TP_MSG_DATA) { unsigned int length; length = min(32u, skb->len); if (!pskb_may_pull(skb, length)) goto error; pr_debug("%s: eth recv\n", session->name); print_hex_dump_bytes("", DUMP_PREFIX_OFFSET, skb->data, length); } if (!pskb_may_pull(skb, ETH_HLEN)) goto error; secpath_reset(skb); /* checksums verified by L2TP */ skb->ip_summed = CHECKSUM_NONE; skb_dst_drop(skb); nf_reset(skb); if (dev_forward_skb(dev, skb) == NET_RX_SUCCESS) { atomic_long_inc(&priv->rx_packets); atomic_long_add(data_len, &priv->rx_bytes); } else { atomic_long_inc(&priv->rx_errors); } return; error: atomic_long_inc(&priv->rx_errors); kfree_skb(skb); }

Contributors

PersonTokensPropCommitsCommitProp
james chapmanjames chapman15175.12%125.00%
eric dumazeteric dumazet4321.39%250.00%
joe perchesjoe perches73.48%125.00%
Total201100.00%4100.00%


static void l2tp_eth_delete(struct l2tp_session *session) { struct l2tp_eth_sess *spriv; struct net_device *dev; if (session) { spriv = l2tp_session_priv(session); dev = spriv->dev; if (dev) { unregister_netdev(dev); spriv->dev = NULL; module_put(THIS_MODULE); } } }

Contributors

PersonTokensPropCommitsCommitProp
james chapmanjames chapman5791.94%150.00%
eric dumazeteric dumazet58.06%150.00%
Total62100.00%2100.00%

#if defined(CONFIG_L2TP_DEBUGFS) || defined(CONFIG_L2TP_DEBUGFS_MODULE)
static void l2tp_eth_show(struct seq_file *m, void *arg) { struct l2tp_session *session = arg; struct l2tp_eth_sess *spriv = l2tp_session_priv(session); struct net_device *dev = spriv->dev; seq_printf(m, " interface %s\n", dev->name); }

Contributors

PersonTokensPropCommitsCommitProp
james chapmanjames chapman52100.00%1100.00%
Total52100.00%1100.00%

#endif
static int l2tp_eth_create(struct net *net, u32 tunnel_id, u32 session_id, u32 peer_session_id, struct l2tp_session_cfg *cfg) { struct net_device *dev; char name[IFNAMSIZ]; struct l2tp_tunnel *tunnel; struct l2tp_session *session; struct l2tp_eth *priv; struct l2tp_eth_sess *spriv; int rc; struct l2tp_eth_net *pn; tunnel = l2tp_tunnel_find(net, tunnel_id); if (!tunnel) { rc = -ENODEV; goto out; } session = l2tp_session_find(net, tunnel, session_id); if (session) { rc = -EEXIST; goto out; } if (cfg->ifname) { dev = dev_get_by_name(net, cfg->ifname); if (dev) { dev_put(dev); rc = -EEXIST; goto out; } strlcpy(name, cfg->ifname, IFNAMSIZ); } else strcpy(name, L2TP_ETH_DEV_NAME); session = l2tp_session_create(sizeof(*spriv), tunnel, session_id, peer_session_id, cfg); if (!session) { rc = -ENOMEM; goto out; } dev = alloc_netdev(sizeof(*priv), name, NET_NAME_UNKNOWN, l2tp_eth_dev_setup); if (!dev) { rc = -ENOMEM; goto out_del_session; } dev_net_set(dev, net); if (session->mtu == 0) session->mtu = dev->mtu - session->hdr_len; dev->mtu = session->mtu; dev->needed_headroom += session->hdr_len; priv = netdev_priv(dev); priv->dev = dev; priv->session = session; INIT_LIST_HEAD(&priv->list); priv->tunnel_sock = tunnel->sock; session->recv_skb = l2tp_eth_dev_recv; session->session_close = l2tp_eth_delete; #if defined(CONFIG_L2TP_DEBUGFS) || defined(CONFIG_L2TP_DEBUGFS_MODULE) session->show = l2tp_eth_show; #endif spriv = l2tp_session_priv(session); spriv->dev = dev; rc = register_netdev(dev); if (rc < 0) goto out_del_dev; __module_get(THIS_MODULE); /* Must be done after register_netdev() */ strlcpy(session->ifname, dev->name, IFNAMSIZ); dev_hold(dev); pn = l2tp_eth_pernet(dev_net(dev)); spin_lock(&pn->l2tp_eth_lock); list_add(&priv->list, &pn->l2tp_eth_dev_list); spin_unlock(&pn->l2tp_eth_lock); return 0; out_del_dev: free_netdev(dev); spriv->dev = NULL; out_del_session: l2tp_session_delete(session); out: return rc; }

Contributors

PersonTokensPropCommitsCommitProp
james chapmanjames chapman44295.05%233.33%
david s. millerdavid s. miller102.15%116.67%
tom parkintom parkin61.29%116.67%
eric dumazeteric dumazet51.08%116.67%
tom gundersentom gundersen20.43%116.67%
Total465100.00%6100.00%


static __net_init int l2tp_eth_init_net(struct net *net) { struct l2tp_eth_net *pn = net_generic(net, l2tp_eth_net_id); INIT_LIST_HEAD(&pn->l2tp_eth_dev_list); spin_lock_init(&pn->l2tp_eth_lock); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
james chapmanjames chapman3888.37%150.00%
jiri pirkojiri pirko511.63%150.00%
Total43100.00%2100.00%

static struct pernet_operations l2tp_eth_net_ops = { .init = l2tp_eth_init_net, .id = &l2tp_eth_net_id, .size = sizeof(struct l2tp_eth_net), }; static const struct l2tp_nl_cmd_ops l2tp_eth_nl_cmd_ops = { .session_create = l2tp_eth_create, .session_delete = l2tp_session_delete, };
static int __init l2tp_eth_init(void) { int err = 0; err = l2tp_nl_register_ops(L2TP_PWTYPE_ETH, &l2tp_eth_nl_cmd_ops); if (err) goto out; err = register_pernet_device(&l2tp_eth_net_ops); if (err) goto out_unreg; pr_info("L2TP ethernet pseudowire support (L2TPv3)\n"); return 0; out_unreg: l2tp_nl_unregister_ops(L2TP_PWTYPE_ETH); out: return err; }

Contributors

PersonTokensPropCommitsCommitProp
james chapmanjames chapman6598.48%150.00%
joe perchesjoe perches11.52%150.00%
Total66100.00%2100.00%


static void __exit l2tp_eth_exit(void) { unregister_pernet_device(&l2tp_eth_net_ops); l2tp_nl_unregister_ops(L2TP_PWTYPE_ETH); }

Contributors

PersonTokensPropCommitsCommitProp
james chapmanjames chapman20100.00%1100.00%
Total20100.00%1100.00%

module_init(l2tp_eth_init); module_exit(l2tp_eth_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("James Chapman <jchapman@katalix.com>"); MODULE_DESCRIPTION("L2TP ethernet pseudowire driver"); MODULE_VERSION("1.0"); MODULE_ALIAS_L2TP_PWTYPE(5);

Overall Contributors

PersonTokensPropCommitsCommitProp
james chapmanjames chapman124379.88%314.29%
eric dumazeteric dumazet24615.81%838.10%
david s. millerdavid s. miller201.29%14.76%
joe perchesjoe perches161.03%29.52%
neil hormanneil horman70.45%14.76%
tom parkintom parkin60.39%14.76%
stephen hemmingerstephen hemminger50.32%14.76%
jiri pirkojiri pirko50.32%14.76%
alexander couzensalexander couzens50.32%14.76%
tom gundersentom gundersen20.13%14.76%
danny kukawkadanny kukawka10.06%14.76%
Total1556100.00%21100.00%
Directory: net/l2tp
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.