Release 4.11 net/sctp/protocol.c
/* 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
Person | Tokens | Prop | Commits | CommitProp |
Eric W. Biedermann | 55 | 39.57% | 2 | 13.33% |
Sridhar Samudrala | 25 | 17.99% | 3 | 20.00% |
Wei Yongjun | 20 | 14.39% | 1 | 6.67% |
Jon Grimm | 13 | 9.35% | 1 | 6.67% |
Florian Westphal | 8 | 5.76% | 1 | 6.67% |
Neil Horman | 6 | 4.32% | 1 | 6.67% |
David S. Miller | 4 | 2.88% | 1 | 6.67% |
Alexey Dobriyan | 3 | 2.16% | 1 | 6.67% |
Randy Dunlap | 2 | 1.44% | 1 | 6.67% |
Eric Dumazet | 1 | 0.72% | 1 | 6.67% |
Christoph Paasch | 1 | 0.72% | 1 | 6.67% |
Pavel Emelyanov | 1 | 0.72% | 1 | 6.67% |
Total | 139 | 100.00% | 15 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Eric W. Biedermann | 28 | 52.83% | 2 | 22.22% |
Jon Grimm | 11 | 20.75% | 1 | 11.11% |
Sridhar Samudrala | 7 | 13.21% | 3 | 33.33% |
Florian Westphal | 5 | 9.43% | 1 | 11.11% |
David S. Miller | 1 | 1.89% | 1 | 11.11% |
Neil Horman | 1 | 1.89% | 1 | 11.11% |
Total | 53 | 100.00% | 9 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 122 | 80.26% | 4 | 44.44% |
Vladislav Yasevich | 14 | 9.21% | 1 | 11.11% |
David S. Miller | 6 | 3.95% | 1 | 11.11% |
Daniel Borkmann | 6 | 3.95% | 1 | 11.11% |
Al Viro | 3 | 1.97% | 1 | 11.11% |
Herbert Xu | 1 | 0.66% | 1 | 11.11% |
Total | 152 | 100.00% | 9 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 52 | 70.27% | 3 | 30.00% |
Eric W. Biedermann | 11 | 14.86% | 2 | 20.00% |
Eric Dumazet | 5 | 6.76% | 1 | 10.00% |
Pavel Emelyanov | 3 | 4.05% | 1 | 10.00% |
Sridhar Samudrala | 2 | 2.70% | 2 | 20.00% |
Dave Jones | 1 | 1.35% | 1 | 10.00% |
Total | 74 | 100.00% | 10 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 47 | 83.93% | 2 | 33.33% |
Eric W. Biedermann | 5 | 8.93% | 1 | 16.67% |
Rusty Russell | 2 | 3.57% | 1 | 16.67% |
Sridhar Samudrala | 1 | 1.79% | 1 | 16.67% |
David S. Miller | 1 | 1.79% | 1 | 16.67% |
Total | 56 | 100.00% | 6 | 100.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,
sctp_scope_t 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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 96 | 49.74% | 5 | 26.32% |
Xin Long | 56 | 29.02% | 3 | 15.79% |
Vladislav Yasevich | 18 | 9.33% | 2 | 10.53% |
Eric W. Biedermann | 8 | 4.15% | 2 | 10.53% |
Marcelo Ricardo Leitner | 7 | 3.63% | 1 | 5.26% |
Al Viro | 5 | 2.59% | 3 | 15.79% |
Sridhar Samudrala | 2 | 1.04% | 2 | 10.53% |
David S. Miller | 1 | 0.52% | 1 | 5.26% |
Total | 193 | 100.00% | 19 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 65 | 65.66% | 1 | 33.33% |
Marcelo Ricardo Leitner | 28 | 28.28% | 1 | 33.33% |
Arnaldo Carvalho de Melo | 6 | 6.06% | 1 | 33.33% |
Total | 99 | 100.00% | 3 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 45 | 95.74% | 1 | 33.33% |
Al Viro | 1 | 2.13% | 1 | 33.33% |
Eric Dumazet | 1 | 2.13% | 1 | 33.33% |
Total | 47 | 100.00% | 3 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 29 | 93.55% | 1 | 33.33% |
Eric Dumazet | 1 | 3.23% | 1 | 33.33% |
Sridhar Samudrala | 1 | 3.23% | 1 | 33.33% |
Total | 31 | 100.00% | 3 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 30 | 96.77% | 1 | 50.00% |
Eric Dumazet | 1 | 3.23% | 1 | 50.00% |
Total | 31 | 100.00% | 2 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 53 | 98.15% | 1 | 50.00% |
Al Viro | 1 | 1.85% | 1 | 50.00% |
Total | 54 | 100.00% | 2 | 100.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(sctp_ipv4addr_param_t);
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
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 66 | 98.51% | 1 | 50.00% |
Al Viro | 1 | 1.49% | 1 | 50.00% |
Total | 67 | 100.00% | 2 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 26 | 55.32% | 2 | 33.33% |
Sridhar Samudrala | 16 | 34.04% | 2 | 33.33% |
David S. Miller | 4 | 8.51% | 1 | 16.67% |
Al Viro | 1 | 2.13% | 1 | 16.67% |
Total | 47 | 100.00% | 6 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 70 | 92.11% | 2 | 66.67% |
Sridhar Samudrala | 6 | 7.89% | 1 | 33.33% |
Total | 76 | 100.00% | 3 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 39 | 90.70% | 2 | 50.00% |
Al Viro | 4 | 9.30% | 2 | 50.00% |
Total | 43 | 100.00% | 4 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 23 | 88.46% | 1 | 50.00% |
Al Viro | 3 | 11.54% | 1 | 50.00% |
Total | 26 | 100.00% | 2 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Vladislav Yasevich | 36 | 48.00% | 2 | 33.33% |
Jon Grimm | 35 | 46.67% | 2 | 33.33% |
Eric Dumazet | 3 | 4.00% | 1 | 16.67% |
Arnaldo Carvalho de Melo | 1 | 1.33% | 1 | 16.67% |
Total | 75 | 100.00% | 6 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 51 | 51.52% | 2 | 22.22% |
Eric W. Biedermann | 17 | 17.17% | 2 | 22.22% |
Vladislav Yasevich | 13 | 13.13% | 1 | 11.11% |
Neil Horman | 10 | 10.10% | 1 | 11.11% |
Vincent Bernat | 4 | 4.04% | 1 | 11.11% |
Al Viro | 3 | 3.03% | 1 | 11.11% |
Arnaldo Carvalho de Melo | 1 | 1.01% | 1 | 11.11% |
Total | 99 | 100.00% | 9 | 100.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 sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
{
sctp_scope_t 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
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 83 | 65.87% | 1 | 33.33% |
Joe Perches | 25 | 19.84% | 1 | 33.33% |
Jon Grimm | 18 | 14.29% | 1 | 33.33% |
Total | 126 | 100.00% | 3 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 218 | 36.27% | 4 | 12.50% |
Marcelo Ricardo Leitner | 93 | 15.47% | 4 | 12.50% |
Vladislav Yasevich | 90 | 14.98% | 4 | 12.50% |
David S. Miller | 52 | 8.65% | 4 | 12.50% |
Wei Yongjun | 35 | 5.82% | 1 | 3.12% |
Xufeng Zhang | 33 | 5.49% | 1 | 3.12% |
Jon Grimm | 28 | 4.66% | 4 | 12.50% |
Gui Jianfeng | 14 | 2.33% | 1 | 3.12% |
Michio Honda | 13 | 2.16% | 1 | 3.12% |
Eric W. Biedermann | 8 | 1.33% | 1 | 3.12% |
Harvey Harrison | 6 | 1.00% | 2 | 6.25% |
Daniel Borkmann | 5 | 0.83% | 1 | 3.12% |
Al Viro | 4 | 0.67% | 3 | 9.38% |
Denis V. Lunev | 2 | 0.33% | 1 | 3.12% |
Total | 601 | 100.00% | 32 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 49 | 65.33% | 3 | 42.86% |
Vladislav Yasevich | 14 | 18.67% | 1 | 14.29% |
David S. Miller | 6 | 8.00% | 1 | 14.29% |
Hideaki Yoshifuji / 吉藤英明 | 5 | 6.67% | 1 | 14.29% |
Jon Grimm | 1 | 1.33% | 1 | 14.29% |
Total | 75 | 100.00% | 7 | 100.00% |
/* What interface did this skb arrive on? */
static int sctp_v4_skb_iif(const struct sk_buff *skb)
{
return inet_iif(skb);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 15 | 83.33% | 2 | 50.00% |
Eric Dumazet | 2 | 11.11% | 1 | 25.00% |
David S. Miller | 1 | 5.56% | 1 | 25.00% |
Total | 18 | 100.00% | 4 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 20 | 86.96% | 1 | 50.00% |
Arnaldo Carvalho de Melo | 3 | 13.04% | 1 | 50.00% |
Total | 23 | 100.00% | 2 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 95 | 70.37% | 2 | 14.29% |
Arnaldo Carvalho de Melo | 11 | 8.15% | 5 | 35.71% |
Vladislav Yasevich | 11 | 8.15% | 1 | 7.14% |
Thomas Graf | 7 | 5.19% | 1 | 7.14% |
David Howells | 4 | 2.96% | 1 | 7.14% |
Hideaki Yoshifuji / 吉藤英明 | 3 | 2.22% | 1 | 7.14% |
Eric W. Biedermann | 3 | 2.22% | 2 | 14.29% |
Eric Dumazet | 1 | 0.74% | 1 | 7.14% |
Total | 135 | 100.00% | 14 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 13 | 54.17% | 1 | 33.33% |
Jason Gunthorpe | 10 | 41.67% | 1 | 33.33% |
Arnaldo Carvalho de Melo | 1 | 4.17% | 1 | 33.33% |
Total | 24 | 100.00% | 3 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 28 | 93.33% | 1 | 50.00% |
Harvey Harrison | 2 | 6.67% | 1 | 50.00% |
Total | 30 | 100.00% | 2 | 100.00% |
static void sctp_v4_ecn_capable(struct sock *sk)
{
INET_ECN_xmit(sk);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vladislav Yasevich | 16 | 100.00% | 1 | 100.00% |
Total | 16 | 100.00% | 1 | 100.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
Person | Tokens | Prop | Commits | CommitProp |
Michio Honda | 234 | 77.23% | 1 | 12.50% |
Eric W. Biedermann | 35 | 11.55% | 1 | 12.50% |
Daniel Borkmann | 15 | 4.95% | 1 | 12.50% |
Daniel C. Halperin | 8 | 2.64% | 1 | 12.50% |
David S. Miller | 7 | 2.31% | 1 | 12.50% |
Wang Weidong | 2 | 0.66% | 1 | 12.50% |
Stephen Hemminger | 1 | 0.33% | 1 | 12.50% |
Eric Dumazet | 1 | 0.33% | 1 | 12.50% |
Total | 303 | 100.00% | 8 | 100.00% |
static void sctp_free_addr_wq(