cregit-Linux how code gets into the kernel

Release 4.7 net/netlink/af_netlink.c

Directory: net/netlink
/*
 * NETLINK      Kernel-user communication protocol.
 *
 *              Authors:        Alan Cox <alan@lxorguk.ukuu.org.uk>
 *                              Alexey Kuznetsov <kuznet@ms2.inr.ac.ru>
 *                              Patrick McHardy <kaber@trash.net>
 *
 *              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.
 *
 * Tue Jun 26 14:36:48 MEST 2001 Herbert "herp" Rosmanith
 *                               added netlink_proto_exit
 * Tue Jan 22 18:32:44 BRST 2002 Arnaldo C. de Melo <acme@conectiva.com.br>
 *                               use nlk_sk, as sk->protinfo is on a diet 8)
 * Fri Jul 22 19:51:12 MEST 2005 Harald Welte <laforge@gnumonks.org>
 *                               - inc module use count of module that owns
 *                                 the kernel socket in case userspace opens
 *                                 socket of same protocol
 *                               - remove all module support, since netlink is
 *                                 mandatory if CONFIG_NET=y these days
 */

#include <linux/module.h>

#include <linux/capability.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/stat.h>
#include <linux/socket.h>
#include <linux/un.h>
#include <linux/fcntl.h>
#include <linux/termios.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/fs.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
#include <linux/skbuff.h>
#include <linux/netdevice.h>
#include <linux/rtnetlink.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/notifier.h>
#include <linux/security.h>
#include <linux/jhash.h>
#include <linux/jiffies.h>
#include <linux/random.h>
#include <linux/bitops.h>
#include <linux/mm.h>
#include <linux/types.h>
#include <linux/audit.h>
#include <linux/mutex.h>
#include <linux/vmalloc.h>
#include <linux/if_arp.h>
#include <linux/rhashtable.h>
#include <asm/cacheflush.h>
#include <linux/hash.h>
#include <linux/genetlink.h>

#include <net/net_namespace.h>
#include <net/sock.h>
#include <net/scm.h>
#include <net/netlink.h>

#include "af_netlink.h"


struct listeners {
	
struct rcu_head		rcu;
	
unsigned long		masks[0];
};

/* state bits */

#define NETLINK_S_CONGESTED		0x0

/* flags */

#define NETLINK_F_KERNEL_SOCKET		0x1

#define NETLINK_F_RECV_PKTINFO		0x2

#define NETLINK_F_BROADCAST_SEND_ERROR	0x4

#define NETLINK_F_RECV_NO_ENOBUFS	0x8

#define NETLINK_F_LISTEN_ALL_NSID	0x10

#define NETLINK_F_CAP_ACK		0x20


static inline int netlink_is_kernel(struct sock *sk) { return nlk_sk(sk)->flags & NETLINK_F_KERNEL_SOCKET; }

Contributors

PersonTokensPropCommitsCommitProp
denis v. lunevdenis v. lunev2195.45%150.00%
nicolas dichtelnicolas dichtel14.55%150.00%
Total22100.00%2100.00%

struct netlink_table *nl_table __read_mostly; EXPORT_SYMBOL_GPL(nl_table); static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait); static int netlink_dump(struct sock *sk); static void netlink_skb_destructor(struct sk_buff *skb); /* nl_table locking explained: * Lookup and traversal are protected with an RCU read-side lock. Insertion * and removal are protected with per bucket lock while using RCU list * modification primitives and may run in parallel to RCU protected lookups. * Destruction of the Netlink socket may only occur *after* nl_table_lock has * been acquired * either during or after the socket has been removed from * the list and after an RCU grace period. */ DEFINE_RWLOCK(nl_table_lock); EXPORT_SYMBOL_GPL(nl_table_lock); static atomic_t nl_table_users = ATOMIC_INIT(0); #define nl_deref_protected(X) rcu_dereference_protected(X, lockdep_is_held(&nl_table_lock)); static ATOMIC_NOTIFIER_HEAD(netlink_chain); static DEFINE_SPINLOCK(netlink_tap_lock); static struct list_head netlink_tap_all __read_mostly; static const struct rhashtable_params netlink_rhashtable_params;
static inline u32 netlink_group_mask(u32 group) { return group ? 1 << (group - 1) : 0; }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy2295.65%150.00%
stephen hemmingerstephen hemminger14.35%150.00%
Total23100.00%2100.00%


static struct sk_buff *netlink_to_full_skb(const struct sk_buff *skb, gfp_t gfp_mask) { unsigned int len = skb_end_offset(skb); struct sk_buff *new; new = alloc_skb(len, gfp_mask); if (new == NULL) return NULL; NETLINK_CB(new).portid = NETLINK_CB(skb).portid; NETLINK_CB(new).dst_group = NETLINK_CB(skb).dst_group; NETLINK_CB(new).creds = NETLINK_CB(skb).creds; memcpy(skb_put(new, len), skb->data, len); return new; }

Contributors

PersonTokensPropCommitsCommitProp
daniel borkmanndaniel borkmann110100.00%1100.00%
Total110100.00%1100.00%


