cregit-Linux how code gets into the kernel

Release 4.14 net/sctp/protocol.c

Directory: net/sctp
/* SCTP kernel implementation
 * (C) Copyright IBM Corp. 2001, 2004
 * Copyright (c) 1999-2000 Cisco, Inc.
 * Copyright (c) 1999-2001 Motorola, Inc.
 * Copyright (c) 2001 Intel Corp.
 * Copyright (c) 2001 Nokia, Inc.
 * Copyright (c) 2001 La Monte H.P. Yarroll
 *
 * This file is part of the SCTP kernel implementation
 *
 * Initialization/cleanup for SCTP protocol support.
 *
 * This SCTP implementation 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, or (at your option)
 * any later version.
 *
 * This SCTP implementation is distributed in the hope that it
 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
 *                 ************************
 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with GNU CC; see the file COPYING.  If not, see
 * <http://www.gnu.org/licenses/>.
 *
 * Please send any bug reports or fixes you make to the
 * email address(es):
 *    lksctp developers <linux-sctp@vger.kernel.org>
 *
 * Written or modified by:
 *    La Monte H.P. Yarroll <piggy@acm.org>
 *    Karl Knutson <karl@athena.chicago.il.us>
 *    Jon Grimm <jgrimm@us.ibm.com>
 *    Sridhar Samudrala <sri@us.ibm.com>
 *    Daisy Chang <daisyc@us.ibm.com>
 *    Ardelle Fan <ardelle.fan@intel.com>
 */


#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

#include <linux/module.h>
#include <linux/init.h>
#include <linux/netdevice.h>
#include <linux/inetdevice.h>
#include <linux/seq_file.h>
#include <linux/bootmem.h>
#include <linux/highmem.h>
#include <linux/swap.h>
#include <linux/slab.h>
#include <net/net_namespace.h>
#include <net/protocol.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/route.h>
#include <net/sctp/sctp.h>
#include <net/addrconf.h>
#include <net/inet_common.h>
#include <net/inet_ecn.h>


#define MAX_SCTP_PORT_HASH_ENTRIES (64 * 1024)

/* Global data structures. */

struct sctp_globals sctp_globals __read_mostly;


struct idr sctp_assocs_id;

DEFINE_SPINLOCK(sctp_assocs_id_lock);


static struct sctp_pf *sctp_pf_inet6_specific;

static struct sctp_pf *sctp_pf_inet_specific;

static struct sctp_af *sctp_af_v4_specific;

static struct sctp_af *sctp_af_v6_specific;


struct kmem_cache *sctp_chunk_cachep __read_mostly;

struct kmem_cache *sctp_bucket_cachep __read_mostly;


long sysctl_sctp_mem[3];

int sysctl_sctp_rmem[3];

int sysctl_sctp_wmem[3];

/* Set up the proc fs entry for the SCTP protocol. */