int netlink_add_tap(struct netlink_tap *nt) { if (unlikely(nt->dev->type != ARPHRD_NETLINK)) return -EINVAL; spin_lock(&netlink_tap_lock); list_add_rcu(&nt->list, &netlink_tap_all); spin_unlock(&netlink_tap_lock); __module_get(nt->module); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
daniel borkmanndaniel borkmann60100.00%1100.00%
Total60100.00%1100.00%

EXPORT_SYMBOL_GPL(netlink_add_tap);
static int __netlink_remove_tap(struct netlink_tap *nt) { bool found = false; struct netlink_tap *tmp; spin_lock(&netlink_tap_lock); list_for_each_entry(tmp, &netlink_tap_all, list) { if (nt == tmp) { list_del_rcu(&nt->list); found = true; goto out; } } pr_warn("__netlink_remove_tap: %p not found\n", nt); out: spin_unlock(&netlink_tap_lock); if (found) module_put(nt->module); return found ? 0 : -ENODEV; }

Contributors

PersonTokensPropCommitsCommitProp
daniel borkmanndaniel borkmann9398.94%150.00%
stephen hemmingerstephen hemminger11.06%150.00%
Total94100.00%2100.00%


int netlink_remove_tap(struct netlink_tap *nt) { int ret; ret = __netlink_remove_tap(nt); synchronize_net(); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
daniel borkmanndaniel borkmann26100.00%1100.00%
Total26100.00%1100.00%

EXPORT_SYMBOL_GPL(netlink_remove_tap);
static bool netlink_filter_tap(const struct sk_buff *skb) { struct sock *sk = skb->sk; /* We take the more conservative approach and * whitelist socket protocols that may pass. */ switch (sk->sk_protocol) { case NETLINK_ROUTE: case NETLINK_USERSOCK: case NETLINK_SOCK_DIAG: case NETLINK_NFLOG: case NETLINK_XFRM: case NETLINK_FIB_LOOKUP: case NETLINK_NETFILTER: case NETLINK_GENERIC: return true; } return false; }

Contributors

PersonTokensPropCommitsCommitProp
daniel borkmanndaniel borkmann5795.00%150.00%
varka bhadramvarka bhadram35.00%150.00%
Total60100.00%2100.00%


static int __netlink_deliver_tap_skb(struct sk_buff *skb, struct net_device *dev) { struct sk_buff *nskb; struct sock *sk = skb->sk; int ret = -ENOMEM; dev_hold(dev); if (is_vmalloc_addr(skb->head)) nskb = netlink_to_full_skb(skb, GFP_ATOMIC); else nskb = skb_clone(skb, GFP_ATOMIC); if (nskb) { nskb->dev = dev; nskb->protocol = htons((u16) sk->sk_protocol); nskb->pkt_type = netlink_is_kernel(sk) ? PACKET_KERNEL : PACKET_USER; skb_reset_network_header(nskb); ret = dev_queue_xmit(nskb); if (unlikely(ret > 0)) ret = net_xmit_errno(ret); } dev_put(dev); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
daniel borkmanndaniel borkmann144100.00%5100.00%
Total144100.00%5100.00%


static void __netlink_deliver_tap(struct sk_buff *skb) { int ret; struct netlink_tap *tmp; if (!netlink_filter_tap(skb)) return; list_for_each_entry_rcu(tmp, &netlink_tap_all, list) { ret = __netlink_deliver_tap_skb(skb, tmp->dev); if (unlikely(ret)) break; } }

Contributors

PersonTokensPropCommitsCommitProp
daniel borkmanndaniel borkmann57100.00%2100.00%
Total57100.00%2100.00%


static void netlink_deliver_tap(struct sk_buff *skb) { rcu_read_lock(); if (unlikely(!list_empty(&netlink_tap_all))) __netlink_deliver_tap(skb); rcu_read_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
daniel borkmanndaniel borkmann34100.00%1100.00%
Total34100.00%1100.00%


static void netlink_deliver_tap_kernel(struct sock *dst, struct sock *src, struct sk_buff *skb) { if (!(netlink_is_kernel(dst) && netlink_is_kernel(src))) netlink_deliver_tap(skb); }

Contributors

PersonTokensPropCommitsCommitProp
daniel borkmanndaniel borkmann41100.00%1100.00%
Total41100.00%1100.00%


static void netlink_overrun(struct sock *sk) { struct netlink_sock *nlk = nlk_sk(sk); if (!(nlk->flags & NETLINK_F_RECV_NO_ENOBUFS)) { if (!test_and_set_bit(NETLINK_S_CONGESTED, &nlk_sk(sk)->state)) { sk->sk_err = ENOBUFS; sk->sk_error_report(sk); } } atomic_inc(&sk->sk_drops); }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy7197.26%150.00%
nicolas dichtelnicolas dichtel22.74%150.00%
Total73100.00%2100.00%


static void netlink_rcv_wake(struct sock *sk) { struct netlink_sock *nlk = nlk_sk(sk); if (skb_queue_empty(&sk->sk_receive_queue)) clear_bit(NETLINK_S_CONGESTED, &nlk->state); if (!test_bit(NETLINK_S_CONGESTED, &nlk->state)) wake_up_interruptible(&nlk->wait); }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy6096.77%150.00%
nicolas dichtelnicolas dichtel23.23%150.00%
Total62100.00%2100.00%


static void netlink_skb_destructor(struct sk_buff *skb) { if (is_vmalloc_addr(skb->head)) { if (!skb->cloned || !atomic_dec_return(&(skb_shinfo(skb)->dataref))) vfree(skb->head); skb->head = NULL; } if (skb->sk != NULL) sock_rfree(skb); }

Contributors

PersonTokensPropCommitsCommitProp
florian westphalflorian westphal5782.61%150.00%
patrick mchardypatrick mchardy1217.39%150.00%
Total69100.00%2100.00%


static void netlink_skb_set_owner_r(struct sk_buff *skb, struct sock *sk) { WARN_ON(skb->sk != NULL); skb->sk = sk; skb->destructor = netlink_skb_destructor; atomic_add(skb->truesize, &sk->sk_rmem_alloc); sk_mem_charge(sk, skb->truesize); }

Contributors

PersonTokensPropCommitsCommitProp
florian westphalflorian westphal4068.97%133.33%
patrick mchardypatrick mchardy1831.03%266.67%
Total58100.00%3100.00%


static void netlink_sock_destruct(struct sock *sk) { struct netlink_sock *nlk = nlk_sk(sk); if (nlk->cb_running) { if (nlk->cb.done) nlk->cb.done(&nlk->cb); module_put(nlk->cb.module); kfree_skb(nlk->cb.skb); } skb_queue_purge(&sk->sk_receive_queue); if (!sock_flag(sk, SOCK_DEAD)) { printk(KERN_ERR "Freeing alive netlink socket %p\n", sk); return; } WARN_ON(atomic_read(&sk->sk_rmem_alloc)); WARN_ON(atomic_read(&sk->sk_wmem_alloc)); WARN_ON(nlk_sk(sk)->groups); }

Contributors

PersonTokensPropCommitsCommitProp
florian westphalflorian westphal4938.28%19.09%
pre-gitpre-git3728.91%218.18%
patrick mchardypatrick mchardy2922.66%327.27%
arnaldo carvalho de meloarnaldo carvalho de melo53.91%218.18%
david s. millerdavid s. miller32.34%19.09%
ilpo jarvinenilpo jarvinen32.34%19.09%
james morrisjames morris21.56%19.09%
Total128100.00%11100.00%

/* This lock without WQ_FLAG_EXCLUSIVE is good on UP and it is _very_ bad on * SMP. Look, when several writers sleep and reader wakes them up, all but one * immediately hit write lock and grab all the cpus. Exclusive sleep solves * this, _but_ remember, it adds useless work on UP machines. */
void netlink_table_grab(void) __acquires (nl_table_lock) { might_sleep(); write_lock_irq(&nl_table_lock); if (atomic_read(&nl_table_users)) { DECLARE_WAITQUEUE(wait, current); add_wait_queue_exclusive(&nl_table_wait, &wait); for (;;) { set_current_state(TASK_UNINTERRUPTIBLE); if (atomic_read(&nl_table_users) == 0) break; write_unlock_irq(&nl_table_lock); schedule(); write_lock_irq(&nl_table_lock); } __set_current_state(TASK_RUNNING); remove_wait_queue(&nl_table_wait, &wait); } }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git8889.80%457.14%
eric dumazeteric dumazet44.08%114.29%
arjan van de venarjan van de ven33.06%114.29%
johannes bergjohannes berg33.06%114.29%
Total98100.00%7100.00%


void netlink_table_ungrab(void) __releases (nl_table_lock) { write_unlock_irq(&nl_table_lock); wake_up(&nl_table_wait); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git1878.26%360.00%
eric dumazeteric dumazet417.39%120.00%
arjan van de venarjan van de ven14.35%120.00%
Total23100.00%5100.00%


static inline void netlink_lock_table(void) { /* read_lock() synchronizes us to netlink_table_grab */ read_lock(&nl_table_lock); atomic_inc(&nl_table_users); read_unlock(&nl_table_lock); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2796.43%266.67%
patrick mchardypatrick mchardy13.57%133.33%
Total28100.00%3100.00%


static inline void netlink_unlock_table(void) { if (atomic_dec_and_test(&nl_table_users)) wake_up(&nl_table_wait); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git2295.65%266.67%
patrick mchardypatrick mchardy14.35%133.33%
Total23100.00%3100.00%

struct netlink_compare_arg { possible_net_t pnet; u32 portid; }; /* Doing sizeof directly may yield 4 extra bytes on 64-bit. */ #define netlink_compare_arg_len \ (offsetof(struct netlink_compare_arg, portid) + sizeof(u32))
static inline int netlink_compare(struct rhashtable_compare_arg *arg, const void *ptr) { const struct netlink_compare_arg *x = arg->key; const struct netlink_sock *nlk = ptr; return nlk->portid != x->portid || !net_eq(sock_net(&nlk->sk), read_pnet(&x->pnet)); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu2640.62%250.00%
thomas grafthomas graf2335.94%125.00%
gao fenggao feng1523.44%125.00%
Total64100.00%4100.00%


static void netlink_compare_arg_init(struct netlink_compare_arg *arg, struct net *net, u32 portid) { memset(arg, 0, sizeof(*arg)); write_pnet(&arg->pnet, net); arg->portid = portid; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu48100.00%1100.00%
Total48100.00%1100.00%


static struct sock *__netlink_lookup(struct netlink_table *table, u32 portid, struct net *net) { struct netlink_compare_arg arg; netlink_compare_arg_init(&arg, net, portid); return rhashtable_lookup_fast(&table->hash, &arg, netlink_rhashtable_params); }

Contributors

PersonTokensPropCommitsCommitProp
thomas grafthomas graf3367.35%250.00%
herbert xuherbert xu1224.49%125.00%
gao fenggao feng48.16%125.00%
Total49100.00%4100.00%


static int __netlink_insert(struct netlink_table *table, struct sock *sk) { struct netlink_compare_arg arg; netlink_compare_arg_init(&arg, sock_net(sk), nlk_sk(sk)->portid); return rhashtable_lookup_insert_key(&table->hash, &arg, &nlk_sk(sk)->node, netlink_rhashtable_params); }

Contributors

PersonTokensPropCommitsCommitProp
ying xueying xue4066.67%125.00%
herbert xuherbert xu2033.33%375.00%
Total60100.00%4100.00%


static struct sock *netlink_lookup(struct net *net, int protocol, u32 portid) { struct netlink_table *table = &nl_table[protocol]; struct sock *sk; rcu_read_lock(); sk = __netlink_lookup(table, portid, net); if (sk) sock_hold(sk); rcu_read_unlock(); return sk; }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy2132.81%112.50%
pre-gitpre-git1726.56%225.00%
thomas grafthomas graf914.06%112.50%
herbert xuherbert xu812.50%112.50%
gao fenggao feng46.25%112.50%
arnaldo carvalho de meloarnaldo carvalho de melo34.69%112.50%
eric w. biedermaneric w. biederman23.12%112.50%
Total64100.00%8100.00%

static const struct proto_ops netlink_ops;
static void netlink_update_listeners(struct sock *sk) { struct netlink_table *tbl = &nl_table[sk->sk_protocol]; unsigned long mask; unsigned int i; struct listeners *listeners; listeners = nl_deref_protected(tbl->listeners); if (!listeners) return; for (i = 0; i < NLGRPLONGS(tbl->groups); i++) { mask = 0; sk_for_each_bound(sk, &tbl->mc_list) { if (i < NLGRPLONGS(nlk_sk(sk)->ngroups)) mask |= nlk_sk(sk)->groups[i]; } listeners->masks[i] = mask; } /* this function is only called with the netlink table "grabbed", which * makes sure updates are visible before bind or setsockopt return. */ }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy8167.50%125.00%
eric dumazeteric dumazet2218.33%250.00%
johannes bergjohannes berg1714.17%125.00%
Total120100.00%4100.00%


static int netlink_insert(struct sock *sk, u32 portid) { struct netlink_table *table = &nl_table[sk->sk_protocol]; int err; lock_sock(sk); err = nlk_sk(sk)->portid == portid ? 0 : -EBUSY; if (nlk_sk(sk)->bound) goto err; err = -ENOMEM; if (BITS_PER_LONG > 32 && unlikely(atomic_read(&table->hash.nelems) >= UINT_MAX)) goto err; nlk_sk(sk)->portid = portid; sock_hold(sk); err = __netlink_insert(table, sk); if (err) { /* In case the hashtable backend returns with -EBUSY * from here, it must not escape to the caller. */ if (unlikely(err == -EBUSY)) err = -EOVERFLOW; if (err == -EEXIST) err = -EADDRINUSE; sock_put(sk); goto err; } /* We need to ensure that the socket is hashed and visible. */ smp_wmb(); nlk_sk(sk)->bound = portid; err: release_sock(sk); return err; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu12569.44%650.00%
thomas grafthomas graf2413.33%216.67%
daniel borkmanndaniel borkmann168.89%18.33%
ying xueying xue105.56%18.33%
gao fenggao feng31.67%18.33%
eric w. biedermaneric w. biederman21.11%18.33%
Total180100.00%12100.00%


static void netlink_remove(struct sock *sk) { struct netlink_table *table; table = &nl_table[sk->sk_protocol]; if (!rhashtable_remove_fast(&table->hash, &nlk_sk(sk)->node, netlink_rhashtable_params)) { WARN_ON(atomic_read(&sk->sk_refcnt) == 1); __sock_put(sk); } netlink_table_grab(); if (nlk_sk(sk)->subscriptions) { __sk_del_bind_node(sk); netlink_update_listeners(sk); } if (sk->sk_protocol == NETLINK_GENERIC) atomic_inc(&genl_sk_destructing_cnt); netlink_table_ungrab(); }

Contributors

PersonTokensPropCommitsCommitProp
thomas grafthomas graf4743.52%112.50%
herbert xuherbert xu3330.56%225.00%
johannes bergjohannes berg2119.44%225.00%
pre-gitpre-git65.56%225.00%
patrick mchardypatrick mchardy10.93%112.50%
Total108100.00%8100.00%

static struct proto netlink_proto = { .name = "NETLINK", .owner = THIS_MODULE, .obj_size = sizeof(struct netlink_sock), };
static int __netlink_create(struct net *net, struct socket *sock, struct mutex *cb_mutex, int protocol, int kern) { struct sock *sk; struct netlink_sock *nlk; sock->ops = &netlink_ops; sk = sk_alloc(net, PF_NETLINK, GFP_KERNEL, &netlink_proto, kern); if (!sk) return -ENOMEM; sock_init_data(sock, sk); nlk = nlk_sk(sk); if (cb_mutex) { nlk->cb_mutex = cb_mutex; } else { nlk->cb_mutex = &nlk->cb_def_mutex; mutex_init(nlk->cb_mutex); } init_waitqueue_head(&nlk->wait); sk->sk_destruct = netlink_sock_destruct; sk->sk_protocol = protocol; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy10173.72%333.33%
pre-gitpre-git1712.41%111.11%
eric w. biedermaneric w. biederman128.76%222.22%
david s. millerdavid s. miller42.92%111.11%
eric dumazeteric dumazet21.46%111.11%
arnaldo carvalho de meloarnaldo carvalho de melo10.73%111.11%
Total137100.00%9100.00%


static int netlink_create(struct net *net, struct socket *sock, int protocol, int kern) { struct module *module = NULL; struct mutex *cb_mutex; struct netlink_sock *nlk; int (*bind)(struct net *net, int group); void (*unbind)(struct net *net, int group); int err = 0; sock->state = SS_UNCONNECTED; if (sock->type != SOCK_RAW && sock->type != SOCK_DGRAM) return -ESOCKTNOSUPPORT; if (protocol < 0 || protocol >= MAX_LINKS) return -EPROTONOSUPPORT; netlink_lock_table(); #ifdef CONFIG_MODULES if (!nl_table[protocol].registered) { netlink_unlock_table(); request_module("net-pf-%d-proto-%d", PF_NETLINK, protocol); netlink_lock_table(); } #endif if (nl_table[protocol].registered && try_module_get(nl_table[protocol].module)) module = nl_table[protocol].module; else err = -EPROTONOSUPPORT; cb_mutex = nl_table[protocol].cb_mutex; bind = nl_table[protocol].bind; unbind = nl_table[protocol].unbind; netlink_unlock_table(); if (err < 0) goto out; err = __netlink_create(net, sock, cb_mutex, protocol, kern); if (err < 0) goto out_module; local_bh_disable(); sock_prot_inuse_add(net, &netlink_proto, 1); local_bh_enable(); nlk = nlk_sk(sock->sk); nlk->module = module; nlk->netlink_bind = bind; nlk->netlink_unbind = unbind; out: return err; out_module: module_put(module); goto out; }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy11538.08%526.32%
pre-gitpre-git5016.56%210.53%
harald welteharald welte3210.60%15.26%
richard guy briggsrichard guy briggs268.61%15.26%
pablo neira ayusopablo neira ayuso247.95%15.26%
alexey dobriyanalexey dobriyan154.97%15.26%
johannes bergjohannes berg113.64%210.53%
eric dumazeteric dumazet103.31%15.26%
eric w. biedermaneric w. biederman92.98%210.53%
david s. millerdavid s. miller61.99%15.26%
eric pariseric paris30.99%15.26%
arnaldo carvalho de meloarnaldo carvalho de melo10.33%15.26%
Total302100.00%19100.00%


static void deferred_put_nlk_sk(struct rcu_head *head) { struct netlink_sock *nlk = container_of(head, struct netlink_sock, rcu); sock_put(&nlk->sk); }

Contributors

PersonTokensPropCommitsCommitProp
thomas grafthomas graf34100.00%1100.00%
Total34100.00%1100.00%


static int netlink_release(struct socket *sock) { struct sock *sk = sock->sk; struct netlink_sock *nlk; if (!sk) return 0; netlink_remove(sk); sock_orphan(sk); nlk = nlk_sk(sk); /* * OK. Socket is unlinked, any packets that arrive now * will be purged. */ /* must not acquire netlink_table_lock in any way again before unbind * and notifying genetlink is done as otherwise it might deadlock */ if (nlk->netlink_unbind) { int i; for (i = 0; i < nlk->ngroups; i++) if (test_bit(i, nlk->groups)) nlk->netlink_unbind(sock_net(sk), i + 1); } if (sk->sk_protocol == NETLINK_GENERIC && atomic_dec_return(&genl_sk_destructing_cnt) == 0) wake_up(&genl_sk_destructing_waitq); sock->sk = NULL; wake_up_interruptible_all(&nlk->wait); skb_queue_purge(&sk->sk_write_queue); if (nlk->portid && nlk->bound) { struct netlink_notify n = { .net = sock_net(sk), .protocol = sk->sk_protocol, .portid = nlk->portid, }; atomic_notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n); } module_put(nlk->module); if (netlink_is_kernel(sk)) { netlink_table_grab(); BUG_ON(nl_table[sk->sk_protocol].registered == 0); if (--nl_table[sk->sk_protocol].registered == 0) { struct listeners *old; old = nl_deref_protected(nl_table[sk->sk_protocol].listeners); RCU_INIT_POINTER(nl_table[sk->sk_protocol].listeners, NULL); kfree_rcu(old, rcu); nl_table[sk->sk_protocol].module = NULL; nl_table[sk->sk_protocol].bind = NULL; nl_table[sk->sk_protocol].unbind = NULL; nl_table[sk->sk_protocol].flags = 0; nl_table[sk->sk_protocol].registered = 0; } netlink_table_ungrab(); } kfree(nlk->groups); nlk->groups = NULL; local_bh_disable(); sock_prot_inuse_add(sock_net(sk), &netlink_proto, -1); local_bh_enable(); call_rcu(&nlk->rcu, deferred_put_nlk_sk); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
johannes bergjohannes berg7819.95%26.45%
pre-gitpre-git5915.09%39.68%
eric dumazeteric dumazet4912.53%39.68%
patrick mchardypatrick mchardy4311.00%412.90%
denis v. lunevdenis v. lunev389.72%39.68%
james morrisjames morris276.91%13.23%
pablo neira ayusopablo neira ayuso225.63%13.23%
harald welteharald welte184.60%13.23%
david s. millerdavid s. miller143.58%26.45%
richard guy briggsrichard guy briggs112.81%13.23%
eric w. biedermaneric w. biederman82.05%26.45%
thomas grafthomas graf71.79%13.23%
art haasart haas41.02%13.23%
arnaldo carvalho de meloarnaldo carvalho de melo41.02%26.45%
dmitry ivanovdmitry ivanov41.02%13.23%
hideaki yoshifujihideaki yoshifuji30.77%13.23%
herbert xuherbert xu10.26%13.23%
alan sternalan stern10.26%13.23%
Total391100.00%31100.00%


static int netlink_autobind(struct socket *sock) { struct sock *sk = sock->sk; struct net *net = sock_net(sk); struct netlink_table *table = &nl_table[sk->sk_protocol]; s32 portid = task_tgid_vnr(current); int err; s32 rover = -4096; bool ok; retry: cond_resched(); rcu_read_lock(); ok = !__netlink_lookup(table, portid, net); rcu_read_unlock(); if (!ok) { /* Bind collision, search negative portid values. */ if (rover == -4096) /* rover will be in range [S32_MIN, -4097] */ rover = S32_MIN + prandom_u32_max(-4096 - S32_MIN); else if (rover >= -4096) rover = -4097; portid = rover--; goto retry; } err = netlink_insert(sk, portid); if (err == -EADDRINUSE) goto retry; /* If 2 threads race to autobind, that is fine. */ if (err == -EBUSY) err = 0; return err; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu6940.83%321.43%
pre-gitpre-git6136.09%214.29%
david s. millerdavid s. miller148.28%214.29%
eric w. biedermaneric w. biederman127.10%214.29%
gao fenggao feng31.78%17.14%
hideaki yoshifujihideaki yoshifuji31.78%17.14%
thomas goffthomas goff31.78%17.14%
thomas grafthomas graf31.78%17.14%
arnaldo carvalho de meloarnaldo carvalho de melo10.59%17.14%
Total169100.00%14100.00%

/** * __netlink_ns_capable - General netlink message capability test * @nsp: NETLINK_CB of the socket buffer holding a netlink command from userspace. * @user_ns: The user namespace of the capability to use * @cap: The capability to use * * Test to see if the opener of the socket we received the message * from had when the netlink socket was created and the sender of the * message has has the capability @cap in the user namespace @user_ns. */
bool __netlink_ns_capable(const struct netlink_skb_parms *nsp, struct user_namespace *user_ns, int cap) { return ((nsp->flags & NETLINK_SKB_DST) || file_ns_capable(nsp->sk->sk_socket->file, user_ns, cap)) && ns_capable(user_ns, cap); }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman52100.00%2100.00%
Total52100.00%2100.00%

EXPORT_SYMBOL(__netlink_ns_capable); /** * netlink_ns_capable - General netlink message capability test * @skb: socket buffer holding a netlink command from userspace * @user_ns: The user namespace of the capability to use * @cap: The capability to use * * Test to see if the opener of the socket we received the message * from had when the netlink socket was created and the sender of the * message has has the capability @cap in the user namespace @user_ns. */
bool netlink_ns_capable(const struct sk_buff *skb, struct user_namespace *user_ns, int cap) { return __netlink_ns_capable(&NETLINK_CB(skb), user_ns, cap); }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman33100.00%1100.00%
Total33100.00%1100.00%

EXPORT_SYMBOL(netlink_ns_capable); /** * netlink_capable - Netlink global message capability test * @skb: socket buffer holding a netlink command from userspace * @cap: The capability to use * * Test to see if the opener of the socket we received the message * from had when the netlink socket was created and the sender of the * message has has the capability @cap in all user namespaces. */
bool netlink_capable(const struct sk_buff *skb, int cap) { return netlink_ns_capable(skb, &init_user_ns, cap); }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman25100.00%1100.00%
Total25100.00%1100.00%

EXPORT_SYMBOL(netlink_capable); /** * netlink_net_capable - Netlink network namespace message capability test * @skb: socket buffer holding a netlink command from userspace * @cap: The capability to use * * Test to see if the opener of the socket we received the message * from had when the netlink socket was created and the sender of the * message has has the capability @cap over the network namespace of * the socket we received the message from. */
bool netlink_net_capable(const struct sk_buff *skb, int cap) { return netlink_ns_capable(skb, sock_net(skb->sk)->user_ns, cap); }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman31100.00%1100.00%
Total31100.00%1100.00%

EXPORT_SYMBOL(netlink_net_capable);
static inline int netlink_allowed(const struct socket *sock, unsigned int flag) { return (nl_table[sock->sk->sk_protocol].flags & flag) || ns_capable(sock_net(sock->sk)->user_ns, CAP_NET_ADMIN); }

Contributors

PersonTokensPropCommitsCommitProp
james morrisjames morris3063.83%112.50%
eric w. biedermaneric w. biederman1123.40%225.00%
pablo neira ayusopablo neira ayuso36.38%225.00%
herbert xuherbert xu12.13%112.50%
arnaldo carvalho de meloarnaldo carvalho de melo12.13%112.50%
stephen hemmingerstephen hemminger12.13%112.50%
Total47100.00%8100.00%


static void netlink_update_subscriptions(struct sock *sk, unsigned int subscriptions) { struct netlink_sock *nlk = nlk_sk(sk); if (nlk->subscriptions && !subscriptions) __sk_del_bind_node(sk); else if (!nlk->subscriptions && subscriptions) sk_add_bind_node(sk, &nl_table[sk->sk_protocol].mc_list); nlk->subscriptions = subscriptions; }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy70100.00%1100.00%
Total70100.00%1100.00%


static int netlink_realloc_groups(struct sock *sk) { struct netlink_sock *nlk = nlk_sk(sk); unsigned int groups; unsigned long *new_groups; int err = 0; netlink_table_grab(); groups = nl_table[sk->sk_protocol].groups; if (!nl_table[sk->sk_protocol].registered) { err = -ENOENT; goto out_unlock; } if (nlk->ngroups >= groups) goto out_unlock; new_groups = krealloc(nlk->groups, NLGRPSZ(groups), GFP_ATOMIC); if (new_groups == NULL) { err = -ENOMEM; goto out_unlock; } memset((char *)new_groups + NLGRPSZ(nlk->ngroups), 0, NLGRPSZ(groups) - NLGRPSZ(nlk->ngroups)); nlk->groups = new_groups; nlk->ngroups = groups; out_unlock: netlink_table_ungrab(); return err; }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy8853.66%150.00%
johannes bergjohannes berg7646.34%150.00%
Total164100.00%2100.00%


static void netlink_undo_bind(int group, long unsigned int groups, struct sock *sk) { struct netlink_sock *nlk = nlk_sk(sk); int undo; if (!nlk->netlink_unbind) return; for (undo = 0; undo < group; undo++) if (test_bit(undo, &groups)) nlk->netlink_unbind(sock_net(sk), undo + 1); }

Contributors

PersonTokensPropCommitsCommitProp
richard guy briggsrichard guy briggs5672.73%120.00%
johannes bergjohannes berg1823.38%240.00%
pablo neira ayusopablo neira ayuso22.60%120.00%
hiroaki shimodahiroaki shimoda11.30%120.00%
Total77100.00%5100.00%


static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len) { struct sock *sk = sock->sk; struct net *net = sock_net(sk); struct netlink_sock *nlk = nlk_sk(sk); struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; int err; long unsigned int groups = nladdr->nl_groups; bool bound; if (addr_len < sizeof(struct sockaddr_nl)) return -EINVAL; if (nladdr->nl_family != AF_NETLINK) return -EINVAL; /* Only superuser is allowed to listen multicasts */ if (groups) { if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV)) return -EPERM; err = netlink_realloc_groups(sk); if (err) return err; } bound = nlk->bound; if (bound) { /* Ensure nlk->portid is up-to-date. */ smp_rmb(); if (nladdr->nl_pid != nlk->portid) return -EINVAL; } if (nlk->netlink_bind && groups) { int group; for (group = 0; group < nlk->ngroups; group++) { if (!test_bit(group, &groups)) continue; err = nlk->netlink_bind(net, group + 1); if (!err) continue; netlink_undo_bind(group, groups, sk); return err; } } /* No need for barriers here as we return to user-space without * using any of the bound attributes. */ if (!bound) { err = nladdr->nl_pid ? netlink_insert(sk, nladdr->nl_pid) : netlink_autobind(sock); if (err) { netlink_undo_bind(nlk->ngroups, groups, sk); return err; } } if (!groups && (nlk->groups == NULL || !(u32)nlk->groups[0])) return 0; netlink_table_grab(); netlink_update_subscriptions(sk, nlk->subscriptions + hweight32(groups) - hweight32(nlk->groups[0])); nlk->groups[0] = (nlk->groups[0] & ~0xffffffffUL) | groups; netlink_update_listeners(sk); netlink_table_ungrab(); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git9926.54%313.04%
richard guy briggsrichard guy briggs9425.20%14.35%
patrick mchardypatrick mchardy6717.96%313.04%
herbert xuherbert xu6216.62%313.04%
hannes frederic sowahannes frederic sowa143.75%14.35%
david s. millerdavid s. miller123.22%14.35%
eric w. biedermaneric w. biederman92.41%313.04%
johannes bergjohannes berg71.88%313.04%
hideaki yoshifujihideaki yoshifuji30.80%14.35%
pablo neira ayusopablo neira ayuso30.80%28.70%
james morrisjames morris20.54%14.35%
arnaldo carvalho de meloarnaldo carvalho de melo10.27%14.35%
Total373100.00%23100.00%


static int netlink_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags) { int err = 0; struct sock *sk = sock->sk; struct netlink_sock *nlk = nlk_sk(sk); struct sockaddr_nl *nladdr = (struct sockaddr_nl *)addr; if (alen < sizeof(addr->sa_family)) return -EINVAL; if (addr->sa_family == AF_UNSPEC) { sk->sk_state = NETLINK_UNCONNECTED; nlk->dst_portid = 0; nlk->dst_group = 0; return 0; } if (addr->sa_family != AF_NETLINK) return -EINVAL; if ((nladdr->nl_groups || nladdr->nl_pid) && !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) return -EPERM; /* No need for barriers here as we return to user-space without * using any of the bound attributes. */ if (!nlk->bound) err = netlink_autobind(sock); if (err == 0) { sk->sk_state = NETLINK_CONNECTED; nlk->dst_portid = nladdr->nl_pid; nlk->dst_group = ffs(nladdr->nl_groups); } return err; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git12967.54%425.00%
herbert xuherbert xu157.85%318.75%
changli gaochangli gao157.85%16.25%
david s. millerdavid s. miller147.33%16.25%
mike pecovnikmike pecovnik63.14%16.25%
patrick mchardypatrick mchardy52.62%16.25%
eric w. biedermaneric w. biederman31.57%212.50%
james morrisjames morris21.05%16.25%
pablo neira ayusopablo neira ayuso10.52%16.25%
arnaldo carvalho de meloarnaldo carvalho de melo10.52%16.25%
Total191100.00%16100.00%


static int netlink_getname(struct socket *sock, struct sockaddr *addr, int *addr_len, int peer) { struct sock *sk = sock->sk; struct netlink_sock *nlk = nlk_sk(sk); DECLARE_SOCKADDR(struct sockaddr_nl *, nladdr, addr); nladdr->nl_family = AF_NETLINK; nladdr->nl_pad = 0; *addr_len = sizeof(*nladdr); if (peer) { nladdr->nl_pid = nlk->dst_portid; nladdr->nl_groups = netlink_group_mask(nlk->dst_group); } else { nladdr->nl_pid = nlk->portid; nladdr->nl_groups = nlk->groups ? nlk->groups[0] : 0; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git8968.46%220.00%
david s. millerdavid s. miller1813.85%220.00%
patrick mchardypatrick mchardy1310.00%330.00%
cyrill gorcunovcyrill gorcunov75.38%110.00%
eric w. biedermaneric w. biederman21.54%110.00%
arnaldo carvalho de meloarnaldo carvalho de melo10.77%110.00%
Total130100.00%10100.00%


static int netlink_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) { /* try to hand this ioctl down to the NIC drivers. */ return -ENOIOCTLCMD; }

Contributors

PersonTokensPropCommitsCommitProp
david decotignydavid decotigny24100.00%1100.00%
Total24100.00%1100.00%


static struct sock *netlink_getsockbyportid(struct sock *ssk, u32 portid) { struct sock *sock; struct netlink_sock *nlk; sock = netlink_lookup(sock_net(ssk), ssk->sk_protocol, portid); if (!sock) return ERR_PTR(-ECONNREFUSED); /* Don't bother queuing skb if kernel socket has no input function */ nlk = nlk_sk(sock); if (sock->sk_state == NETLINK_CONNECTED && nlk->dst_portid != nlk_sk(ssk)->portid) { sock_put(sock); return ERR_PTR(-ECONNREFUSED); } return sock; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton3434.69%17.69%
pre-gitpre-git2121.43%323.08%
herbert xuherbert xu1414.29%17.69%
david s. millerdavid s. miller1010.20%17.69%
eric w. biedermaneric w. biederman77.14%215.38%
denis v. lunevdenis v. lunev44.08%17.69%
hideaki yoshifujihideaki yoshifuji33.06%17.69%
james morrisjames morris33.06%17.69%
arnaldo carvalho de meloarnaldo carvalho de melo11.02%17.69%
adrian bunkadrian bunk11.02%17.69%
Total98100.00%13100.00%


struct sock *netlink_getsockbyfilp(struct file *filp) { struct inode *inode = file_inode(filp); struct sock *sock; if (!S_ISSOCK(inode->i_mode)) return ERR_PTR(-ENOTSOCK); sock = SOCKET_I(inode)->sk; if (sock->sk_family != AF_NETLINK) return ERR_PTR(-EINVAL); sock_hold(sock); return sock; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton5673.68%116.67%
pre-gitpre-git1013.16%350.00%
matthew wilcoxmatthew wilcox79.21%116.67%
al viroal viro33.95%116.67%
Total76100.00%6100.00%


static struct sk_buff *netlink_alloc_large_skb(unsigned int size, int broadcast) { struct sk_buff *skb; void *data; if (size <= NLMSG_GOODSIZE || broadcast) return alloc_skb(size, GFP_KERNEL); size = SKB_DATA_ALIGN(size) + SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); data = vmalloc(size); if (data == NULL) return NULL; skb = __build_skb(data, size); if (skb == NULL) vfree(data); else skb->destructor = netlink_skb_destructor; return skb; }

Contributors

PersonTokensPropCommitsCommitProp
pablo neira ayusopablo neira ayuso10199.02%266.67%
eric dumazeteric dumazet10.98%133.33%
Total102100.00%3100.00%

/* * Attach a skb to a netlink socket. * The caller must hold a reference to the destination socket. On error, the * reference is dropped. The skb is not send to the destination, just all * all error checks are performed and memory in the queue is reserved. * Return values: * < 0: error. skb freed, reference to sock dropped. * 0: continue * 1: repeat lookup - reference dropped while waiting for socket memory. */
int netlink_attachskb(struct sock *sk, struct sk_buff *skb, long *timeo, struct sock *ssk) { struct netlink_sock *nlk; nlk = nlk_sk(sk); if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || test_bit(NETLINK_S_CONGESTED, &nlk->state))) { DECLARE_WAITQUEUE(wait, current); if (!*timeo) { if (!ssk || netlink_is_kernel(ssk)) netlink_overrun(sk); sock_put(sk); kfree_skb(skb); return -EAGAIN; } __set_current_state(TASK_INTERRUPTIBLE); add_wait_queue(&nlk->wait, &wait); if ((atomic_read(&sk->sk_rmem_alloc) > sk->sk_rcvbuf || test_bit(NETLINK_S_CONGESTED, &nlk->state)) && !sock_flag(sk, SOCK_DEAD)) *timeo = schedule_timeout(*timeo); __set_current_state(TASK_RUNNING); remove_wait_queue(&nlk->wait, &wait); sock_put(sk); if (signal_pending(current)) { kfree_skb(skb); return sock_intr_errno(*timeo); } return 1; } netlink_skb_set_owner_r(skb, sk); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git14866.67%736.84%
andrew mortonandrew morton3817.12%15.26%
alexey kuznetsovalexey kuznetsov104.50%15.26%
patrick mchardypatrick mchardy83.60%315.79%
arnaldo carvalho de meloarnaldo carvalho de melo83.60%315.79%
david s. millerdavid s. miller52.25%15.26%
james morrisjames morris20.90%15.26%
nicolas dichtelnicolas dichtel20.90%15.26%
denis v. lunevdenis v. lunev10.45%15.26%
Total222100.00%19100.00%


static int __netlink_sendskb(struct sock *sk, struct sk_buff *skb) { int len = skb->len; netlink_deliver_tap(skb); skb_queue_tail(&sk->sk_receive_queue, skb); sk->sk_data_ready(sk); return len; }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton2041.67%120.00%
pre-gitpre-git1531.25%120.00%
eric dumazeteric dumazet612.50%120.00%
daniel borkmanndaniel borkmann510.42%120.00%
arnaldo carvalho de meloarnaldo carvalho de melo24.17%120.00%
Total48100.00%5100.00%


int netlink_sendskb(struct sock *sk, struct sk_buff *skb) { int len = __netlink_sendskb(sk, skb); sock_put(sk); return len; }

Contributors

PersonTokensPropCommitsCommitProp
eric dumazeteric dumazet2472.73%125.00%
pre-gitpre-git824.24%250.00%
andrew mortonandrew morton13.03%125.00%
Total33100.00%4100.00%


void netlink_detachskb(struct sock *sk, struct sk_buff *skb) { kfree_skb(skb); sock_put(sk); }

Contributors

PersonTokensPropCommitsCommitProp
andrew mortonandrew morton25100.00%1100.00%
Total25100.00%1100.00%


static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation) { int delta; WARN_ON(skb->sk != NULL); delta = skb->end - skb->tail; if (is_vmalloc_addr(skb->head) || delta * 2 < skb->truesize) return skb; if (skb_shared(skb)) { struct sk_buff *nskb = skb_clone(skb, allocation); if (!nskb) return skb; consume_skb(skb); skb = nskb; } if (!pskb_expand_head(skb, 0, -delta, allocation)) skb->truesize -= delta; return skb; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu10385.83%333.33%
pablo neira ayusopablo neira ayuso75.83%111.11%
patrick mchardypatrick mchardy54.17%111.11%
arnaldo carvalho de meloarnaldo carvalho de melo21.67%111.11%
eric dumazeteric dumazet10.83%111.11%
david s. millerdavid s. miller10.83%111.11%
al viroal viro10.83%111.11%
Total120100.00%9100.00%


static int netlink_unicast_kernel(struct sock *sk, struct sk_buff *skb, struct sock *ssk) { int ret; struct netlink_sock *nlk = nlk_sk(sk); ret = -ECONNREFUSED; if (nlk->netlink_rcv != NULL) { ret = skb->len; netlink_skb_set_owner_r(skb, sk); NETLINK_CB(skb).sk = ssk; netlink_deliver_tap_kernel(sk, ssk, skb); nlk->netlink_rcv(skb); consume_skb(skb); } else { kfree_skb(skb); } sock_put(sk); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy4541.67%120.00%
denis v. lunevdenis v. lunev3734.26%120.00%
florian westphalflorian westphal1614.81%120.00%
eric dumazeteric dumazet54.63%120.00%
eric w. biedermaneric w. biederman54.63%120.00%
Total108100.00%5100.00%


int netlink_unicast(struct sock *ssk, struct sk_buff *skb, u32 portid, int nonblock) { struct sock *sk; int err; long timeo; skb = netlink_trim(skb, gfp_any()); timeo = sock_sndtimeo(ssk, nonblock); retry: sk = netlink_getsockbyportid(ssk, portid); if (IS_ERR(sk)) { kfree_skb(skb); return PTR_ERR(sk); } if (netlink_is_kernel(sk)) return netlink_unicast_kernel(sk, skb, ssk); if (sk_filter(sk, skb)) { err = skb->len; kfree_skb(skb); sock_put(sk); return err; } err = netlink_attachskb(sk, skb, &timeo, ssk); if (err == 1) goto retry; if (err) return err; return netlink_sendskb(sk, skb); }

Contributors

PersonTokensPropCommitsCommitProp
florian westphalflorian westphal9456.29%111.11%
andrew mortonandrew morton2816.77%111.11%
patrick mchardypatrick mchardy2615.57%222.22%
stephen hemmingerstephen hemminger116.59%111.11%
denis v. lunevdenis v. lunev31.80%111.11%
herbert xuherbert xu31.80%222.22%
daniel borkmanndaniel borkmann21.20%111.11%
Total167100.00%9100.00%

EXPORT_SYMBOL(netlink_unicast);
int netlink_has_listeners(struct sock *sk, unsigned int group) { int res = 0; struct listeners *listeners; BUG_ON(!netlink_is_kernel(sk)); rcu_read_lock(); listeners = rcu_dereference(nl_table[sk->sk_protocol].listeners); if (listeners && group - 1 < nl_table[sk->sk_protocol].groups) res = test_bit(group - 1, listeners->masks); rcu_read_unlock(); return res; }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy5665.12%120.00%
johannes bergjohannes berg2326.74%120.00%
eric dumazeteric dumazet66.98%240.00%
denis v. lunevdenis v. lunev11.16%120.00%
Total86100.00%5100.00%

EXPORT_SYMBOL_GPL(netlink_has_listeners);
static int netlink_broadcast_deliver(struct sock *sk, struct sk_buff *skb) { struct netlink_sock *nlk = nlk_sk(sk); if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf && !test_bit(NETLINK_S_CONGESTED, &nlk->state)) { netlink_skb_set_owner_r(skb, sk); __netlink_sendskb(sk, skb); return atomic_read(&sk->sk_rmem_alloc) > (sk->sk_rcvbuf >> 1); } return -1; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git5764.77%220.00%
herbert xuherbert xu1112.50%110.00%
david s. millerdavid s. miller1011.36%110.00%
stephen hemmingerstephen hemminger44.55%110.00%
arnaldo carvalho de meloarnaldo carvalho de melo33.41%220.00%
nicolas dichtelnicolas dichtel11.14%110.00%
eric dumazeteric dumazet11.14%110.00%
patrick mchardypatrick mchardy11.14%110.00%
Total88100.00%10100.00%

struct netlink_broadcast_data { struct sock *exclude_sk; struct net *net; u32 portid; u32 group; int failure; int delivery_failure; int congested; int delivered; gfp_t allocation; struct sk_buff *skb, *skb2; int (*tx_filter)(struct sock *dsk, struct sk_buff *skb, void *data); void *tx_data; };
static void do_one_broadcast(struct sock *sk, struct netlink_broadcast_data *p) { struct netlink_sock *nlk = nlk_sk(sk); int val; if (p->exclude_sk == sk) return; if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups || !test_bit(p->group - 1, nlk->groups)) return; if (!net_eq(sock_net(sk), p->net)) { if (!(nlk->flags & NETLINK_F_LISTEN_ALL_NSID)) return; if (!peernet_has_id(sock_net(sk), p->net)) return; if (!file_ns_capable(sk->sk_socket->file, p->net->user_ns, CAP_NET_BROADCAST)) return; } if (p->failure) { netlink_overrun(sk); return; } sock_hold(sk); if (p->skb2 == NULL) { if (skb_shared(p->skb)) { p->skb2 = skb_clone(p->skb, p->allocation); } else { p->skb2 = skb_get(p->skb); /* * skb ownership may have been set when * delivered to a previous socket. */ skb_orphan(p->skb2); } } if (p->skb2 == NULL) { netlink_overrun(sk); /* Clone failed. Notify ALL listeners. */ p->failure = 1; if (nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR) p->delivery_failure = 1; goto out; } if (p->tx_filter && p->tx_filter(sk, p->skb2, p->tx_data)) { kfree_skb(p->skb2); p->skb2 = NULL; goto out; } if (sk_filter(sk, p->skb2)) { kfree_skb(p->skb2); p->skb2 = NULL; goto out; } NETLINK_CB(p->skb2).nsid = peernet2id(sock_net(sk), p->net); NETLINK_CB(p->skb2).nsid_is_set = true; val = netlink_broadcast_deliver(sk, p->skb2); if (val < 0) { netlink_overrun(sk); if (nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR) p->delivery_failure = 1; } else { p->congested |= val; p->delivered = 1; p->skb2 = NULL; } out: sock_put(sk); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git10524.94%29.09%
nicolas dichtelnicolas dichtel9923.52%29.09%
herbert xuherbert xu6114.49%29.09%
eric w. biedermaneric w. biederman4510.69%313.64%
pablo neira ayusopablo neira ayuso266.18%29.09%
stephen hemmingerstephen hemminger245.70%14.55%
david s. millerdavid s. miller225.23%313.64%
patrick mchardypatrick mchardy184.28%29.09%
hideaki yoshifujihideaki yoshifuji81.90%29.09%
tommy s. christensentommy s. christensen71.66%14.55%
rami rosenrami rosen51.19%14.55%
arnaldo carvalho de meloarnaldo carvalho de melo10.24%14.55%
Total421100.00%22100.00%


int netlink_broadcast_filtered(struct sock *ssk, struct sk_buff *skb, u32 portid, u32 group, gfp_t allocation, int (*filter)(struct sock *dsk, struct sk_buff *skb, void *data), void *filter_data) { struct net *net = sock_net(ssk); struct netlink_broadcast_data info; struct sock *sk; skb = netlink_trim(skb, allocation); info.exclude_sk = ssk; info.net = net; info.portid = portid; info.group = group; info.failure = 0; info.delivery_failure = 0; info.congested = 0; info.delivered = 0; info.allocation = allocation; info.skb = skb; info.skb2 = NULL; info.tx_filter = filter; info.tx_data = filter_data; /* While we sleep in clone, do not allow to change socket list */ netlink_lock_table(); sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list) do_one_broadcast(sk, &info); consume_skb(skb); netlink_unlock_table(); if (info.delivery_failure) { kfree_skb(info.skb2); return -ENOBUFS; } consume_skb(info.skb2); if (info.delivered) { if (info.congested && gfpflags_allow_blocking(allocation)) yield(); return 0; } return -ESRCH; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu12854.24%318.75%
eric w. biedermaneric w. biederman5422.88%318.75%
neil hormanneil horman166.78%16.25%
pablo neira ayusopablo neira ayuso145.93%16.25%
pre-gitpre-git83.39%318.75%
david s. millerdavid s. miller52.12%16.25%
tommy s. christensentommy s. christensen41.69%16.25%
hideaki yoshifujihideaki yoshifuji31.27%16.25%
mel gormanmel gorman31.27%16.25%
al viroal viro10.42%16.25%
Total236100.00%16100.00%

EXPORT_SYMBOL(netlink_broadcast_filtered);
int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 portid, u32 group, gfp_t allocation) { return netlink_broadcast_filtered(ssk, skb, portid, group, allocation, NULL, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman42100.00%2100.00%
Total42100.00%2100.00%

EXPORT_SYMBOL(netlink_broadcast); struct netlink_set_err_data { struct sock *exclude_sk; u32 portid; u32 group; int code; };
static int do_one_set_err(struct sock *sk, struct netlink_set_err_data *p) { struct netlink_sock *nlk = nlk_sk(sk); int ret = 0; if (sk == p->exclude_sk) goto out; if (!net_eq(sock_net(sk), sock_net(p->exclude_sk))) goto out; if (nlk->portid == p->portid || p->group - 1 >= nlk->ngroups || !test_bit(p->group - 1, nlk->groups)) goto out; if (p->code == ENOBUFS && nlk->flags & NETLINK_F_RECV_NO_ENOBUFS) { ret = 1; goto out; } sk->sk_err = p->code; sk->sk_error_report(sk); out: return ret; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu7250.35%110.00%
pablo neira ayusopablo neira ayuso2819.58%110.00%
patrick mchardypatrick mchardy1812.59%220.00%
eric w. biedermaneric w. biederman128.39%220.00%
hideaki yoshifujihideaki yoshifuji64.20%110.00%
octavian purdilaoctavian purdila53.50%110.00%
arnaldo carvalho de meloarnaldo carvalho de melo10.70%110.00%
nicolas dichtelnicolas dichtel10.70%110.00%
Total143100.00%10100.00%

/** * netlink_set_err - report error to broadcast listeners * @ssk: the kernel netlink socket, as returned by netlink_kernel_create() * @portid: the PORTID of a process that we want to skip (if any) * @group: the broadcast group that will notice the error * @code: error code, must be negative (as usual in kernelspace) * * This function returns the number of broadcast listeners that have set the * NETLINK_NO_ENOBUFS socket option. */
int netlink_set_err(struct sock *ssk, u32 portid, u32 group, int code) { struct netlink_set_err_data info; struct sock *sk; int ret = 0; info.exclude_sk = ssk; info.portid = portid; info.group = group; /* sk->sk_err wants a positive error value */ info.code = -code; read_lock(&nl_table_lock); sk_for_each_bound(sk, &nl_table[ssk->sk_protocol].mc_list) ret += do_one_set_err(sk, &info); read_unlock(&nl_table_lock); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git3538.89%333.33%
herbert xuherbert xu3235.56%111.11%
pablo neira ayusopablo neira ayuso1314.44%222.22%
arnaldo carvalho de meloarnaldo carvalho de melo55.56%111.11%
eric w. biedermaneric w. biederman33.33%111.11%
david s. millerdavid s. miller22.22%111.11%
Total90100.00%9100.00%

EXPORT_SYMBOL(netlink_set_err); /* must be called with netlink table grabbed */
static void netlink_update_socket_mc(struct netlink_sock *nlk, unsigned int group, int is_new) { int old, new = !!is_new, subscriptions; old = test_bit(group - 1, nlk->groups); subscriptions = nlk->subscriptions - old + new; if (new) __set_bit(group - 1, nlk->groups); else __clear_bit(group - 1, nlk->groups); netlink_update_subscriptions(&nlk->sk, subscriptions); netlink_update_listeners(&nlk->sk); }

Contributors

PersonTokensPropCommitsCommitProp
johannes bergjohannes berg97100.00%1100.00%
Total97100.00%1100.00%


static int netlink_setsockopt(struct socket *sock, int level, int optname, char __user *optval, unsigned int optlen) { struct sock *sk = sock->sk; struct netlink_sock *nlk = nlk_sk(sk); unsigned int val = 0; int err; if (level != SOL_NETLINK) return -ENOPROTOOPT; if (optlen >= sizeof(int) && get_user(val, (unsigned int __user *)optval)) return -EFAULT; switch (optname) { case NETLINK_PKTINFO: if (val) nlk->flags |= NETLINK_F_RECV_PKTINFO; else nlk->flags &= ~NETLINK_F_RECV_PKTINFO; err = 0; break; case NETLINK_ADD_MEMBERSHIP: case NETLINK_DROP_MEMBERSHIP: { if (!netlink_allowed(sock, NL_CFG_F_NONROOT_RECV)) return -EPERM; err = netlink_realloc_groups(sk); if (err) return err; if (!val || val - 1 >= nlk->ngroups) return -EINVAL; if (optname == NETLINK_ADD_MEMBERSHIP && nlk->netlink_bind) { err = nlk->netlink_bind(sock_net(sk), val); if (err) return err; } netlink_table_grab(); netlink_update_socket_mc(nlk, val, optname == NETLINK_ADD_MEMBERSHIP); netlink_table_ungrab(); if (optname == NETLINK_DROP_MEMBERSHIP && nlk->netlink_unbind) nlk->netlink_unbind(sock_net(sk), val); err = 0; break; } case NETLINK_BROADCAST_ERROR: if (val) nlk->flags |= NETLINK_F_BROADCAST_SEND_ERROR; else nlk->flags &= ~NETLINK_F_BROADCAST_SEND_ERROR; err = 0; break; case NETLINK_NO_ENOBUFS: if (val) { nlk->flags |= NETLINK_F_RECV_NO_ENOBUFS; clear_bit(NETLINK_S_CONGESTED, &nlk->state); wake_up_interruptible(&nlk->wait); } else { nlk->flags &= ~NETLINK_F_RECV_NO_ENOBUFS; } err = 0; break; case NETLINK_LISTEN_ALL_NSID: if (!ns_capable(sock_net(sk)->user_ns, CAP_NET_BROADCAST)) return -EPERM; if (val) nlk->flags |= NETLINK_F_LISTEN_ALL_NSID; else nlk->flags &= ~NETLINK_F_LISTEN_ALL_NSID; err = 0; break; case NETLINK_CAP_ACK: if (val) nlk->flags |= NETLINK_F_CAP_ACK; else nlk->flags &= ~NETLINK_F_CAP_ACK; err = 0; break; default: err = -ENOPROTOOPT; } return err; }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy19247.29%316.67%
pablo neira ayusopablo neira ayuso6816.75%316.67%
nicolas dichtelnicolas dichtel5212.81%211.11%
richard guy briggsrichard guy briggs4511.08%211.11%
christophe ricardchristophe ricard266.40%15.56%
johannes bergjohannes berg194.68%422.22%
eric dumazeteric dumazet20.49%15.56%
david s. millerdavid s. miller10.25%15.56%
eric w. biedermaneric w. biederman10.25%15.56%
Total406100.00%18100.00%


static int netlink_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen) { struct sock *sk = sock->sk; struct netlink_sock *nlk = nlk_sk(sk); int len, val, err; if (level != SOL_NETLINK) return -ENOPROTOOPT; if (get_user(len, optlen)) return -EFAULT; if (len < 0) return -EINVAL; switch (optname) { case NETLINK_PKTINFO: if (len < sizeof(int)) return -EINVAL; len = sizeof(int); val = nlk->flags & NETLINK_F_RECV_PKTINFO ? 1 : 0; if (put_user(len, optlen) || put_user(val, optval)) return -EFAULT; err = 0; break; case NETLINK_BROADCAST_ERROR: if (len < sizeof(int)) return -EINVAL; len = sizeof(int); val = nlk->flags & NETLINK_F_BROADCAST_SEND_ERROR ? 1 : 0; if (put_user(len, optlen) || put_user(val, optval)) return -EFAULT; err = 0; break; case NETLINK_NO_ENOBUFS: if (len < sizeof(int)) return -EINVAL; len = sizeof(int); val = nlk->flags & NETLINK_F_RECV_NO_ENOBUFS ? 1 : 0; if (put_user(len, optlen) || put_user(val, optval)) return -EFAULT; err = 0; break; case NETLINK_LIST_MEMBERSHIPS: { int pos, idx, shift; err = 0; netlink_lock_table(); for (pos = 0; pos * 8 < nlk->ngroups; pos += sizeof(u32)) { if (len - pos < sizeof(u32)) break; idx = pos / sizeof(unsigned long); shift = (pos % sizeof(unsigned long)) * 8; if (put_user((u32)(nlk->groups[idx] >> shift), (u32 __user *)(optval + pos))) { err = -EFAULT; break; } } if (put_user(ALIGN(nlk->ngroups / 8, sizeof(u32)), optlen)) err = -EFAULT; netlink_unlock_table(); break; } case NETLINK_CAP_ACK: if (len < sizeof(int)) return -EINVAL; len = sizeof(int); val = nlk->flags & NETLINK_F_CAP_ACK ? 1 : 0; if (put_user(len, optlen) || put_user(val, optval)) return -EFAULT; err = 0; break; default: err = -ENOPROTOOPT; } return err; }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy15231.21%112.50%
david herrmanndavid herrmann14629.98%225.00%
pablo neira ayusopablo neira ayuso11824.23%225.00%
christophe ricardchristophe ricard6012.32%112.50%
heiko carstensheiko carstens81.64%112.50%
nicolas dichtelnicolas dichtel30.62%112.50%
Total487100.00%8100.00%


static void netlink_cmsg_recv_pktinfo(struct msghdr *msg, struct sk_buff *skb) { struct nl_pktinfo info; info.group = NETLINK_CB(skb).dst_group; put_cmsg(msg, SOL_NETLINK, NETLINK_PKTINFO, sizeof(info), &info); }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy48100.00%1100.00%
Total48100.00%1100.00%


static void netlink_cmsg_listen_all_nsid(struct sock *sk, struct msghdr *msg, struct sk_buff *skb) { if (!NETLINK_CB(skb).nsid_is_set) return; put_cmsg(msg, SOL_NETLINK, NETLINK_LISTEN_ALL_NSID, sizeof(int), &NETLINK_CB(skb).nsid); }

Contributors

PersonTokensPropCommitsCommitProp
nicolas dichtelnicolas dichtel54100.00%1100.00%
Total54100.00%1100.00%


static int netlink_sendmsg(struct socket *sock, struct msghdr *msg, size_t len) { struct sock *sk = sock->sk; struct netlink_sock *nlk = nlk_sk(sk); DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name); u32 dst_portid; u32 dst_group; struct sk_buff *skb; int err; struct scm_cookie scm; u32 netlink_skb_flags = 0; if (msg->msg_flags&MSG_OOB) return -EOPNOTSUPP; err = scm_send(sock, msg, &scm, true); if (err < 0) return err; if (msg->msg_namelen) { err = -EINVAL; if (addr->nl_family != AF_NETLINK) goto out; dst_portid = addr->nl_pid; dst_group = ffs(addr->nl_groups); err = -EPERM; if ((dst_group || dst_portid) && !netlink_allowed(sock, NL_CFG_F_NONROOT_SEND)) goto out; netlink_skb_flags |= NETLINK_SKB_DST; } else { dst_portid = nlk->dst_portid; dst_group = nlk->dst_group; } if (!nlk->bound) { err = netlink_autobind(sock); if (err) goto out; } else { /* Ensure nlk is hashed and visible. */ smp_rmb(); } err = -EMSGSIZE; if (len > sk->sk_sndbuf - 32) goto out; err = -ENOBUFS; skb = netlink_alloc_large_skb(len, dst_group); if (skb == NULL) goto out; NETLINK_CB(skb).portid = nlk->portid; NETLINK_CB(skb).dst_group = dst_group; NETLINK_CB(skb).creds = scm.creds; NETLINK_CB(skb).flags = netlink_skb_flags; err = -EFAULT; if (memcpy_from_msg(skb_put(skb, len), msg, len)) { kfree_skb(skb); goto out; } err = security_netlink_send(sk, skb); if (err) { kfree_skb(skb); goto out; } if (dst_group) { atomic_inc(&skb->users); netlink_broadcast(sk, skb, dst_portid, dst_group, GFP_KERNEL); } err = netlink_unicast(sk, skb, dst_portid, msg->msg_flags&MSG_DONTWAIT); out: scm_destroy(&scm); return err; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git24960.58%414.29%
eric w. biedermaneric w. biederman5312.90%517.86%
james morrisjames morris276.57%414.29%
benjamin lahaisebenjamin lahaise266.33%13.57%
patrick mchardypatrick mchardy122.92%13.57%
david s. millerdavid s. miller122.92%13.57%
steffen hurrlesteffen hurrle81.95%13.57%
herbert xuherbert xu81.95%13.57%
pablo neira ayusopablo neira ayuso71.70%414.29%
christoph hellwigchristoph hellwig30.73%13.57%
eric dumazeteric dumazet20.49%13.57%
arnaldo carvalho de meloarnaldo carvalho de melo20.49%27.14%
stephen hemmingerstephen hemminger10.24%13.57%
al viroal viro10.24%13.57%
Total411100.00%28100.00%


static int netlink_recvmsg(struct socket *sock, struct msghdr *msg, size_t len, int flags) { struct scm_cookie scm; struct sock *sk = sock->sk; struct netlink_sock *nlk = nlk_sk(sk); int noblock = flags&MSG_DONTWAIT; size_t copied; struct sk_buff *skb, *data_skb; int err, ret; if (flags&MSG_OOB) return -EOPNOTSUPP; copied = 0; skb = skb_recv_datagram(sk, flags, noblock, &err); if (skb == NULL) goto out; data_skb = skb; #ifdef CONFIG_COMPAT_NETLINK_MESSAGES if (unlikely(skb_shinfo(skb)->frag_list)) { /* * If this skb has a frag_list, then here that means that we * will have to use the frag_list skb's data for compat tasks * and the regular skb's data for normal (non-compat) tasks. * * If we need to send the compat skb, assign it to the * 'data_skb' variable so that it will be used below for data * copying. We keep 'skb' for everything else, including * freeing both later. */ if (flags & MSG_CMSG_COMPAT) data_skb = skb_shinfo(skb)->frag_list; } #endif /* Record the max length of recvmsg() calls for future allocations */ nlk->max_recvmsg_len = max(nlk->max_recvmsg_len, len); nlk->max_recvmsg_len = min_t(size_t, nlk->max_recvmsg_len, 16384); copied = data_skb->len; if (len < copied) { msg->msg_flags |= MSG_TRUNC; copied = len; } skb_reset_transport_header(data_skb); err = skb_copy_datagram_msg(data_skb, 0, msg, copied); if (msg->msg_name) { DECLARE_SOCKADDR(struct sockaddr_nl *, addr, msg->msg_name); addr->nl_family = AF_NETLINK; addr->nl_pad = 0; addr->nl_pid = NETLINK_CB(skb).portid; addr->nl_groups = netlink_group_mask(NETLINK_CB(skb).dst_group); msg->msg_namelen = sizeof(*addr); } if (nlk->flags & NETLINK_F_RECV_PKTINFO) netlink_cmsg_recv_pktinfo(msg, skb); if (nlk->flags & NETLINK_F_LISTEN_ALL_NSID) netlink_cmsg_listen_all_nsid(sk, msg, skb); memset(&scm, 0, sizeof(scm)); scm.creds = *NETLINK_CREDS(skb); if (flags & MSG_TRUNC) copied = data_skb->len; skb_free_datagram(sk, skb); if (nlk->cb_running && atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf / 2) { ret = netlink_dump(sk); if (ret) { sk->sk_err = -ret; sk->sk_error_report(sk); } } scm_recv(sock, msg, &scm, flags); out: netlink_rcv_wake(sk); return err ? : copied; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git21750.35%27.69%
johannes bergjohannes berg4410.21%27.69%
benjamin lahaisebenjamin lahaise317.19%13.85%
eric dumazeteric dumazet296.73%13.85%
patrick mchardypatrick mchardy276.26%311.54%
andrey vaginandrey vagin255.80%13.85%
david s. millerdavid s. miller194.41%415.38%
nicolas dichtelnicolas dichtel184.18%27.69%
steffen hurrlesteffen hurrle71.62%13.85%
arnaldo carvalho de meloarnaldo carvalho de melo61.39%311.54%
stephen hemmingerstephen hemminger20.46%13.85%
christoph hellwigchristoph hellwig20.46%13.85%
ben pfaffben pfaff10.23%13.85%
pravin b shelarpravin b shelar10.23%13.85%
eric w. biedermaneric w. biederman10.23%13.85%
james morrisjames morris10.23%13.85%
Total431100.00%26100.00%


static void netlink_data_ready(struct sock *sk) { BUG(); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git1178.57%250.00%
denis v. lunevdenis v. lunev214.29%125.00%
stephen hemmingerstephen hemminger17.14%125.00%
Total14100.00%4100.00%

/* * We export these functions to other modules. They provide a * complete set of kernel non-blocking support for message * queueing. */
struct sock * __netlink_kernel_create(struct net *net, int unit, struct module *module, struct netlink_kernel_cfg *cfg) { struct socket *sock; struct sock *sk; struct netlink_sock *nlk; struct listeners *listeners = NULL; struct mutex *cb_mutex = cfg ? cfg->cb_mutex : NULL; unsigned int groups; BUG_ON(!nl_table); if (unit < 0 || unit >= MAX_LINKS) return NULL; if (sock_create_lite(PF_NETLINK, SOCK_DGRAM, unit, &sock)) return NULL; if (__netlink_create(net, sock, cb_mutex, unit, 1) < 0) goto out_sock_release_nosk; sk = sock->sk; if (!cfg || cfg->groups < 32) groups = 32; else groups = cfg->groups; listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL); if (!listeners) goto out_sock_release; sk->sk_data_ready = netlink_data_ready; if (cfg && cfg->input) nlk_sk(sk)->netlink_rcv = cfg->input; if (netlink_insert(sk, 0)) goto out_sock_release; nlk = nlk_sk(sk); nlk->flags |= NETLINK_F_KERNEL_SOCKET; netlink_table_grab(); if (!nl_table[unit].registered) { nl_table[unit].groups = groups; rcu_assign_pointer(nl_table[unit].listeners, listeners); nl_table[unit].cb_mutex = cb_mutex; nl_table[unit].module = module; if (cfg) { nl_table[unit].bind = cfg->bind; nl_table[unit].unbind = cfg->unbind; nl_table[unit].flags = cfg->flags; if (cfg->compare) nl_table[unit].compare = cfg->compare; } nl_table[unit].registered = 1; } else { kfree(listeners); nl_table[unit].registered++; } netlink_table_ungrab(); return sk; out_sock_release: kfree(listeners); netlink_kernel_release(sk); return NULL; out_sock_release_nosk: sock_release(sock); return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
patrick mchardypatrick mchardy10226.15%618.18%
pre-gitpre-git7218.46%26.06%
pablo neira ayusopablo neira ayuso6817.44%412.12%
eric w. biedermaneric w. biederman215.38%412.12%
harald welteharald welte215.38%13.03%
gao fenggao feng174.36%13.03%
pavel emelianovpavel emelianov164.10%13.03%
herbert xuherbert xu112.82%26.06%
eric dumazeteric dumazet112.82%13.03%
hiroaki shimodahiroaki shimoda112.82%13.03%
james morrisjames morris102.56%13.03%
denis v. lunevdenis v. lunev102.56%39.09%
jesper juhljesper juhl82.05%13.03%
akinobu mitaakinobu mita41.03%13.03%
johannes bergjohannes berg30.77%13.03%
david s. millerdavid s. miller30.77%13.03%
arnaldo carvalho de meloarnaldo carvalho de melo10.26%13.03%
nicolas dichtelnicolas dichtel10.26%13.03%
Total390100.00%33100.00%

EXPORT_SYMBOL(__netlink_kernel_create);
void netlink_kernel_release(struct sock *sk) { if (sk == NULL || sk->sk_socket == NULL) return; sock_release(sk->sk_socket); }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman1653.33%133.33%
denis v. lunevdenis v. lunev1446.67%266.67%
Total30100.00%3100.00%

EXPORT_SYMBOL(netlink_kernel_release);
int __netlink_change_ngroups(struct sock *sk, unsigned int groups) { struct listeners *new, *old; struct netlink_table *tbl = &nl_table[sk->sk_protocol]; if (groups < 32) groups = 32; if (NLGRPSZ(tbl->groups) < NLGRPSZ(groups)) { new = kzalloc(sizeof(*new) + NLGRPSZ(groups), GFP_ATOMIC); if (!new) return -ENOMEM; old = nl_deref_protected(tbl->listeners); memcpy(new->masks, old->masks, NLGRPSZ(tbl->groups)); rcu_assign_pointer(tbl->listeners, new); kfree_rcu(old, rcu); } tbl->groups = groups; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
johannes bergjohannes berg11884.29%350.00%
eric dumazeteric dumazet2014.29%233.33%
lai jiangshanlai jiangshan21.43%116.67%
Total140100.00%6100.00%

/** * netlink_change_ngroups - change number of multicast groups * * This changes the number of multicast groups that are available * on a certain netlink family. Note that it is not possible to * change the number of groups to below 32. Also note that it does * not implicitly call netlink_clear_multicast_users() when the * number of groups is reduced. * * @sk: The kernel netlink socket, as returned by netlink_kernel_create(). * @groups: The new number of groups. */
int netlink_change_ngroups(struct sock *sk, unsigned int groups) { int err; netlink_table_grab(); err = __netlink_change_ngroups(sk, groups); netlink_table_ungrab(); return err; }

Contributors

PersonTokensPropCommitsCommitProp
johannes bergjohannes berg35100.00%2100.00%
Total35100.00%2100.00%


void __netlink_clear_multicast_users(struct sock *ksk, unsigned int group) { struct sock *sk; struct netlink_table *tbl = &nl_table[ksk->sk_protocol]; sk_for_each_bound(sk, &tbl->mc_list) netlink_update_socket_mc(nlk_sk(sk), group, 0); }

Contributors

PersonTokensPropCommitsCommitProp
johannes bergjohannes berg50100.00%2100.00%
Total50100.00%2100.00%


struct nlmsghdr * __nlmsg_put(struct sk_buff *skb, u32 portid, u32 seq, int type, int len, int flags) { struct nlmsghdr *nlh; int size = nlmsg_msg_size(len); nlh = (struct nlmsghdr *)skb_put(skb, NLMSG_ALIGN(size)); nlh->nlmsg_type = type; nlh->nlmsg_len = size; nlh->nlmsg_flags = flags; nlh->nlmsg_pid = portid; nlh->nlmsg_seq = seq; if (!__builtin_constant_p(size) || NLMSG_ALIGN(size) - size != 0) memset(nlmsg_data(nlh) + len, 0, NLMSG_ALIGN(size) - size); return nlh; }

Contributors

PersonTokensPropCommitsCommitProp
denys vlasenkodenys vlasenko12296.83%133.33%
hong zhi guohong zhi guo21.59%133.33%
eric w. biedermaneric w. biederman21.59%133.33%
Total126100.00%3100.00%

EXPORT_SYMBOL(__nlmsg_put); /* * It looks a bit ugly. * It would be better to create kernel thread. */
static int netlink_dump(struct sock *sk) { struct netlink_sock *nlk = nlk_sk(sk); struct netlink_callback *cb; struct sk_buff *skb = NULL; struct nlmsghdr *nlh; struct module *module; int len, err = -ENOBUFS; int alloc_min_size; int alloc_size; mutex_lock(nlk->cb_mutex); if (!nlk->cb_running) { err = -EINVAL; goto errout_skb; } if (atomic_read(&sk->sk_rmem_alloc) >= sk->sk_rcvbuf) goto errout_skb; /* NLMSG_GOODSIZE is small to avoid high order allocations being * required, but it makes sense to _attempt_ a 16K bytes allocation * to reduce number of system calls on dump operations, if user * ever provided a big enough buffer. */ cb = &nlk->cb; alloc_min_size = max_t(int, cb->min_dump_alloc, NLMSG_GOODSIZE); if (alloc_min_size < nlk->max_recvmsg_len) { alloc_size = nlk->max_recvmsg_len; skb = alloc_skb(alloc_size, GFP_KERNEL | __GFP_NOWARN | __GFP_NORETRY); } if (!skb) { alloc_size = alloc_min_size; skb = alloc_skb(alloc_size, GFP_KERNEL); } if (!skb) goto errout_skb; /* Trim skb to allocated size. User is expected to provide buffer as * large as max(min_dump_alloc, 16KiB (mac_recvmsg_len capped at * netlink_recvmsg())). dump will pack as many smaller messages as * could fit within the allocated skb. skb is typically allocated * with larger space than required (could be as much as near 2x the * requested size with align to next power of 2 approach). Allowing * dump to use the excess space makes it difficult for a user to have a * reasonable static buffer based on the expected largest dump of a * single netdev. The outcome is MSG_TRUNC error. */ skb_reserve(skb, skb_tailroom(skb) - alloc_size); netlink_skb_set_owner_r(skb, sk); len = cb->dump(skb, cb); if (len > 0) { mutex_unlock(nlk->cb_mutex); if (sk_filter(sk, skb)) kfree_skb(skb); else __netlink_sendskb(sk, skb); return 0; } nlh = nlmsg_put_answer(skb, cb, NLMSG_DONE, sizeof(len), NLM_F_MULTI); if (!nlh) goto errout_skb; nl_dump_check_consistent(cb, nlh); memcpy(nlmsg_data(nlh), &len, sizeof(len)); if (sk_filter(sk, skb)) kfree_skb(skb); else __netlink_sendskb(sk, skb); if (cb->done) cb->done(cb); nlk->cb_running = false; module = cb->module; skb = cb->skb; mutex_unlock(nlk->cb_mutex); module_put(module); consume_skb(skb); return 0; errout_skb: mutex_unlock(nlk->cb_mutex); kfree_skb(skb); return err; }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git12732.90%210.00%
ronen aradronen arad5012.95%15.00%
thomas grafthomas graf4511.66%315.00%
patrick mchardypatrick mchardy328.29%210.00%
stephen hemmingerstephen hemminger307.77%15.00%
eric dumazeteric dumazet287.25%210.00%
greg rosegreg rose205.18%15.00%
herbert xuherbert xu174.40%15.00%
david s. millerdavid s. miller133.37%15.00%
pravin b shelarpravin b shelar82.07%15.00%
johannes bergjohannes berg71.81%15.00%
gao fenggao feng51.30%15.00%
florian westphalflorian westphal20.52%15.00%
dan carpenterdan carpenter10.26%15.00%
arnaldo carvalho de meloarnaldo carvalho de melo10.26%15.00%
Total386100.00%20100.00%


int __netlink_dump_start(struct sock *ssk, struct sk_buff *skb, const struct nlmsghdr *nlh, struct netlink_dump_control *control) { struct netlink_callback *cb; struct sock *sk; struct netlink_sock *nlk; int ret; atomic_inc(&skb->users); sk = netlink_lookup(sock_net(ssk), ssk->sk_protocol, NETLINK_CB(skb).portid); if (sk == NULL) { ret = -ECONNREFUSED; goto error_free; } nlk = nlk_sk(sk); mutex_lock(nlk->cb_mutex); /* A dump is in progress... */ if (nlk->cb_running) { ret = -EBUSY; goto error_unlock; } /* add reference of module which cb->dump belongs to */ if (!try_module_get(control->module)) { ret = -EPROTONOSUPPORT; goto error_unlock; } cb = &nlk->cb; memset(cb, 0, sizeof(*cb)); cb->start = control->start; cb->dump = control->dump; cb->done = control->done; cb->nlh = nlh; cb->data = control->data; cb->module = control->module; cb->min_dump_alloc = control->min_dump_alloc; cb->skb = skb; nlk->cb_running = true; mutex_unlock(nlk->cb_mutex); if (cb->start) cb->start(cb); ret = netlink_dump(sk); sock_put(sk); if (ret) return ret; /* We successfully started a dump, by returning -EINTR we * signal not to send ACK even if it was requested. */ return -EINTR; error_unlock: sock_put(sk); mutex_unlock(nlk->cb_mutex); error_free: kfree_skb(skb); return ret; }

Contributors

PersonTokensPropCommitsCommitProp
pravin b shelarpravin b shelar10635.93%15.56%
pre-gitpre-git8328.14%211.11%
gao fenggao feng268.81%15.56%
tom herberttom herbert217.12%15.56%
david s. millerdavid s. miller155.08%15.56%
patrick mchardypatrick mchardy134.41%316.67%
andrey vaginandrey vagin124.07%15.56%
herbert xuherbert xu51.69%15.56%
eric w. biedermaneric w. biederman41.36%211.11%
denis v. lunevdenis v. lunev31.02%15.56%
hideaki yoshifujihideaki yoshifuji31.02%15.56%
arnaldo carvalho de meloarnaldo carvalho de melo20.68%211.11%
pablo neira ayusopablo neira ayuso20.68%15.56%
Total295100.00%18100.00%

EXPORT_SYMBOL(__netlink_dump_start);
void netlink_ack(struct sk_buff *in_skb, struct nlmsghdr *nlh, int err) { struct sk_buff *skb; struct nlmsghdr *rep; struct nlmsgerr *errmsg; size_t payload = sizeof(*errmsg); struct netlink_sock *nlk = nlk_sk(NETLINK_CB(in_skb).sk); /* Error messages get the original request appened, unless the user * requests to cap the error message. */ if (!(nlk->flags & NETLINK_F_CAP_ACK) && err) payload += nlmsg_len(nlh); skb = nlmsg_new(payload, GFP_KERNEL); if (!skb) { struct sock *sk; sk = netlink_lookup(sock_net(in_skb->sk), in_skb->sk->sk_protocol, NETLINK_CB(in_skb).portid); if (sk) { sk->sk_err = ENOBUFS; sk->sk_error_report(sk); sock_put(sk); } return; } rep = __nlmsg_put(skb, NETLINK_CB(in_skb).portid, nlh->nlmsg_seq, NLMSG_ERROR, payload, 0); errmsg = nlmsg_data(rep); errmsg->error = err; memcpy(&errmsg->msg, nlh, payload > sizeof(*errmsg) ? nlh->nlmsg_len : sizeof(*nlh)); netlink_unicast(in_skb->sk, skb, NETLINK_CB(in_skb).portid, MSG_DONTWAIT); }

Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git11850.86%216.67%
david s. millerdavid s. miller4720.26%18.33%
christophe ricardchristophe ricard3213.79%18.33%
thomas grafthomas graf229.48%325.00%
eric w. biedermaneric w. biederman83.45%216.67%
hideaki yoshifujihideaki yoshifuji31.29%18.33%
john fastabendjohn fastabend10.43%18.33%
florian westphalflorian westphal10.43%18.33%
Total232100.00%12100.00%

EXPORT_SYMBOL(netlink_ack);
int netlink_rcv_skb(struct sk_buff *skb, int (*cb)(struct sk_buff *, struct nlmsghdr *)) { struct nlmsghdr *nlh; int err; while (skb->len >= nlmsg_total_size(0)) { int msglen; nlh = nlmsg_hdr(skb); err = 0; if (nlh->nlmsg_len < NLMSG_HDRLEN || skb->len < nlh->nlmsg_len) return 0; /* Only requests are handled by the kernel */ if (!(nlh->nlmsg_flags & NLM_F_REQUEST)) goto ack; /* Skip control messages */ if (nlh->nlmsg_type < NLMSG_MIN_TYPE) goto ack; err = cb(skb, nlh); if (err == -EINTR) goto skip; ack: if (nlh->nlmsg_flags & NLM_F_ACK || err) netlink_ack(skb, nlh, err); skip: msglen = NLMSG_ALIGN(nlh->nlmsg_len); if (msglen > skb->len) msglen = skb->len; skb_pull(skb, msglen); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
thomas grafthomas graf14982.32%450.00%
denis v. lunevdenis v. lunev2312.71%225.00%
martin murraymartin murray63.31%112.50%
arnaldo carvalho de meloarnaldo carvalho de melo31.66%112.50%
Total181100.00%8100.00%

EXPORT_SYMBOL(netlink_rcv_skb); /** * nlmsg_notify - send a notification netlink message * @sk: netlink socket to use * @skb: notification message * @portid: destination netlink portid for reports or 0 * @group: destination multicast group or 0 * @report: 1 to report back, 0 to disable * @flags: allocation flags */
int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 portid, unsigned int group, int report, gfp_t flags) { int err = 0; if (group) { int exclude_portid = 0; if (report) { atomic_inc(&skb->users); exclude_portid = portid; } /* errors reported via destination sk->sk_err, but propagate * delivery errors if NETLINK_BROADCAST_ERROR flag is set */ err = nlmsg_multicast(sk, skb, exclude_portid, group, flags); } if (report) { int err2; err2 = nlmsg_unicast(sk, skb, portid); if (!err || err == -ESRCH) err = err2; } return err; }

Contributors

PersonTokensPropCommitsCommitProp
thomas grafthomas graf8674.78%133.33%
pablo neira ayusopablo neira ayuso2320.00%133.33%
eric w. biedermaneric w. biederman65.22%133.33%
Total115100.00%3100.00%

EXPORT_SYMBOL(nlmsg_notify); #ifdef CONFIG_PROC_FS struct nl_seq_iter { struct seq_net_private p; struct rhashtable_iter hti; int link; };
static int netlink_walk_start(struct nl_seq_iter *iter) { int err; err = rhashtable_walk_init(&nl_table[iter->link].hash, &iter->hti, GFP_KERNEL); if (err) { iter->link = MAX_LINKS; return err; } err = rhashtable_walk_start(&iter->hti); return err == -EAGAIN ? 0 : err; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu4867.61%233.33%
stephen hemmingerstephen hemminger1723.94%116.67%
bob copelandbob copeland22.82%116.67%
thomas grafthomas graf22.82%116.67%
pre-gitpre-git22.82%116.67%
Total71100.00%6100.00%


static void netlink_walk_stop(struct nl_seq_iter *iter) { rhashtable_walk_stop(&iter->hti); rhashtable_walk_exit(&iter->hti); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu1659.26%120.00%
stephen hemmingerstephen hemminger829.63%120.00%
thomas grafthomas graf13.70%120.00%
pre-gitpre-git13.70%120.00%
arnaldo carvalho de meloarnaldo carvalho de melo13.70%120.00%
Total27100.00%5100.00%


static void *__netlink_seq_next(struct seq_file *seq) { struct nl_seq_iter *iter = seq->private; struct netlink_sock *nlk; do { for (;;) { int err; nlk = rhashtable_walk_next(&iter->hti); if (IS_ERR(nlk)) { if (PTR_ERR(nlk) == -EAGAIN) continue; return nlk; } if (nlk) break; netlink_walk_stop(iter); if (++iter->link >= MAX_LINKS) return NULL; err = netlink_walk_start(iter); if (err) return ERR_PTR(err); } } while (sock_net(&nlk->sk) != seq_file_net(seq)); return nlk; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu9069.23%222.22%
stephen hemmingerstephen hemminger1612.31%111.11%
thomas grafthomas graf1410.77%333.33%
gao fenggao feng53.85%111.11%
eric w. biedermaneric w. biederman32.31%111.11%
hideaki yoshifujihideaki yoshifuji21.54%111.11%
Total130100.00%9100.00%


static void *netlink_seq_start(struct seq_file *seq, loff_t *posp) { struct nl_seq_iter *iter = seq->private; void *obj = SEQ_START_TOKEN; loff_t pos; int err; iter->link = 0; err = netlink_walk_start(iter); if (err) return ERR_PTR(err); for (pos = *posp; pos && obj && !IS_ERR(obj); pos--) obj = __netlink_seq_next(seq); return obj; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu8291.11%240.00%
stephen hemmingerstephen hemminger44.44%120.00%
eric w. biedermaneric w. biederman33.33%120.00%
thomas grafthomas graf11.11%120.00%
Total90100.00%5100.00%


static void *netlink_seq_next(struct seq_file *seq, void *v, loff_t *pos) { ++*pos; return __netlink_seq_next(seq); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu2790.00%266.67%
stephen hemmingerstephen hemminger310.00%133.33%
Total30100.00%3100.00%


static void netlink_seq_stop(struct seq_file *seq, void *v) { struct nl_seq_iter *iter = seq->private; if (iter->link >= MAX_LINKS) return; netlink_walk_stop(iter); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu2257.89%150.00%
stephen hemmingerstephen hemminger1642.11%150.00%
Total38100.00%2100.00%


static int netlink_seq_show(struct seq_file *seq, void *v) { if (v == SEQ_START_TOKEN) { seq_puts(seq, "sk Eth Pid Groups " "Rmem Wmem Dump Locks Drops Inode\n"); } else { struct sock *s = v; struct netlink_sock *nlk = nlk_sk(s); seq_printf(seq, "%pK %-3d %-6u %08x %-8d %-8d %d %-8d %-8d %-8lu\n", s, s->sk_protocol, nlk->portid, nlk->groups ? (u32)nlk->groups[0] : 0, sk_rmem_alloc_get(s), sk_wmem_alloc_get(s), nlk->cb_running, atomic_read(&s->sk_refcnt), atomic_read(&s->sk_drops), sock_i_ino(s) ); } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
stephen hemmingerstephen hemminger4234.43%16.67%
pre-gitpre-git3125.41%213.33%
patrick mchardypatrick mchardy129.84%213.33%
david s. millerdavid s. miller129.84%16.67%
pablo neira ayusopablo neira ayuso86.56%16.67%
masatake yamatomasatake yamato64.92%16.67%
eric dumazeteric dumazet43.28%213.33%
arnaldo carvalho de meloarnaldo carvalho de melo32.46%213.33%
pravin b shelarpravin b shelar21.64%16.67%
eric w. biedermaneric w. biederman10.82%16.67%
john levonjohn levon10.82%16.67%
Total122100.00%15100.00%

static const struct seq_operations netlink_seq_ops = { .start = netlink_seq_start, .next = netlink_seq_next, .stop = netlink_seq_stop, .show = netlink_seq_show, };
static int netlink_seq_open(struct inode *inode, struct file *file) { return seq_open_net(inode, file, &netlink_seq_ops, sizeof(struct nl_seq_iter)); }

Contributors

PersonTokensPropCommitsCommitProp
stephen hemmingerstephen hemminger1442.42%116.67%
denis v. lunevdenis v. lunev515.15%116.67%
pavel emelianovpavel emelianov515.15%116.67%
eric w. biedermaneric w. biederman515.15%116.67%
herbert xuherbert xu39.09%116.67%
pre-gitpre-git13.03%116.67%
Total33100.00%6100.00%

static const struct file_operations netlink_seq_fops = { .owner = THIS_MODULE, .open = netlink_seq_open, .read = seq_read, .llseek = seq_lseek, .release = seq_release_net, }; #endif
int netlink_register_notifier(struct notifier_block *nb) { return atomic_notifier_chain_register(&netlink_chain, nb); }

Contributors

PersonTokensPropCommitsCommitProp
james morrisjames morris1894.74%150.00%
alan sternalan stern15.26%150.00%
Total19100.00%2100.00%

EXPORT_SYMBOL(netlink_register_notifier);
int netlink_unregister_notifier(struct notifier_block *nb) { return atomic_notifier_chain_unregister(&netlink_chain, nb); }

Contributors

PersonTokensPropCommitsCommitProp
james morrisjames morris1894.74%150.00%
alan sternalan stern15.26%150.00%
Total19100.00%2100.00%

EXPORT_SYMBOL(netlink_unregister_notifier); static const struct proto_ops netlink_ops = { .family = PF_NETLINK, .owner = THIS_MODULE, .release = netlink_release, .bind = netlink_bind, .connect = netlink_connect, .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = netlink_getname, .poll = datagram_poll, .ioctl = netlink_ioctl, .listen = sock_no_listen, .shutdown = sock_no_shutdown, .setsockopt = netlink_setsockopt, .getsockopt = netlink_getsockopt, .sendmsg = netlink_sendmsg, .recvmsg = netlink_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, }; static const struct net_proto_family netlink_family_ops = { .family = PF_NETLINK, .create = netlink_create, .owner = THIS_MODULE, /* for consistency 8) */ };
static int __net_init netlink_net_init(struct net *net) { #ifdef CONFIG_PROC_FS if (!proc_create("netlink", 0, net->proc_net, &netlink_seq_fops)) return -ENOMEM; #endif return 0; }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman3585.37%133.33%
gao fenggao feng512.20%133.33%
pavel emelianovpavel emelianov12.44%133.33%
Total41100.00%3100.00%


static void __net_exit netlink_net_exit(struct net *net) { #ifdef CONFIG_PROC_FS remove_proc_entry("netlink", net->proc_net); #endif }

Contributors

PersonTokensPropCommitsCommitProp
eric w. biedermaneric w. biederman2076.92%133.33%
gao fenggao feng519.23%133.33%
pavel emelianovpavel emelianov13.85%133.33%
Total26100.00%3100.00%


static void __init netlink_add_usersock_entry(void) { struct listeners *listeners; int groups = 32; listeners = kzalloc(sizeof(*listeners) + NLGRPSZ(groups), GFP_KERNEL); if (!listeners) panic("netlink_add_usersock_entry: Cannot allocate listeners\n"); netlink_table_grab(); nl_table[NETLINK_USERSOCK].groups = groups; rcu_assign_pointer(nl_table[NETLINK_USERSOCK].listeners, listeners); nl_table[NETLINK_USERSOCK].module = THIS_MODULE; nl_table[NETLINK_USERSOCK].registered = 1; nl_table[NETLINK_USERSOCK].flags = NL_CFG_F_NONROOT_SEND; netlink_table_ungrab(); }

Contributors

PersonTokensPropCommitsCommitProp
david s. millerdavid s. miller8079.21%125.00%
eric dumazeteric dumazet1211.88%125.00%
pablo neira ayusopablo neira ayuso98.91%250.00%
Total101100.00%4100.00%

static struct pernet_operations __net_initdata netlink_net_ops = { .init = netlink_net_init, .exit = netlink_net_exit, };
static inline u32 netlink_hash(const void *data, u32 len, u32 seed) { const struct netlink_sock *nlk = data; struct netlink_compare_arg arg; netlink_compare_arg_init(&arg, sock_net(&nlk->sk), nlk->portid); return jhash2((u32 *)&arg, netlink_compare_arg_len / sizeof(u32), seed); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu5580.88%342.86%
arnaldo carvalho de meloarnaldo carvalho de melo57.35%114.29%
pre-gitpre-git57.35%228.57%
patrick mchardypatrick mchardy34.41%114.29%
Total68100.00%7100.00%

static const struct rhashtable_params netlink_rhashtable_params = { .head_offset = offsetof(struct netlink_sock, node), .key_len = netlink_compare_arg_len, .obj_hashfn = netlink_hash, .obj_cmpfn = netlink_compare, .automatic_shrinking = true, };
static int __init netlink_proto_init(void) { int i; int err = proto_register(&netlink_proto, 0); if (err != 0) goto out; BUILD_BUG_ON(sizeof(struct netlink_skb_parms) > FIELD_SIZEOF(struct sk_buff, cb)); nl_table = kcalloc(MAX_LINKS, sizeof(*nl_table), GFP_KERNEL); if (!nl_table) goto panic; for (i = 0; i < MAX_LINKS; i++) { if (rhashtable_init(&nl_table[i].hash, &netlink_rhashtable_params) < 0) { while (--i > 0) rhashtable_destroy(&nl_table[i].hash); kfree(nl_table); goto panic; } } INIT_LIST_HEAD(&netlink_tap_all); netlink_add_usersock_entry(); sock_register(&netlink_family_ops); register_pernet_subsys(&netlink_net_ops); /* The netlink device handler may be needed early. */ rtnetlink_init(); out: return err; panic: panic("netlink_init: Cannot allocate nl_table\n"); }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu8851.76%212.50%
pre-gitpre-git2112.35%318.75%
arnaldo carvalho de meloarnaldo carvalho de melo169.41%212.50%
thomas grafthomas graf127.06%16.25%
akinobu mitaakinobu mita116.47%16.25%
hideaki yoshifujihideaki yoshifuji74.12%212.50%
daniel borkmanndaniel borkmann63.53%16.25%
david s. millerdavid s. miller31.76%16.25%
eric w. biedermaneric w. biederman31.76%212.50%
panagiotis issaris*panagiotis issaris*31.76%16.25%
Total170100.00%16100.00%

core_initcall(netlink_proto_init);

Overall Contributors

PersonTokensPropCommitsCommitProp
pre-gitpre-git224618.75%186.29%
patrick mchardypatrick mchardy166813.93%248.39%
herbert xuherbert xu142511.90%238.04%
daniel borkmanndaniel borkmann6765.64%82.80%
eric w. biedermaneric w. biederman6455.39%144.90%
johannes bergjohannes berg6405.34%144.90%
pablo neira ayusopablo neira ayuso5624.69%175.94%
thomas grafthomas graf5534.62%175.94%
david s. millerdavid s. miller3472.90%134.55%
florian westphalflorian westphal2632.20%20.70%
eric dumazeteric dumazet2612.18%155.24%
stephen hemmingerstephen hemminger2522.10%82.80%
nicolas dichtelnicolas dichtel2462.05%20.70%
richard guy briggsrichard guy briggs2321.94%20.70%
andrew mortonandrew morton2071.73%20.70%
denis v. lunevdenis v. lunev1711.43%103.50%
james morrisjames morris1501.25%93.15%
david herrmanndavid herrmann1461.22%20.70%
denys vlasenkodenys vlasenko1271.06%10.35%
christophe ricardchristophe ricard1221.02%10.35%
arnaldo carvalho de meloarnaldo carvalho de melo1221.02%113.85%
pravin b shelarpravin b shelar1170.98%10.35%
gao fenggao feng930.78%41.40%
harald welteharald welte710.59%10.35%
benjamin lahaisebenjamin lahaise570.48%10.35%
ying xueying xue510.43%10.35%
ronen aradronen arad500.42%10.35%
andrey vaginandrey vagin500.42%20.70%
hideaki yoshifujihideaki yoshifuji450.38%62.10%
rusty russellrusty russell380.32%10.35%
david decotignydavid decotigny250.21%10.35%
pavel emelianovpavel emelianov230.19%31.05%
tom herberttom herbert210.18%10.35%
greg rosegreg rose200.17%10.35%
neil hormanneil horman160.13%10.35%
changli gaochangli gao150.13%10.35%
steffen hurrlesteffen hurrle150.13%10.35%
alexey dobriyanalexey dobriyan150.13%10.35%
akinobu mitaakinobu mita150.13%10.35%
hannes frederic sowahannes frederic sowa140.12%10.35%
hiroaki shimodahiroaki shimoda120.10%10.35%
tommy s. christensentommy s. christensen110.09%20.70%
alexey kuznetsovalexey kuznetsov100.08%10.35%
heiko carstensheiko carstens80.07%10.35%
jesper juhljesper juhl80.07%10.35%
matthew wilcoxmatthew wilcox70.06%10.35%
al viroal viro70.06%41.40%
alan sternalan stern70.06%10.35%
cyrill gorcunovcyrill gorcunov70.06%10.35%
mike pecovnikmike pecovnik60.05%10.35%
masatake yamatomasatake yamato60.05%10.35%
martin murraymartin murray60.05%10.35%
linus torvaldslinus torvalds50.04%31.05%
octavian purdilaoctavian purdila50.04%10.35%
christoph hellwigchristoph hellwig50.04%10.35%
arjan van de venarjan van de ven50.04%20.70%
rami rosenrami rosen50.04%10.35%
dmitry ivanovdmitry ivanov40.03%10.35%
art haasart haas40.03%10.35%
thomas gleixnerthomas gleixner40.03%10.35%
thomas goffthomas goff30.03%10.35%
mel gormanmel gorman30.03%10.35%
eric pariseric paris30.03%10.35%
ilpo jarvinenilpo jarvinen30.03%10.35%
panagiotis issaris*panagiotis issaris*30.03%10.35%
randy dunlaprandy dunlap30.03%10.35%
varka bhadramvarka bhadram30.03%10.35%
lai jiangshanlai jiangshan20.02%10.35%
hong zhi guohong zhi guo20.02%10.35%
bob copelandbob copeland20.02%10.35%
ben pfaffben pfaff10.01%10.35%
adrian bunkadrian bunk10.01%10.35%
dan carpenterdan carpenter10.01%10.35%
john fastabendjohn fastabend10.01%10.35%
philippe de muyterphilippe de muyter10.01%10.35%
john levonjohn levon10.01%10.35%
Total11977100.00%286100.00%
Directory: net/netlink
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
{% endraw %}