static int __net_init sctp_proc_init(struct net *net) { #ifdef CONFIG_PROC_FS net->sctp.proc_net_sctp = proc_net_mkdir(net, "sctp", net->proc_net); if (!net->sctp.proc_net_sctp) goto out_proc_net_sctp; if (sctp_snmp_proc_init(net)) goto out_snmp_proc_init; if (sctp_eps_proc_init(net)) goto out_eps_proc_init; if (sctp_assocs_proc_init(net)) goto out_assocs_proc_init; if (sctp_remaddr_proc_init(net)) goto out_remaddr_proc_init; return 0; out_remaddr_proc_init: sctp_assocs_proc_exit(net); out_assocs_proc_init: sctp_eps_proc_exit(net); out_eps_proc_init: sctp_snmp_proc_exit(net); out_snmp_proc_init: remove_proc_entry("sctp", net->proc_net); net->sctp.proc_net_sctp = NULL; out_proc_net_sctp: return -ENOMEM; #endif /* CONFIG_PROC_FS */ return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann5539.57%213.33%
Sridhar Samudrala2517.99%320.00%
Wei Yongjun2014.39%16.67%
Jon Grimm139.35%16.67%
Florian Westphal85.76%16.67%
Neil Horman64.32%16.67%
David S. Miller42.88%16.67%
Alexey Dobriyan32.16%16.67%
Randy Dunlap21.44%16.67%
Christoph Paasch10.72%16.67%
Eric Dumazet10.72%16.67%
Pavel Emelyanov10.72%16.67%
Total139100.00%15100.00%

/* Clean up the proc fs entry for the SCTP protocol. * Note: Do not make this __exit as it is used in the init error * path. */
static void sctp_proc_exit(struct net *net) { #ifdef CONFIG_PROC_FS sctp_snmp_proc_exit(net); sctp_eps_proc_exit(net); sctp_assocs_proc_exit(net); sctp_remaddr_proc_exit(net); remove_proc_entry("sctp", net->proc_net); net->sctp.proc_net_sctp = NULL; #endif }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann2852.83%222.22%
Jon Grimm1120.75%111.11%
Sridhar Samudrala713.21%333.33%
Florian Westphal59.43%111.11%
David S. Miller11.89%111.11%
Neil Horman11.89%111.11%
Total53100.00%9100.00%

/* Private helper to extract ipv4 address and stash them in * the protocol structure. */
static void sctp_v4_copy_addrlist(struct list_head *addrlist, struct net_device *dev) { struct in_device *in_dev; struct in_ifaddr *ifa; struct sctp_sockaddr_entry *addr; rcu_read_lock(); if ((in_dev = __in_dev_get_rcu(dev)) == NULL) { rcu_read_unlock(); return; } for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) { /* Add the address to the local list. */ addr = kzalloc(sizeof(*addr), GFP_ATOMIC); if (addr) { addr->a.v4.sin_family = AF_INET; addr->a.v4.sin_port = 0; addr->a.v4.sin_addr.s_addr = ifa->ifa_local; addr->valid = 1; INIT_LIST_HEAD(&addr->list); list_add_tail(&addr->list, addrlist); } } rcu_read_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm12280.26%444.44%
Vladislav Yasevich149.21%111.11%
Daniel Borkmann63.95%111.11%
David S. Miller63.95%111.11%
Al Viro31.97%111.11%
Herbert Xu10.66%111.11%
Total152100.00%9100.00%

/* Extract our IP addresses from the system and stash them in the * protocol structure. */
static void sctp_get_local_addr_list(struct net *net) { struct net_device *dev; struct list_head *pos; struct sctp_af *af; rcu_read_lock(); for_each_netdev_rcu(net, dev) { list_for_each(pos, &sctp_address_families) { af = list_entry(pos, struct sctp_af, list); af->copy_addrlist(&net->sctp.local_addr_list, dev); } } rcu_read_unlock(); }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm5270.27%330.00%
Eric W. Biedermann1114.86%220.00%
Eric Dumazet56.76%110.00%
Pavel Emelyanov34.05%110.00%
Sridhar Samudrala22.70%220.00%
Dave Jones11.35%110.00%
Total74100.00%10100.00%

/* Free the existing local addresses. */
static void sctp_free_local_addr_list(struct net *net) { struct sctp_sockaddr_entry *addr; struct list_head *pos, *temp; list_for_each_safe(pos, temp, &net->sctp.local_addr_list) { addr = list_entry(pos, struct sctp_sockaddr_entry, list); list_del(pos); kfree(addr); } }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm4783.93%233.33%
Eric W. Biedermann58.93%116.67%
Rusty Russell23.57%116.67%
Sridhar Samudrala11.79%116.67%
David S. Miller11.79%116.67%
Total56100.00%6100.00%

/* Copy the local addresses which are valid for 'scope' into 'bp'. */
int sctp_copy_local_addr_list(struct net *net, struct sctp_bind_addr *bp, enum sctp_scope scope, gfp_t gfp, int copy_flags) { struct sctp_sockaddr_entry *addr; union sctp_addr laddr; int error = 0; rcu_read_lock(); list_for_each_entry_rcu(addr, &net->sctp.local_addr_list, list) { if (!addr->valid) continue; if (!sctp_in_scope(net, &addr->a, scope)) continue; /* Now that the address is in scope, check to see if * the address type is really supported by the local * sock as well as the remote peer. */ if (addr->a.sa.sa_family == AF_INET && !(copy_flags & SCTP_ADDR4_PEERSUPP)) continue; if (addr->a.sa.sa_family == AF_INET6 && (!(copy_flags & SCTP_ADDR6_ALLOWED) || !(copy_flags & SCTP_ADDR6_PEERSUPP))) continue; laddr = addr->a; /* also works for setting ipv6 address port */ laddr.v4.sin_port = htons(bp->port); if (sctp_bind_addr_state(bp, &laddr) != -1) continue; error = sctp_add_bind_addr(bp, &addr->a, sizeof(addr->a), SCTP_ADDR_SRC, GFP_ATOMIC); if (error) break; } rcu_read_unlock(); return error; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm9548.97%525.00%
Xin Long5829.90%420.00%
Vladislav Yasevich189.28%210.00%
Eric W. Biedermann84.12%210.00%
Marcelo Ricardo Leitner73.61%15.00%
Al Viro52.58%315.00%
Sridhar Samudrala21.03%210.00%
David S. Miller10.52%15.00%
Total194100.00%20100.00%

/* Initialize a sctp_addr from in incoming skb. */
static void sctp_v4_from_skb(union sctp_addr *addr, struct sk_buff *skb, int is_saddr) { /* Always called on head skb, so this is safe */ struct sctphdr *sh = sctp_hdr(skb); struct sockaddr_in *sa = &addr->v4; addr->v4.sin_family = AF_INET; if (is_saddr) { sa->sin_port = sh->source; sa->sin_addr.s_addr = ip_hdr(skb)->saddr; } else { sa->sin_port = sh->dest; sa->sin_addr.s_addr = ip_hdr(skb)->daddr; } }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm6565.66%133.33%
Marcelo Ricardo Leitner2828.28%133.33%
Arnaldo Carvalho de Melo66.06%133.33%
Total99100.00%3100.00%

/* Initialize an sctp_addr from a socket. */
static void sctp_v4_from_sk(union sctp_addr *addr, struct sock *sk) { addr->v4.sin_family = AF_INET; addr->v4.sin_port = 0; addr->v4.sin_addr.s_addr = inet_sk(sk)->inet_rcv_saddr; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm4595.74%133.33%
Eric Dumazet12.13%133.33%
Al Viro12.13%133.33%
Total47100.00%3100.00%

/* Initialize sk->sk_rcv_saddr from sctp_addr. */
static void sctp_v4_to_sk_saddr(union sctp_addr *addr, struct sock *sk) { inet_sk(sk)->inet_rcv_saddr = addr->v4.sin_addr.s_addr; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm2993.55%133.33%
Sridhar Samudrala13.23%133.33%
Eric Dumazet13.23%133.33%
Total31100.00%3100.00%

/* Initialize sk->sk_daddr from sctp_addr. */
static void sctp_v4_to_sk_daddr(union sctp_addr *addr, struct sock *sk) { inet_sk(sk)->inet_daddr = addr->v4.sin_addr.s_addr; }

Contributors

PersonTokensPropCommitsCommitProp
Sridhar Samudrala3096.77%150.00%
Eric Dumazet13.23%150.00%
Total31100.00%2100.00%

/* Initialize a sctp_addr from an address parameter. */
static void sctp_v4_from_addr_param(union sctp_addr *addr, union sctp_addr_param *param, __be16 port, int iif) { addr->v4.sin_family = AF_INET; addr->v4.sin_port = port; addr->v4.sin_addr.s_addr = param->v4.addr.s_addr; }

Contributors

PersonTokensPropCommitsCommitProp
Sridhar Samudrala5398.15%150.00%
Al Viro11.85%150.00%
Total54100.00%2100.00%

/* Initialize an address parameter from a sctp_addr and return the length * of the address parameter. */
static int sctp_v4_to_addr_param(const union sctp_addr *addr, union sctp_addr_param *param) { int length = sizeof(struct sctp_ipv4addr_param); param->v4.param_hdr.type = SCTP_PARAM_IPV4_ADDRESS; param->v4.param_hdr.length = htons(length); param->v4.addr.s_addr = addr->v4.sin_addr.s_addr; return length; }

Contributors

PersonTokensPropCommitsCommitProp
Sridhar Samudrala6595.59%133.33%
Xin Long22.94%133.33%
Al Viro11.47%133.33%
Total68100.00%3100.00%

/* Initialize a sctp_addr from a dst_entry. */
static void sctp_v4_dst_saddr(union sctp_addr *saddr, struct flowi4 *fl4, __be16 port) { saddr->v4.sin_family = AF_INET; saddr->v4.sin_port = port; saddr->v4.sin_addr.s_addr = fl4->saddr; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm2655.32%233.33%
Sridhar Samudrala1634.04%233.33%
David S. Miller48.51%116.67%
Al Viro12.13%116.67%
Total47100.00%6100.00%

/* Compare two addresses exactly. */
static int sctp_v4_cmp_addr(const union sctp_addr *addr1, const union sctp_addr *addr2) { if (addr1->sa.sa_family != addr2->sa.sa_family) return 0; if (addr1->v4.sin_port != addr2->v4.sin_port) return 0; if (addr1->v4.sin_addr.s_addr != addr2->v4.sin_addr.s_addr) return 0; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm7092.11%266.67%
Sridhar Samudrala67.89%133.33%
Total76100.00%3100.00%

/* Initialize addr struct to INADDR_ANY. */
static void sctp_v4_inaddr_any(union sctp_addr *addr, __be16 port) { addr->v4.sin_family = AF_INET; addr->v4.sin_addr.s_addr = htonl(INADDR_ANY); addr->v4.sin_port = port; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm3990.70%250.00%
Al Viro49.30%250.00%
Total43100.00%4100.00%

/* Is this a wildcard address? */
static int sctp_v4_is_any(const union sctp_addr *addr) { return htonl(INADDR_ANY) == addr->v4.sin_addr.s_addr; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm2388.46%150.00%
Al Viro311.54%150.00%
Total26100.00%2100.00%

/* This function checks if the address is a valid address to be used for * SCTP binding. * * Output: * Return 0 - If the address is a non-unicast or an illegal address. * Return 1 - If the address is a unicast. */
static int sctp_v4_addr_valid(union sctp_addr *addr, struct sctp_sock *sp, const struct sk_buff *skb) { /* IPv4 addresses not allowed */ if (sp && ipv6_only_sock(sctp_opt2sk(sp))) return 0; /* Is this a non-unicast address or a unusable SCTP address? */ if (IS_IPV4_UNUSABLE_ADDRESS(addr->v4.sin_addr.s_addr)) return 0; /* Is this a broadcast address? */ if (skb && skb_rtable(skb)->rt_flags & RTCF_BROADCAST) return 0; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Vladislav Yasevich3648.00%233.33%
Jon Grimm3546.67%233.33%
Eric Dumazet34.00%116.67%
Arnaldo Carvalho de Melo11.33%116.67%
Total75100.00%6100.00%

/* Should this be available for binding? */
static int sctp_v4_available(union sctp_addr *addr, struct sctp_sock *sp) { struct net *net = sock_net(&sp->inet.sk); int ret = inet_addr_type(net, addr->v4.sin_addr.s_addr); if (addr->v4.sin_addr.s_addr != htonl(INADDR_ANY) && ret != RTN_LOCAL && !sp->inet.freebind && !net->ipv4.sysctl_ip_nonlocal_bind) return 0; if (ipv6_only_sock(sctp_opt2sk(sp))) return 0; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm5151.52%222.22%
Eric W. Biedermann1717.17%222.22%
Vladislav Yasevich1313.13%111.11%
Neil Horman1010.10%111.11%
Vincent Bernat44.04%111.11%
Al Viro33.03%111.11%
Arnaldo Carvalho de Melo11.01%111.11%
Total99100.00%9100.00%

/* Checking the loopback, private and other address scopes as defined in * RFC 1918. The IPv4 scoping is based on the draft for SCTP IPv4 * scoping <draft-stewart-tsvwg-sctp-ipv4-00.txt>. * * Level 0 - unusable SCTP addresses * Level 1 - loopback address * Level 2 - link-local addresses * Level 3 - private addresses. * Level 4 - global addresses * For INIT and INIT-ACK address list, let L be the level of * of requested destination address, sender and receiver * SHOULD include all of its addresses with level greater * than or equal to L. * * IPv4 scoping can be controlled through sysctl option * net.sctp.addr_scope_policy */
static enum sctp_scope sctp_v4_scope(union sctp_addr *addr) { enum sctp_scope retval; /* Check for unusable SCTP addresses. */ if (IS_IPV4_UNUSABLE_ADDRESS(addr->v4.sin_addr.s_addr)) { retval = SCTP_SCOPE_UNUSABLE; } else if (ipv4_is_loopback(addr->v4.sin_addr.s_addr)) { retval = SCTP_SCOPE_LOOPBACK; } else if (ipv4_is_linklocal_169(addr->v4.sin_addr.s_addr)) { retval = SCTP_SCOPE_LINK; } else if (ipv4_is_private_10(addr->v4.sin_addr.s_addr) || ipv4_is_private_172(addr->v4.sin_addr.s_addr) || ipv4_is_private_192(addr->v4.sin_addr.s_addr)) { retval = SCTP_SCOPE_PRIVATE; } else { retval = SCTP_SCOPE_GLOBAL; } return retval; }

Contributors

PersonTokensPropCommitsCommitProp
Sridhar Samudrala9070.31%125.00%
Joe Perches2519.53%125.00%
Jon Grimm97.03%125.00%
Xin Long43.12%125.00%
Total128100.00%4100.00%

/* Returns a valid dst cache entry for the given source and destination ip * addresses. If an association is passed, trys to get a dst entry with a * source address that matches an address in the bind address list. */
static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr, struct flowi *fl, struct sock *sk) { struct sctp_association *asoc = t->asoc; struct rtable *rt; struct flowi4 *fl4 = &fl->u.ip4; struct sctp_bind_addr *bp; struct sctp_sockaddr_entry *laddr; struct dst_entry *dst = NULL; union sctp_addr *daddr = &t->ipaddr; union sctp_addr dst_saddr; memset(fl4, 0x0, sizeof(struct flowi4)); fl4->daddr = daddr->v4.sin_addr.s_addr; fl4->fl4_dport = daddr->v4.sin_port; fl4->flowi4_proto = IPPROTO_SCTP; if (asoc) { fl4->flowi4_tos = RT_CONN_FLAGS(asoc->base.sk); fl4->flowi4_oif = asoc->base.sk->sk_bound_dev_if; fl4->fl4_sport = htons(asoc->base.bind_addr.port); } if (saddr) { fl4->saddr = saddr->v4.sin_addr.s_addr; fl4->fl4_sport = saddr->v4.sin_port; } pr_debug("%s: dst:%pI4, src:%pI4 - ", __func__, &fl4->daddr, &fl4->saddr); rt = ip_route_output_key(sock_net(sk), fl4); if (!IS_ERR(rt)) dst = &rt->dst; /* If there is no association or if a source address is passed, no * more validation is required. */ if (!asoc || saddr) goto out; bp = &asoc->base.bind_addr; if (dst) { /* Walk through the bind address list and look for a bind * address that matches the source address of the returned dst. */ sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port)); rcu_read_lock(); list_for_each_entry_rcu(laddr, &bp->address_list, list) { if (!laddr->valid || (laddr->state == SCTP_ADDR_DEL) || (laddr->state != SCTP_ADDR_SRC && !asoc->src_out_of_asoc_ok)) continue; if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a)) goto out_unlock; } rcu_read_unlock(); /* None of the bound addresses match the source address of the * dst. So release it. */ dst_release(dst); dst = NULL; } /* Walk through the bind address list and try to get a dst that * matches a bind address as the source address. */ rcu_read_lock(); list_for_each_entry_rcu(laddr, &bp->address_list, list) { struct net_device *odev; if (!laddr->valid) continue; if (laddr->state != SCTP_ADDR_SRC || AF_INET != laddr->a.sa.sa_family) continue; fl4->fl4_sport = laddr->a.v4.sin_port; flowi4_update_output(fl4, asoc->base.sk->sk_bound_dev_if, RT_CONN_FLAGS(asoc->base.sk), daddr->v4.sin_addr.s_addr, laddr->a.v4.sin_addr.s_addr); rt = ip_route_output_key(sock_net(sk), fl4); if (IS_ERR(rt)) continue; if (!dst) dst = &rt->dst; /* Ensure the src address belongs to the output * interface. */ odev = __ip_dev_find(sock_net(sk), laddr->a.v4.sin_addr.s_addr, false); if (!odev || odev->ifindex != fl4->flowi4_oif) { if (&rt->dst != dst) dst_release(&rt->dst); continue; } if (dst != &rt->dst) dst_release(dst); dst = &rt->dst; break; } out_unlock: rcu_read_unlock(); out: t->dst = dst; if (dst) pr_debug("rt_dst:%pI4, rt_src:%pI4\n", &fl4->daddr, &fl4->saddr); else pr_debug("no route\n"); }

Contributors

PersonTokensPropCommitsCommitProp
Sridhar Samudrala21936.44%412.50%
Marcelo Ricardo Leitner9315.47%412.50%
Vladislav Yasevich9014.98%412.50%
David S. Miller528.65%412.50%
Wei Yongjun355.82%13.12%
Xufeng Zhang335.49%13.12%
Jon Grimm274.49%412.50%
Gui Jianfeng142.33%13.12%
Michio Honda132.16%13.12%
Eric W. Biedermann81.33%13.12%
Harvey Harrison61.00%26.25%
Daniel Borkmann50.83%13.12%
Al Viro40.67%39.38%
Denis V. Lunev20.33%13.12%
Total601100.00%32100.00%

/* For v4, the source address is cached in the route entry(dst). So no need * to cache it separately and hence this is an empty routine. */
static void sctp_v4_get_saddr(struct sctp_sock *sk, struct sctp_transport *t, struct flowi *fl) { union sctp_addr *saddr = &t->saddr; struct rtable *rt = (struct rtable *)t->dst; if (rt) { saddr->v4.sin_family = AF_INET; saddr->v4.sin_addr.s_addr = fl->u.ip4.saddr; } }

Contributors

PersonTokensPropCommitsCommitProp
Sridhar Samudrala4965.33%342.86%
Vladislav Yasevich1418.67%114.29%
David S. Miller68.00%114.29%
Hideaki Yoshifuji / 吉藤英明56.67%114.29%
Jon Grimm11.33%114.29%
Total75100.00%7100.00%

/* What interface did this skb arrive on? */
static int sctp_v4_skb_iif(const struct sk_buff *skb) { return inet_iif(skb); }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm1583.33%250.00%
Eric Dumazet211.11%125.00%
David S. Miller15.56%125.00%
Total18100.00%4100.00%

/* Was this packet marked by Explicit Congestion Notification? */
static int sctp_v4_is_ce(const struct sk_buff *skb) { return INET_ECN_is_ce(ip_hdr(skb)->tos); }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm2086.96%150.00%
Arnaldo Carvalho de Melo313.04%150.00%
Total23100.00%2100.00%

/* Create and initialize a new sk for the socket returned by accept(). */
static struct sock *sctp_v4_create_accept_sk(struct sock *sk, struct sctp_association *asoc, bool kern) { struct sock *newsk = sk_alloc(sock_net(sk), PF_INET, GFP_KERNEL, sk->sk_prot, kern); struct inet_sock *newinet; if (!newsk) goto out; sock_init_data(NULL, newsk); sctp_copy_sock(newsk, sk, asoc); sock_reset_flag(newsk, SOCK_ZAPPED); newinet = inet_sk(newsk); newinet->inet_daddr = asoc->peer.primary_addr.v4.sin_addr.s_addr; sk_refcnt_debug_inc(newsk); if (newsk->sk_prot->init(newsk)) { sk_common_release(newsk); newsk = NULL; } out: return newsk; }

Contributors

PersonTokensPropCommitsCommitProp
Sridhar Samudrala9570.37%214.29%
Vladislav Yasevich118.15%17.14%
Arnaldo Carvalho de Melo118.15%535.71%
Thomas Graf75.19%17.14%
David Howells42.96%17.14%
Eric W. Biedermann32.22%214.29%
Hideaki Yoshifuji / 吉藤英明32.22%17.14%
Eric Dumazet10.74%17.14%
Total135100.00%14100.00%


static int sctp_v4_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr) { /* No address mapping for V4 sockets */ return sizeof(struct sockaddr_in); }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm1354.17%133.33%
Jason Gunthorpe1041.67%133.33%
Arnaldo Carvalho de Melo14.17%133.33%
Total24100.00%3100.00%

/* Dump the v4 addr to the seq file. */
static void sctp_v4_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr) { seq_printf(seq, "%pI4 ", &addr->v4.sin_addr); }

Contributors

PersonTokensPropCommitsCommitProp
Sridhar Samudrala2893.33%150.00%
Harvey Harrison26.67%150.00%
Total30100.00%2100.00%


static void sctp_v4_ecn_capable(struct sock *sk) { INET_ECN_xmit(sk); }

Contributors

PersonTokensPropCommitsCommitProp
Vladislav Yasevich16100.00%1100.00%
Total16100.00%1100.00%


static void sctp_addr_wq_timeout_handler(unsigned long arg) { struct net *net = (struct net *)arg; struct sctp_sockaddr_entry *addrw, *temp; struct sctp_sock *sp; spin_lock_bh(&net->sctp.addr_wq_lock); list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) { pr_debug("%s: the first ent in wq:%p is addr:%pISc for cmd:%d at " "entry:%p\n", __func__, &net->sctp.addr_waitq, &addrw->a.sa, addrw->state, addrw); #if IS_ENABLED(CONFIG_IPV6) /* Now we send an ASCONF for each association */ /* Note. we currently don't handle link local IPv6 addressees */ if (addrw->a.sa.sa_family == AF_INET6) { struct in6_addr *in6; if (ipv6_addr_type(&addrw->a.v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) goto free_next; in6 = (struct in6_addr *)&addrw->a.v6.sin6_addr; if (ipv6_chk_addr(net, in6, NULL, 0) == 0 && addrw->state == SCTP_ADDR_NEW) { unsigned long timeo_val; pr_debug("%s: this is on DAD, trying %d sec " "later\n", __func__, SCTP_ADDRESS_TICK_DELAY); timeo_val = jiffies; timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY); mod_timer(&net->sctp.addr_wq_timer, timeo_val); break; } } #endif list_for_each_entry(sp, &net->sctp.auto_asconf_splist, auto_asconf_list) { struct sock *sk; sk = sctp_opt2sk(sp); /* ignore bound-specific endpoints */ if (!sctp_is_ep_boundall(sk)) continue; bh_lock_sock(sk); if (sctp_asconf_mgmt(sp, addrw) < 0) pr_debug("%s: sctp_asconf_mgmt failed\n", __func__); bh_unlock_sock(sk); } #if IS_ENABLED(CONFIG_IPV6) free_next: #endif list_del(&addrw->list); kfree(addrw); } spin_unlock_bh(&net->sctp.addr_wq_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Michio Honda23477.23%112.50%
Eric W. Biedermann3511.55%112.50%
Daniel Borkmann154.95%112.50%
Daniel C. Halperin82.64%112.50%
David S. Miller72.31%112.50%
Wang Weidong20.66%112.50%
Eric Dumazet10.33%112.50%
Stephen Hemminger10.33%112.50%
Total303100.00%8100.00%


static void sctp_free_addr_wq(struct net *net) { struct sctp_sockaddr_entry *addrw; struct sctp_sockaddr_entry *temp; spin_lock_bh(&net->sctp.addr_wq_lock); del_timer(&net->sctp.addr_wq_timer); list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) { list_del(&addrw->list); kfree(addrw); } spin_unlock_bh(&net->sctp.addr_wq_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Michio Honda5673.68%150.00%
Eric W. Biedermann2026.32%150.00%
Total76100.00%2100.00%

/* lookup the entry for the same address in the addr_waitq * sctp_addr_wq MUST be locked */
static struct sctp_sockaddr_entry *sctp_addr_wq_lookup(struct net *net, struct sctp_sockaddr_entry *addr) { struct sctp_sockaddr_entry *addrw; list_for_each_entry(addrw, &net->sctp.addr_waitq, list) { if (addrw->a.sa.sa_family != addr->a.sa.sa_family) continue; if (addrw->a.sa.sa_family == AF_INET) { if (addrw->a.v4.sin_addr.s_addr == addr->a.v4.sin_addr.s_addr) return addrw; } else if (addrw->a.sa.sa_family == AF_INET6) { if (ipv6_addr_equal(&addrw->a.v6.sin6_addr, &addr->a.v6.sin6_addr)) return addrw; } } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
Michio Honda12995.56%150.00%
Eric W. Biedermann64.44%150.00%
Total135100.00%2100.00%


void sctp_addr_wq_mgmt(struct net *net, struct sctp_sockaddr_entry *addr, int cmd) { struct sctp_sockaddr_entry *addrw; unsigned long timeo_val; /* first, we check if an opposite message already exist in the queue. * If we found such message, it is removed. * This operation is a bit stupid, but the DHCP client attaches the * new address after a couple of addition and deletion of that address */ spin_lock_bh(&net->sctp.addr_wq_lock); /* Offsets existing events in addr_wq */ addrw = sctp_addr_wq_lookup(net, addr); if (addrw) { if (addrw->state != cmd) { pr_debug("%s: offsets existing entry for %d, addr:%pISc " "in wq:%p\n", __func__, addrw->state, &addrw->a.sa, &net->sctp.addr_waitq); list_del(&addrw->list); kfree(addrw); } spin_unlock_bh(&net->sctp.addr_wq_lock); return; } /* OK, we have to add the new address to the wait queue */ addrw = kmemdup(addr, sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); if (addrw == NULL) { spin_unlock_bh(&net->sctp.addr_wq_lock); return; } addrw->state = cmd; list_add_tail(&addrw->list, &net->sctp.addr_waitq); pr_debug("%s: add new entry for cmd:%d, addr:%pISc in wq:%p\n", __func__, addrw->state, &addrw->a.sa, &net->sctp.addr_waitq); if (!timer_pending(&net->sctp.addr_wq_timer)) { timeo_val = jiffies; timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY); mod_timer(&net->sctp.addr_wq_timer, timeo_val); } spin_unlock_bh(&net->sctp.addr_wq_lock); }

Contributors

PersonTokensPropCommitsCommitProp
Michio Honda18074.07%133.33%
Eric W. Biedermann5221.40%133.33%
Daniel Borkmann114.53%133.33%
Total243100.00%3100.00%

/* Event handler for inet address addition/deletion events. * The sctp_local_addr_list needs to be protocted by a spin lock since * multiple notifiers (say IPv4 and IPv6) may be running at the same * time and thus corrupt the list. * The reader side is protected with RCU. */
static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev, void *ptr) { struct in_ifaddr *ifa = (struct in_ifaddr *)ptr; struct sctp_sockaddr_entry *addr = NULL; struct sctp_sockaddr_entry *temp; struct net *net = dev_net(ifa->ifa_dev->dev); int found = 0; switch (ev) { case NETDEV_UP: addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC); if (addr) { addr->a.v4.sin_family = AF_INET; addr->a.v4.sin_port = 0; addr->a.v4.sin_addr.s_addr = ifa->ifa_local; addr->valid = 1; spin_lock_bh(&net->sctp.local_addr_lock); list_add_tail_rcu(&addr->list, &net->sctp.local_addr_list); sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_NEW); spin_unlock_bh(&net->sctp.local_addr_lock); } break; case NETDEV_DOWN: spin_lock_bh(&net->sctp.local_addr_lock); list_for_each_entry_safe(addr, temp, &net->sctp.local_addr_list, list) { if (addr->a.sa.sa_family == AF_INET && addr->a.v4.sin_addr.s_addr == ifa->ifa_local) { sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL); found = 1; addr->valid = 0; list_del_rcu(&addr->list); break; } } spin_unlock_bh(&net->sctp.local_addr_lock); if (found) kfree_rcu(addr, rcu); break; } return NOTIFY_DONE; }

Contributors

PersonTokensPropCommitsCommitProp
Sridhar Samudrala11841.99%215.38%
Vladislav Yasevich5118.15%17.69%
Eric W. Biedermann4014.23%17.69%
Jon Grimm3111.03%215.38%
Michio Honda144.98%17.69%
Pavel Emelyanov103.56%17.69%
Chidambar 'ilLogict' Zinnoury62.14%17.69%
Denis V. Lunev51.78%17.69%
Hideaki Yoshifuji / 吉藤英明31.07%17.69%
Lai Jiangshan20.71%17.69%
Adrian Bunk10.36%17.69%
Total281100.00%13100.00%

/* * Initialize the control inode/socket with a control endpoint data * structure. This endpoint is reserved exclusively for the OOTB processing. */
static int sctp_ctl_sock_init(struct net *net) { int err; sa_family_t family = PF_INET; if (sctp_get_pf_specific(PF_INET6)) family = PF_INET6; err = inet_ctl_sock_create(&net->sctp.ctl_sock, family, SOCK_SEQPACKET, IPPROTO_SCTP, net); /* If IPv6 socket could not be created, try the IPv4 socket */ if (err < 0 && family == PF_INET6) err = inet_ctl_sock_create(&net->sctp.ctl_sock, AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP, net); if (err < 0) { pr_err("Failed to create the SCTP control socket\n"); return err; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm5050.00%222.22%
Brian Haley2626.00%111.11%
Eric W. Biedermann1616.00%111.11%
Denis V. Lunev44.00%222.22%
Joe Perches22.00%111.11%
Sridhar Samudrala11.00%111.11%
David S. Miller11.00%111.11%
Total100100.00%9100.00%

/* Register address family specific functions. */
int sctp_register_af(struct sctp_af *af) { switch (af->sa_family) { case AF_INET: if (sctp_af_v4_specific) return 0; sctp_af_v4_specific = af; break; case AF_INET6: if (sctp_af_v6_specific) return 0; sctp_af_v6_specific = af; break; default: return 0; } INIT_LIST_HEAD(&af->list); list_add_tail(&af->list, &sctp_address_families); return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm7398.65%375.00%
Sridhar Samudrala11.35%125.00%
Total74100.00%4100.00%

/* Get the table of functions for manipulating a particular address * family. */
struct sctp_af *sctp_get_af_specific(sa_family_t family) { switch (family) { case AF_INET: return sctp_af_v4_specific; case AF_INET6: return sctp_af_v6_specific; default: return NULL; } }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm32100.00%2100.00%
Total32100.00%2100.00%

/* Common code to initialize a AF_INET msg_name. */
static void sctp_inet_msgname(char *msgname, int *addr_len) { struct sockaddr_in *sin; sin = (struct sockaddr_in *)msgname; *addr_len = sizeof(struct sockaddr_in); sin->sin_family = AF_INET; memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm59100.00%1100.00%
Total59100.00%1100.00%

/* Copy the primary address of the peer primary address as the msg_name. */
static void sctp_inet_event_msgname(struct sctp_ulpevent *event, char *msgname, int *addr_len) { struct sockaddr_in *sin, *sinfrom; if (msgname) { struct sctp_association *asoc; asoc = event->asoc; sctp_inet_msgname(msgname, addr_len); sin = (struct sockaddr_in *)msgname; sinfrom = &asoc->peer.primary_addr.v4; sin->sin_port = htons(asoc->peer.port); sin->sin_addr.s_addr = sinfrom->sin_addr.s_addr; } }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm8588.54%250.00%
Sridhar Samudrala1111.46%250.00%
Total96100.00%4100.00%

/* Initialize and copy out a msgname from an inbound skb. */
static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *len) { if (msgname) { struct sctphdr *sh = sctp_hdr(skb); struct sockaddr_in *sin = (struct sockaddr_in *)msgname; sctp_inet_msgname(msgname, len); sin->sin_port = sh->source; sin->sin_addr.s_addr = ip_hdr(skb)->saddr; } }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm5573.33%250.00%
Arnaldo Carvalho de Melo2026.67%250.00%
Total75100.00%4100.00%

/* Do we support this AF? */
static int sctp_inet_af_supported(sa_family_t family, struct sctp_sock *sp) { /* PF_INET only supports AF_INET addresses. */ return AF_INET == family; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm1995.00%266.67%
Arnaldo Carvalho de Melo15.00%133.33%
Total20100.00%3100.00%

/* Address matching with wildcards allowed. */
static int sctp_inet_cmp_addr(const union sctp_addr *addr1, const union sctp_addr *addr2, struct sctp_sock *opt) { /* PF_INET only supports AF_INET addresses. */ if (addr1->sa.sa_family != addr2->sa.sa_family) return 0; if (htonl(INADDR_ANY) == addr1->v4.sin_addr.s_addr || htonl(INADDR_ANY) == addr2->v4.sin_addr.s_addr) return 1; if (addr1->v4.sin_addr.s_addr == addr2->v4.sin_addr.s_addr) return 1; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm8992.71%133.33%
Al Viro66.25%133.33%
Arnaldo Carvalho de Melo11.04%133.33%
Total96100.00%3100.00%

/* Verify that provided sockaddr looks bindable. Common verification has * already been taken care of. */
static int sctp_inet_bind_verify(struct sctp_sock *opt, union sctp_addr *addr) { return sctp_v4_available(addr, opt); }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm2395.83%266.67%
Arnaldo Carvalho de Melo14.17%133.33%
Total24100.00%3100.00%

/* Verify that sockaddr looks sendable. Common verification has already * been taken care of. */
static int sctp_inet_send_verify(struct sctp_sock *opt, union sctp_addr *addr) { return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm1894.74%150.00%
Arnaldo Carvalho de Melo15.26%150.00%
Total19100.00%2100.00%

/* Fill in Supported Address Type information for INIT and INIT-ACK * chunks. Returns number of addresses supported. */
static int sctp_inet_supported_addrs(const struct sctp_sock *opt, __be16 *types) { types[0] = SCTP_PARAM_IPV4_ADDRESS; return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm2492.31%133.33%
Arnaldo Carvalho de Melo13.85%133.33%
Al Viro13.85%133.33%
Total26100.00%3100.00%

/* Wrapper routine that calls the ip transmit routine. */
static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *transport) { struct inet_sock *inet = inet_sk(skb->sk); pr_debug("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, skb->len, &transport->fl.u.ip4.saddr, &transport->fl.u.ip4.daddr); inet->pmtudisc = transport->param_flags & SPP_PMTUD_ENABLE ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; SCTP_INC_STATS(sock_net(&inet->sk), SCTP_MIB_OUTSCTPPACKS); return ip_queue_xmit(&inet->sk, skb, &transport->fl); }

Contributors

PersonTokensPropCommitsCommitProp
Sridhar Samudrala4138.32%218.18%
Herbert Xu2624.30%19.09%
David S. Miller2119.63%218.18%
Eric W. Biedermann87.48%19.09%
Eric Dumazet54.67%19.09%
Harvey Harrison43.74%218.18%
Hideaki Yoshifuji / 吉藤英明10.93%19.09%
Daniel Borkmann10.93%19.09%
Total107100.00%11100.00%

static struct sctp_af sctp_af_inet; static struct sctp_pf sctp_pf_inet = { .event_msgname = sctp_inet_event_msgname, .skb_msgname = sctp_inet_skb_msgname, .af_supported = sctp_inet_af_supported, .cmp_addr = sctp_inet_cmp_addr, .bind_verify = sctp_inet_bind_verify, .send_verify = sctp_inet_send_verify, .supported_addrs = sctp_inet_supported_addrs, .create_accept_sk = sctp_v4_create_accept_sk, .addr_to_user = sctp_v4_addr_to_user, .to_sk_saddr = sctp_v4_to_sk_saddr, .to_sk_daddr = sctp_v4_to_sk_daddr, .af = &sctp_af_inet }; /* Notifier for inetaddr addition/deletion events. */ static struct notifier_block sctp_inetaddr_notifier = { .notifier_call = sctp_inetaddr_event, }; /* Socket operations. */ static const struct proto_ops inet_seqpacket_ops = { .family = PF_INET, .owner = THIS_MODULE, .release = inet_release, /* Needs to be wrapped... */ .bind = inet_bind, .connect = inet_dgram_connect, .socketpair = sock_no_socketpair, .accept = inet_accept, .getname = inet_getname, /* Semantics are different. */ .poll = sctp_poll, .ioctl = inet_ioctl, .listen = sctp_inet_listen, .shutdown = inet_shutdown, /* Looks harmless. */ .setsockopt = sock_common_setsockopt, /* IP_SOL IP_OPTION is a problem */ .getsockopt = sock_common_getsockopt, .sendmsg = inet_sendmsg, .recvmsg = inet_recvmsg, .mmap = sock_no_mmap, .sendpage = sock_no_sendpage, #ifdef CONFIG_COMPAT .compat_setsockopt = compat_sock_common_setsockopt, .compat_getsockopt = compat_sock_common_getsockopt, #endif }; /* Registration with AF_INET family. */ static struct inet_protosw sctp_seqpacket_protosw = { .type = SOCK_SEQPACKET, .protocol = IPPROTO_SCTP, .prot = &sctp_prot, .ops = &inet_seqpacket_ops, .flags = SCTP_PROTOSW_FLAG }; static struct inet_protosw sctp_stream_protosw = { .type = SOCK_STREAM, .protocol = IPPROTO_SCTP, .prot = &sctp_prot, .ops = &inet_seqpacket_ops, .flags = SCTP_PROTOSW_FLAG }; /* Register with IP layer. */ static const struct net_protocol sctp_protocol = { .handler = sctp_rcv, .err_handler = sctp_v4_err, .no_policy = 1, .netns_ok = 1, .icmp_strict_tag_validation = 1, }; /* IPv4 address related functions. */ static struct sctp_af sctp_af_inet = { .sa_family = AF_INET, .sctp_xmit = sctp_v4_xmit, .setsockopt = ip_setsockopt, .getsockopt = ip_getsockopt, .get_dst = sctp_v4_get_dst, .get_saddr = sctp_v4_get_saddr, .copy_addrlist = sctp_v4_copy_addrlist, .from_skb = sctp_v4_from_skb, .from_sk = sctp_v4_from_sk, .from_addr_param = sctp_v4_from_addr_param, .to_addr_param = sctp_v4_to_addr_param, .cmp_addr = sctp_v4_cmp_addr, .addr_valid = sctp_v4_addr_valid, .inaddr_any = sctp_v4_inaddr_any, .is_any = sctp_v4_is_any, .available = sctp_v4_available, .scope = sctp_v4_scope, .skb_iif = sctp_v4_skb_iif, .is_ce = sctp_v4_is_ce, .seq_dump_addr = sctp_v4_seq_dump_addr, .ecn_capable = sctp_v4_ecn_capable, .net_header_len = sizeof(struct iphdr), .sockaddr_len = sizeof(struct sockaddr_in), #ifdef CONFIG_COMPAT .compat_setsockopt = compat_ip_setsockopt, .compat_getsockopt = compat_ip_getsockopt, #endif };
struct sctp_pf *sctp_get_pf_specific(sa_family_t family) { switch (family) { case PF_INET: return sctp_pf_inet_specific; case PF_INET6: return sctp_pf_inet6_specific; default: return NULL; } }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm32100.00%2100.00%
Total32100.00%2100.00%

/* Register the PF specific function table. */
int sctp_register_pf(struct sctp_pf *pf, sa_family_t family) { switch (family) { case PF_INET: if (sctp_pf_inet_specific) return 0; sctp_pf_inet_specific = pf; break; case PF_INET6: if (sctp_pf_inet6_specific) return 0; sctp_pf_inet6_specific = pf; break; default: return 0; } return 1; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm56100.00%2100.00%
Total56100.00%2100.00%


static inline int init_sctp_mibs(struct net *net) { net->sctp.sctp_statistics = alloc_percpu(struct sctp_mib); if (!net->sctp.sctp_statistics) return -ENOMEM; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Américo Wang1845.00%120.00%
Ravikiran G. Thirumalai922.50%120.00%
Eric W. Biedermann820.00%120.00%
Eric Dumazet410.00%120.00%
Hideaki Yoshifuji / 吉藤英明12.50%120.00%
Total40100.00%5100.00%


static inline void cleanup_sctp_mibs(struct net *net) { free_percpu(net->sctp.sctp_statistics); }

Contributors

PersonTokensPropCommitsCommitProp
Ravikiran G. Thirumalai1152.38%125.00%
Eric W. Biedermann838.10%125.00%
Américo Wang14.76%125.00%
Hideaki Yoshifuji / 吉藤英明14.76%125.00%
Total21100.00%4100.00%


static void sctp_v4_pf_init(void) { /* Initialize the SCTP specific PF functions. */ sctp_register_pf(&sctp_pf_inet, PF_INET); sctp_register_af(&sctp_af_inet); }

Contributors

PersonTokensPropCommitsCommitProp
Vladislav Yasevich23100.00%1100.00%
Total23100.00%1100.00%


static void sctp_v4_pf_exit(void) { list_del(&sctp_af_inet.list); }

Contributors

PersonTokensPropCommitsCommitProp
Vladislav Yasevich16100.00%1100.00%
Total16100.00%1100.00%


static int sctp_v4_protosw_init(void) { int rc; rc = proto_register(&sctp_prot, 1); if (rc) return rc; /* Register SCTP(UDP and TCP style) with socket layer. */ inet_register_protosw(&sctp_seqpacket_protosw); inet_register_protosw(&sctp_stream_protosw); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Vladislav Yasevich44100.00%1100.00%
Total44100.00%1100.00%


static void sctp_v4_protosw_exit(void) { inet_unregister_protosw(&sctp_stream_protosw); inet_unregister_protosw(&sctp_seqpacket_protosw); proto_unregister(&sctp_prot); }

Contributors

PersonTokensPropCommitsCommitProp
Vladislav Yasevich26100.00%1100.00%
Total26100.00%1100.00%


static int sctp_v4_add_protocol(void) { /* Register notifier for inet address additions/deletions. */ register_inetaddr_notifier(&sctp_inetaddr_notifier); /* Register SCTP with inet layer. */ if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0) return -EAGAIN; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Vladislav Yasevich35100.00%1100.00%
Total35100.00%1100.00%


static void sctp_v4_del_protocol(void) { inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); unregister_inetaddr_notifier(&sctp_inetaddr_notifier); }

Contributors

PersonTokensPropCommitsCommitProp
Vladislav Yasevich22100.00%1100.00%
Total22100.00%1100.00%


static int __net_init sctp_defaults_init(struct net *net) { int status; /* * 14. Suggested SCTP Protocol Parameter Values */ /* The following protocol parameters are RECOMMENDED: */ /* RTO.Initial - 3 seconds */ net->sctp.rto_initial = SCTP_RTO_INITIAL; /* RTO.Min - 1 second */ net->sctp.rto_min = SCTP_RTO_MIN; /* RTO.Max - 60 seconds */ net->sctp.rto_max = SCTP_RTO_MAX; /* RTO.Alpha - 1/8 */ net->sctp.rto_alpha = SCTP_RTO_ALPHA; /* RTO.Beta - 1/4 */ net->sctp.rto_beta = SCTP_RTO_BETA; /* Valid.Cookie.Life - 60 seconds */ net->sctp.valid_cookie_life = SCTP_DEFAULT_COOKIE_LIFE; /* Whether Cookie Preservative is enabled(1) or not(0) */ net->sctp.cookie_preserve_enable = 1; /* Default sctp sockets to use md5 as their hmac alg */ #if defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_MD5) net->sctp.sctp_hmac_alg = "md5"; #elif defined (CONFIG_SCTP_DEFAULT_COOKIE_HMAC_SHA1) net->sctp.sctp_hmac_alg = "sha1"; #else net->sctp.sctp_hmac_alg = NULL; #endif /* Max.Burst - 4 */ net->sctp.max_burst = SCTP_DEFAULT_MAX_BURST; /* Enable pf state by default */ net->sctp.pf_enable = 1; /* Association.Max.Retrans - 10 attempts * Path.Max.Retrans - 5 attempts (per destination address) * Max.Init.Retransmits - 8 attempts */ net->sctp.max_retrans_association = 10; net->sctp.max_retrans_path = 5; net->sctp.max_retrans_init = 8; /* Sendbuffer growth - do per-socket accounting */ net->sctp.sndbuf_policy = 0; /* Rcvbuffer growth - do per-socket accounting */ net->sctp.rcvbuf_policy = 0; /* HB.interval - 30 seconds */ net->sctp.hb_interval = SCTP_DEFAULT_TIMEOUT_HEARTBEAT; /* delayed SACK timeout */ net->sctp.sack_timeout = SCTP_DEFAULT_TIMEOUT_SACK; /* Disable ADDIP by default. */ net->sctp.addip_enable = 0; net->sctp.addip_noauth = 0; net->sctp.default_auto_asconf = 0; /* Enable PR-SCTP by default. */ net->sctp.prsctp_enable = 1; /* Disable RECONF by default. */ net->sctp.reconf_enable = 0; /* Disable AUTH by default. */ net->sctp.auth_enable = 0; /* Set SCOPE policy to enabled */ net->sctp.scope_policy = SCTP_SCOPE_POLICY_ENABLE; /* Set the default rwnd update threshold */ net->sctp.rwnd_upd_shift = SCTP_DEFAULT_RWND_SHIFT; /* Initialize maximum autoclose timeout. */ net->sctp.max_autoclose = INT_MAX / HZ; status = sctp_sysctl_net_register(net); if (status) goto err_sysctl_register; /* Allocate and initialise sctp mibs. */ status = init_sctp_mibs(net); if (status) goto err_init_mibs; /* Initialize proc fs directory. */ status = sctp_proc_init(net); if (status) goto err_init_proc; sctp_dbg_objcnt_init(net); /* Initialize the local address list. */ INIT_LIST_HEAD(&net->sctp.local_addr_list); spin_lock_init(&net->sctp.local_addr_lock); sctp_get_local_addr_list(net); /* Initialize the address event list */ INIT_LIST_HEAD(&net->sctp.addr_waitq); INIT_LIST_HEAD(&net->sctp.auto_asconf_splist); spin_lock_init(&net->sctp.addr_wq_lock); net->sctp.addr_wq_timer.expires = 0; setup_timer(&net->sctp.addr_wq_timer, sctp_addr_wq_timeout_handler, (unsigned long)net); return 0; err_init_proc: cleanup_sctp_mibs(net); err_init_mibs: sctp_sysctl_net_unregister(net); err_sysctl_register: return status; }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann37686.04%650.00%
Neil Horman419.38%216.67%
Xin Long92.06%18.33%
Zhu Yanjun92.06%18.33%
Christoph Paasch10.23%18.33%
Marcelo Ricardo Leitner10.23%18.33%
Total437100.00%12100.00%


static void __net_exit sctp_defaults_exit(struct net *net) { /* Free the local address list */ sctp_free_addr_wq(net); sctp_free_local_addr_list(net); sctp_dbg_objcnt_exit(net); sctp_proc_exit(net); cleanup_sctp_mibs(net); sctp_sysctl_net_unregister(net); }

Contributors

PersonTokensPropCommitsCommitProp
Eric W. Biedermann4195.35%466.67%
Marcelo Ricardo Leitner12.33%116.67%
Christoph Paasch12.33%116.67%
Total43100.00%6100.00%

static struct pernet_operations sctp_defaults_ops = { .init = sctp_defaults_init, .exit = sctp_defaults_exit, };
static int __net_init sctp_ctrlsock_init(struct net *net) { int status; /* Initialize the control inode/socket for handling OOTB packets. */ status = sctp_ctl_sock_init(net); if (status) pr_err("Failed to initialize the SCTP control sock\n"); return status; }

Contributors

PersonTokensPropCommitsCommitProp
Marcelo Ricardo Leitner35100.00%1100.00%
Total35100.00%1100.00%


static void __net_init sctp_ctrlsock_exit(struct net *net) { /* Free the control endpoint. */ inet_ctl_sock_destroy(net->sctp.ctl_sock); }

Contributors

PersonTokensPropCommitsCommitProp
Marcelo Ricardo Leitner22100.00%1100.00%
Total22100.00%1100.00%

static struct pernet_operations sctp_ctrlsock_ops = { .init = sctp_ctrlsock_init, .exit = sctp_ctrlsock_exit, }; /* Initialize the universe into something sensible. */
static __init int sctp_init(void) { int i; int status = -EINVAL; unsigned long goal; unsigned long limit; int max_share; int order; int num_entries; int max_entry_order; sock_skb_cb_check_size(sizeof(struct sctp_ulpevent)); /* Allocate bind_bucket and chunk caches. */ status = -ENOBUFS; sctp_bucket_cachep = kmem_cache_create("sctp_bind_bucket", sizeof(struct sctp_bind_bucket), 0, SLAB_HWCACHE_ALIGN, NULL); if (!sctp_bucket_cachep) goto out; sctp_chunk_cachep = kmem_cache_create("sctp_chunk", sizeof(struct sctp_chunk), 0, SLAB_HWCACHE_ALIGN, NULL); if (!sctp_chunk_cachep) goto err_chunk_cachep; status = percpu_counter_init(&sctp_sockets_allocated, 0, GFP_KERNEL); if (status) goto err_percpu_counter_init; /* Implementation specific variables. */ /* Initialize default stream count setup information. */ sctp_max_instreams = SCTP_DEFAULT_INSTREAMS; sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS; /* Initialize handle used for association ids. */ idr_init(&sctp_assocs_id); limit = nr_free_buffer_pages() / 8; limit = max(limit, 128UL); sysctl_sctp_mem[0] = limit / 4 * 3; sysctl_sctp_mem[1] = limit; sysctl_sctp_mem[2] = sysctl_sctp_mem[0] * 2; /* Set per-socket limits to no more than 1/128 the pressure threshold*/ limit = (sysctl_sctp_mem[1]) << (PAGE_SHIFT - 7); max_share = min(4UL*1024*1024, limit); sysctl_sctp_rmem[0] = SK_MEM_QUANTUM; /* give each asoc 1 page min */ sysctl_sctp_rmem[1] = 1500 * SKB_TRUESIZE(1); sysctl_sctp_rmem[2] = max(sysctl_sctp_rmem[1], max_share); sysctl_sctp_wmem[0] = SK_MEM_QUANTUM; sysctl_sctp_wmem[1] = 16*1024; sysctl_sctp_wmem[2] = max(64*1024, max_share); /* Size and allocate the association hash table. * The methodology is similar to that of the tcp hash tables. * Though not identical. Start by getting a goal size */ if (totalram_pages >= (128 * 1024)) goal = totalram_pages >> (22 - PAGE_SHIFT); else goal = totalram_pages >> (24 - PAGE_SHIFT); /* Then compute the page order for said goal */ order = get_order(goal); /* Now compute the required page order for the maximum sized table we * want to create */ max_entry_order = get_order(MAX_SCTP_PORT_HASH_ENTRIES * sizeof(struct sctp_bind_hashbucket)); /* Limit the page order by that maximum hash table size */ order = min(order, max_entry_order); /* Allocate and initialize the endpoint hash table. */ sctp_ep_hashsize = 64; sctp_ep_hashtable = kmalloc(64 * sizeof(struct sctp_hashbucket), GFP_KERNEL); if (!sctp_ep_hashtable) { pr_err("Failed endpoint_hash alloc\n"); status = -ENOMEM; goto err_ehash_alloc; } for (i = 0; i < sctp_ep_hashsize; i++) { rwlock_init(&sctp_ep_hashtable[i].lock); INIT_HLIST_HEAD(&sctp_ep_hashtable[i].chain); } /* Allocate and initialize the SCTP port hash table. * Note that order is initalized to start at the max sized * table we want to support. If we can't get that many pages * reduce the order and try again */ do { sctp_port_hashtable = (struct sctp_bind_hashbucket *) __get_free_pages(GFP_KERNEL | __GFP_NOWARN, order); } while (!sctp_port_hashtable && --order > 0); if (!sctp_port_hashtable) { pr_err("Failed bind hash alloc\n"); status = -ENOMEM; goto err_bhash_alloc; } /* Now compute the number of entries that will fit in the * port hash space we allocated */ num_entries = (1UL << order) * PAGE_SIZE / sizeof(struct sctp_bind_hashbucket); /* And finish by rounding it down to the nearest power of two * this wastes some memory of course, but its needed because * the hash function operates based on the assumption that * that the number of entries is a power of two */ sctp_port_hashsize = rounddown_pow_of_two(num_entries); for (i = 0; i < sctp_port_hashsize; i++) { spin_lock_init(&sctp_port_hashtable[i].lock); INIT_HLIST_HEAD(&sctp_port_hashtable[i].chain); } status = sctp_transport_hashtable_init(); if (status) goto err_thash_alloc; pr_info("Hash tables configured (bind %d/%d)\n", sctp_port_hashsize, num_entries); sctp_sysctl_register(); INIT_LIST_HEAD(&sctp_address_families); sctp_v4_pf_init(); sctp_v6_pf_init(); status = register_pernet_subsys(&sctp_defaults_ops); if (status) goto err_register_defaults; status = sctp_v4_protosw_init(); if (status) goto err_protosw_init; status = sctp_v6_protosw_init(); if (status) goto err_v6_protosw_init; status = register_pernet_subsys(&sctp_ctrlsock_ops); if (status) goto err_register_ctrlsock; status = sctp_v4_add_protocol(); if (status) goto err_add_protocol; /* Register SCTP with inet6 layer. */ status = sctp_v6_add_protocol(); if (status) goto err_v6_add_protocol; if (sctp_offload_init() < 0) pr_crit("%s: Cannot add SCTP protocol offload\n", __func__); out: return status; err_v6_add_protocol: sctp_v4_del_protocol(); err_add_protocol: unregister_pernet_subsys(&sctp_ctrlsock_ops); err_register_ctrlsock: sctp_v6_protosw_exit(); err_v6_protosw_init: sctp_v4_protosw_exit(); err_protosw_init: unregister_pernet_subsys(&sctp_defaults_ops); err_register_defaults: sctp_v4_pf_exit(); sctp_v6_pf_exit(); sctp_sysctl_unregister(); free_pages((unsigned long)sctp_port_hashtable, get_order(sctp_port_hashsize * sizeof(struct sctp_bind_hashbucket))); err_bhash_alloc: sctp_transport_hashtable_destroy(); err_thash_alloc: kfree(sctp_ep_hashtable); err_ehash_alloc: percpu_counter_destroy(&sctp_sockets_allocated); err_percpu_counter_init: kmem_cache_destroy(sctp_chunk_cachep); err_chunk_cachep: kmem_cache_destroy(sctp_bucket_cachep); goto out; }

Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm23931.04%38.82%
Neil Horman20326.36%25.88%
Sridhar Samudrala13217.14%514.71%
Eric W. Biedermann445.71%25.88%
Marcelo Ricardo Leitner415.32%25.88%
Vladislav Yasevich405.19%411.76%
Arnaldo Carvalho de Melo141.82%12.94%
Xin Long111.43%12.94%
Daniel Borkmann91.17%25.88%
Andrew Morton81.04%12.94%
Eric Dumazet70.91%38.82%
Wei Yongjun60.78%12.94%
Joe Perches50.65%12.94%
David S. Miller40.52%25.88%
Jan Beulich30.39%12.94%
Tejun Heo20.26%12.94%
Eyal Birger10.13%12.94%
Hideo Aoki10.13%12.94%
Total770100.00%34100.00%

/* Exit handler for the SCTP protocol. */
static __exit void sctp_exit(void) { /* BUG. This should probably do something useful like clean * up all the remaining associations and all that memory. */ /* Unregister with inet6/inet layers. */ sctp_v6_del_protocol(); sctp_v4_del_protocol(); unregister_pernet_subsys(&sctp_ctrlsock_ops); /* Free protosw registrations */ sctp_v6_protosw_exit(); sctp_v4_protosw_exit(); unregister_pernet_subsys(&sctp_defaults_ops); /* Unregister with socket layer. */ sctp_v6_pf_exit(); sctp_v4_pf_exit(); sctp_sysctl_unregister(); free_pages((unsigned long)sctp_port_hashtable, get_order(sctp_port_hashsize * sizeof(struct sctp_bind_hashbucket))); kfree(sctp_ep_hashtable); sctp_transport_hashtable_destroy(); percpu_counter_destroy(&sctp_sockets_allocated); rcu_barrier(); /* Wait for completion of call_rcu()'s */ kmem_cache_destroy(sctp_chunk_cachep); kmem_cache_destroy(sctp_bucket_cachep); }

Contributors

PersonTokensPropCommitsCommitProp
Sridhar Samudrala3031.91%426.67%
Jon Grimm2122.34%213.33%
Vladislav Yasevich1212.77%16.67%
Eric W. Biedermann1111.70%213.33%
Marcelo Ricardo Leitner77.45%16.67%
Xin Long66.38%213.33%
Jesper Dangaard Brouer44.26%16.67%
David S. Miller22.13%16.67%
Daniel Borkmann11.06%16.67%
Total94100.00%15100.00%

module_init(sctp_init); module_exit(sctp_exit); /* * __stringify doesn't likes enums, so use IPPROTO_SCTP value (132) directly. */ MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-132"); MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-132"); MODULE_AUTHOR("Linux Kernel SCTP developers <linux-sctp@vger.kernel.org>"); MODULE_DESCRIPTION("Support for the SCTP protocol (RFC2960)"); module_param_named(no_checksums, sctp_checksum_disable, bool, 0644); MODULE_PARM_DESC(no_checksums, "Disable checksums computing and verification"); MODULE_LICENSE("GPL");

Overall Contributors

PersonTokensPropCommitsCommitProp
Jon Grimm212132.01%2210.28%
Sridhar Samudrala112316.95%209.35%
Eric W. Biedermann82212.41%146.54%
Michio Honda6279.46%20.93%
Vladislav Yasevich4937.44%136.07%
Neil Horman2894.36%73.27%
Marcelo Ricardo Leitner2553.85%83.74%
David S. Miller1372.07%167.48%
Arnaldo Carvalho de Melo1231.86%136.07%
Xin Long911.37%94.21%
Wei Yongjun610.92%31.40%
Daniel Borkmann490.74%41.87%
Joe Perches390.59%20.93%
Eric Dumazet360.54%136.07%
Al Viro330.50%125.61%
Xufeng Zhang330.50%10.47%
Herbert Xu270.41%20.93%
Brian Haley270.41%20.93%
Jason Gunthorpe220.33%10.47%
Ravikiran G. Thirumalai200.30%10.47%
Américo Wang190.29%10.47%
Hideaki Yoshifuji / 吉藤英明150.23%62.80%
Pavel Emelyanov140.21%31.40%
Gui Jianfeng140.21%10.47%
Florian Westphal130.20%10.47%
Harvey Harrison120.18%20.93%
Denis V. Lunev110.17%41.87%
Zhu Yanjun90.14%10.47%
Daniel C. Halperin80.12%10.47%
Andrew Morton80.12%10.47%
Thomas Graf70.11%10.47%
Chidambar 'ilLogict' Zinnoury60.09%10.47%
Hannes Frederic Sowa50.08%10.47%
Tom Lendacky50.08%10.47%
Tejun Heo50.08%20.93%
Vincent Bernat40.06%10.47%
Alexey Dobriyan40.06%20.93%
Christoph Lameter40.06%10.47%
David Howells40.06%10.47%
Jesper Dangaard Brouer40.06%10.47%
Thomas Gleixner40.06%10.47%
Jan Beulich30.05%10.47%
Christoph Paasch30.05%10.47%
Rusty Russell20.03%10.47%
Lai Jiangshan20.03%10.47%
Wang Weidong20.03%10.47%
Randy Dunlap20.03%10.47%
Jeff Kirsher10.02%10.47%
Adrian Bunk10.02%10.47%
Stephen Hemminger10.02%10.47%
Bhaskar Dutta10.02%10.47%
Hideo Aoki10.02%10.47%
Patrick McHardy10.02%10.47%
Dave Jones10.02%10.47%
Eyal Birger10.02%10.47%
Steven Cole10.02%10.47%
Total6626100.00%214100.00%
Directory: net/sctp
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.