Something went wrong. Try again.
Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726// SPDX-License-Identifier: GPL-2.0-or-later/* 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. * * 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/memblock.h>#include <linux/highmem.h>#include <linux/slab.h>#include <net/flow.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>#include <net/inet_sock.h>#include <net/udp_tunnel.h>#include <net/inet_dscp.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];
/* 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; }
in_dev_for_each_ifa_rcu(ifa, in_dev) { /* Add the address to the local list. */ addr = kzalloc_obj(*addr, GFP_ATOMIC); if (addr) { addr->a.v4.sin_family = AF_INET; 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();}
/* 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();}
/* 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); }}
/* 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_ALLOWED) || !(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;}
/* Copy over any ip options */static void sctp_v4_copy_ip_options(struct sock *sk, struct sock *newsk){ struct inet_sock *newinet, *inet = inet_sk(sk); struct ip_options_rcu *inet_opt, *newopt = NULL;
newinet = inet_sk(newsk);
rcu_read_lock(); inet_opt = rcu_dereference(inet->inet_opt); if (inet_opt) { newopt = sock_kmemdup(newsk, inet_opt, sizeof(*inet_opt) + inet_opt->opt.optlen, GFP_ATOMIC); if (!newopt) pr_err("%s: Failed to copy ip options\n", __func__); } RCU_INIT_POINTER(newinet->inet_opt, newopt); rcu_read_unlock();}
/* Account for the IP options */static int sctp_v4_ip_options_len(struct sock *sk){ struct inet_sock *inet = inet_sk(sk); struct ip_options_rcu *inet_opt; int len = 0;
rcu_read_lock(); inet_opt = rcu_dereference(inet->inet_opt); if (inet_opt) len = inet_opt->opt.optlen;
rcu_read_unlock(); return len;}
/* 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; } memset(sa->sin_zero, 0, sizeof(sa->sin_zero));}
/* 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; memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero));}
/* 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;}
/* 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;}
/* Initialize a sctp_addr from an address parameter. */static bool sctp_v4_from_addr_param(union sctp_addr *addr, union sctp_addr_param *param, __be16 port, int iif){ if (ntohs(param->v4.param_hdr.length) < sizeof(struct sctp_ipv4addr_param)) return false;
addr->v4.sin_family = AF_INET; addr->v4.sin_port = port; addr->v4.sin_addr.s_addr = param->v4.addr.s_addr; memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero));
return true;}
/* 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;}
/* 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; memset(saddr->v4.sin_zero, 0, sizeof(saddr->v4.sin_zero));}
/* 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;}
/* 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; memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero));}
/* 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;}
/* 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;}
/* Should this be available for binding? */static int sctp_v4_available(union sctp_addr *addr, struct sctp_sock *sp){ struct sock *sk = &sp->inet.sk; struct net *net = sock_net(sk); int tb_id = RT_TABLE_LOCAL; int ret;
tb_id = l3mdev_fib_table_by_index(net, sk->sk_bound_dev_if) ?: tb_id; ret = inet_addr_type_table(net, addr->v4.sin_addr.s_addr, tb_id); if (addr->v4.sin_addr.s_addr != htonl(INADDR_ANY) && ret != RTN_LOCAL && !inet_test_bit(FREEBIND, sk) && !READ_ONCE(net->ipv4.sysctl_ip_nonlocal_bind)) return 0;
if (ipv6_only_sock(sctp_opt2sk(sp))) return 0;
return 1;}
/* 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 * 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) || ipv4_is_test_198(addr->v4.sin_addr.s_addr)) { retval = SCTP_SCOPE_PRIVATE; } else { retval = SCTP_SCOPE_GLOBAL; }
return retval;}
/* 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 flowi _fl; 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; dscp_t dscp;
if (t->dscp & SCTP_DSCP_SET_MASK) dscp = inet_dsfield_to_dscp(t->dscp); else dscp = inet_sk_dscp(inet_sk(sk));
memset(&_fl, 0x0, sizeof(_fl)); fl4->daddr = daddr->v4.sin_addr.s_addr; fl4->fl4_dport = daddr->v4.sin_port; fl4->flowi4_proto = IPPROTO_SCTP; if (asoc) { fl4->flowi4_dscp = dscp; fl4->flowi4_scope = ip_sock_rt_scope(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; if (!fl4->fl4_sport) 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; t->dst = dst; memcpy(fl, &_fl, sizeof(_fl)); }
/* 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, 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;
/* 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 (!dst) { dst = &rt->dst; t->dst = dst; memcpy(fl, &_fl, sizeof(_fl)); } else { dst_release(&rt->dst); } continue; }
dst_release(dst); dst = &rt->dst; t->dst = dst; memcpy(fl, &_fl, sizeof(_fl)); break; }
out_unlock: rcu_read_unlock();out: if (dst) { pr_debug("rt_dst:%pI4, rt_src:%pI4\n", &fl->u.ip4.daddr, &fl->u.ip4.saddr); } else { t->dst = NULL; pr_debug("no route\n"); }}
/* 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 = dst_rtable(t->dst);
if (rt) { saddr->v4.sin_family = AF_INET; saddr->v4.sin_addr.s_addr = fl->u.ip4.saddr; }}
/* What interface did this skb arrive on? */static int sctp_v4_skb_iif(const struct sk_buff *skb){ return inet_iif(skb);}
static int sctp_v4_skb_sdif(const struct sk_buff *skb){ return inet_sdif(skb);}
/* 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);}
static int sctp_v4_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr){ /* No address mapping for V4 sockets */ memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero)); return sizeof(struct sockaddr_in);}
/* 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);}
static void sctp_v4_ecn_capable(struct sock *sk){ INET_ECN_xmit(sk);}
static void sctp_addr_wq_timeout_handler(struct timer_list *t){ struct net *net = timer_container_of(net, t, sctp.addr_wq_timer); 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);}
static void sctp_free_addr_wq(struct net *net){ struct sctp_sockaddr_entry *addrw; struct sctp_sockaddr_entry *temp;
timer_shutdown_sync(&net->sctp.addr_wq_timer);
spin_lock_bh(&net->sctp.addr_wq_lock); 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);}
/* 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;}
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);
/* Avoid searching the queue or modifying it if there are no consumers, * as it can lead to performance degradation if addresses are modified * en-masse. * * If the queue already contains some events, update it anyway to avoid * ugly races between new sessions and new address events. */ if (list_empty(&net->sctp.auto_asconf_splist) && list_empty(&net->sctp.addr_waitq)) { spin_unlock_bh(&net->sctp.addr_wq_lock); return; }
/* 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);}
/* 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 = kzalloc_obj(*addr, GFP_ATOMIC); if (addr) { addr->a.v4.sin_family = AF_INET; 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) { found = 1; addr->valid = 0; list_del_rcu(&addr->list); sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL); break; } } spin_unlock_bh(&net->sctp.local_addr_lock); if (found) kfree_rcu(addr, rcu); break; }
return NOTIFY_DONE;}
/* * 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;}
static int sctp_udp_rcv(struct sock *sk, struct sk_buff *skb){ SCTP_INPUT_CB(skb)->encap_port = udp_hdr(skb)->source;
skb_set_transport_header(skb, sizeof(struct udphdr)); sctp_rcv(skb); return 0;}
int sctp_udp_sock_start(struct net *net){ struct udp_tunnel_sock_cfg tuncfg = {NULL}; struct udp_port_cfg udp_conf = {0}; struct socket *sock; int err;
udp_conf.family = AF_INET; udp_conf.local_ip.s_addr = htonl(INADDR_ANY); udp_conf.local_udp_port = htons(net->sctp.udp_port); err = udp_sock_create(net, &udp_conf, &sock); if (err) { pr_err("Failed to create the SCTP UDP tunneling v4 sock\n"); return err; }
tuncfg.encap_type = 1; tuncfg.encap_rcv = sctp_udp_rcv; tuncfg.encap_err_lookup = sctp_udp_v4_err; setup_udp_tunnel_sock(net, sock->sk, &tuncfg); net->sctp.udp4_sock = sock->sk;
#if IS_ENABLED(CONFIG_IPV6) memset(&udp_conf, 0, sizeof(udp_conf));
udp_conf.family = AF_INET6; udp_conf.local_ip6 = in6addr_any; udp_conf.local_udp_port = htons(net->sctp.udp_port); udp_conf.use_udp6_rx_checksums = true; udp_conf.ipv6_v6only = true; err = udp_sock_create(net, &udp_conf, &sock); if (err) { pr_err("Failed to create the SCTP UDP tunneling v6 sock\n"); udp_tunnel_sock_release(net->sctp.udp4_sock); net->sctp.udp4_sock = NULL; return err; }
tuncfg.encap_type = 1; tuncfg.encap_rcv = sctp_udp_rcv; tuncfg.encap_err_lookup = sctp_udp_v6_err; setup_udp_tunnel_sock(net, sock->sk, &tuncfg); net->sctp.udp6_sock = sock->sk;#endif
return 0;}
void sctp_udp_sock_stop(struct net *net){ if (net->sctp.udp4_sock) { udp_tunnel_sock_release(net->sctp.udp4_sock); net->sctp.udp4_sock = NULL; } if (net->sctp.udp6_sock) { udp_tunnel_sock_release(net->sctp.udp6_sock); net->sctp.udp6_sock = NULL; }}
/* 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;}
/* 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; }}
/* 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));}
/* 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; }}
/* 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; }}
/* 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;}
/* 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;}
/* 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);}
/* 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;}
/* 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;}
/* Wrapper routine that calls the ip transmit routine. */static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *t){ struct dst_entry *dst = dst_clone(t->dst); struct flowi4 *fl4 = &t->fl.u.ip4; struct sock *sk = skb->sk; struct inet_sock *inet = inet_sk(sk); __u8 dscp = READ_ONCE(inet->tos); __be16 df = 0;
pr_debug("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n", __func__, skb, skb->len, &fl4->saddr, &fl4->daddr);
if (t->dscp & SCTP_DSCP_SET_MASK) dscp = t->dscp & SCTP_DSCP_VAL_MASK;
inet->pmtudisc = t->param_flags & SPP_PMTUD_ENABLE ? IP_PMTUDISC_DO : IP_PMTUDISC_DONT; SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
if (!t->encap_port || !sctp_sk(sk)->udp_port) { skb_dst_set(skb, dst); return __ip_queue_xmit(sk, skb, &t->fl, dscp); }
if (skb_is_gso(skb)) skb_shinfo(skb)->gso_type |= SKB_GSO_UDP_TUNNEL_CSUM;
if (ip_dont_fragment(sk, dst) && !skb->ignore_df) df = htons(IP_DF);
skb->encapsulation = 1; skb_reset_inner_mac_header(skb); skb_reset_inner_transport_header(skb); skb_set_inner_ipproto(skb, IPPROTO_SCTP); local_bh_disable(); udp_tunnel_xmit_skb(dst_rtable(dst), sk, skb, fl4->saddr, fl4->daddr, dscp, ip4_dst_hoplimit(dst), df, sctp_sk(sk)->udp_port, t->encap_port, false, false, 0); local_bh_enable(); return 0;}
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, .addr_to_user = sctp_v4_addr_to_user, .to_sk_saddr = sctp_v4_to_sk_saddr, .to_sk_daddr = sctp_v4_to_sk_daddr, .copy_ip_options = sctp_v4_copy_ip_options, .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 = sctp_inet_connect, .socketpair = sock_no_socketpair, .accept = inet_accept, .getname = inet_getname, /* Semantics are different. */ .poll = sctp_poll, .ioctl = inet_ioctl, .gettstamp = sock_gettstamp, .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,};
/* 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};
static int sctp4_rcv(struct sk_buff *skb){ SCTP_INPUT_CB(skb)->encap_port = 0; return sctp_rcv(skb);}
/* Register with IP layer. */static const struct net_protocol sctp_protocol = { .handler = sctp4_rcv, .err_handler = sctp_v4_err, .no_policy = 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, .skb_sdif = sctp_v4_skb_sdif, .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), .ip_options_len = sctp_v4_ip_options_len,};
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; }}
/* 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;}
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;}
static inline void cleanup_sctp_mibs(struct net *net){ free_percpu(net->sctp.sctp_statistics);}
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);}
static void sctp_v4_pf_exit(void){ list_del(&sctp_af_inet.list);}
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;}
static void sctp_v4_protosw_exit(void){ inet_unregister_protosw(&sctp_stream_protosw); inet_unregister_protosw(&sctp_seqpacket_protosw); proto_unregister(&sctp_prot);}
static int sctp_v4_add_protocol(void){ int ret;
/* Register notifier for inet address additions/deletions. */ ret = register_inetaddr_notifier(&sctp_inetaddr_notifier); if (ret) return ret;
/* Register SCTP with inet layer. */ if (inet_add_protocol(&sctp_protocol, IPPROTO_SCTP) < 0) { unregister_inetaddr_notifier(&sctp_inetaddr_notifier); return -EAGAIN; }
return 0;}
static void sctp_v4_del_protocol(void){ inet_del_protocol(&sctp_protocol, IPPROTO_SCTP); unregister_inetaddr_notifier(&sctp_inetaddr_notifier);}
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;
/* Whether cookie authentication is enabled(1) or not(0) */ net->sctp.cookie_auth_enable = !IS_ENABLED(CONFIG_SCTP_DEFAULT_COOKIE_HMAC_NONE);
/* Max.Burst - 4 */ net->sctp.max_burst = SCTP_DEFAULT_MAX_BURST;
/* Disable of Primary Path Switchover by default */ net->sctp.ps_retrans = SCTP_PS_RETRANS_MAX;
/* Enable pf state by default */ net->sctp.pf_enable = 1;
/* Ignore pf exposure feature by default */ net->sctp.pf_expose = SCTP_PF_EXPOSE_UNSET;
/* 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;
/* Enable ECN by default. */ net->sctp.ecn_enable = 1;
/* Set UDP tunneling listening port to 0 by default */ net->sctp.udp_port = 0;
/* Set remote encap port to 0 by default */ net->sctp.encap_port = 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;
#ifdef CONFIG_NET_L3_MASTER_DEV net->sctp.l3mdev_accept = 1;#endif
/* Allocate and initialise sctp mibs. */ status = init_sctp_mibs(net); if (status) goto err_init_mibs;
#ifdef CONFIG_PROC_FS /* Initialize proc fs directory. */ status = sctp_proc_init(net); if (status) goto err_init_proc;#endif
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; timer_setup(&net->sctp.addr_wq_timer, sctp_addr_wq_timeout_handler, 0);
return 0;
#ifdef CONFIG_PROC_FSerr_init_proc: cleanup_sctp_mibs(net);#endiferr_init_mibs: return status;}
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);
#ifdef CONFIG_PROC_FS remove_proc_subtree("sctp", net->proc_net); net->sctp.proc_net_sctp = NULL;#endif cleanup_sctp_mibs(net);}
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; }
status = sctp_sysctl_net_register(net); if (status) { inet_ctl_sock_destroy(net->sctp.ctl_sock); net->sctp.ctl_sock = NULL; }
return status;}
static void __net_exit sctp_ctrlsock_exit(struct net *net){ sctp_sysctl_net_unregister(net); sctp_udp_sock_stop(net);
/* Free the control endpoint. */ inet_ctl_sock_destroy(net->sctp.ctl_sock); net->sctp.ctl_sock = NULL;}
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){ unsigned long nr_pages = totalram_pages(); unsigned long limit; unsigned long goal; int max_entry_order; int num_entries; int max_share; int status; int order; int i;
sock_skb_cb_check_size(sizeof(struct sctp_ulpevent));
/* Allocate bind_bucket and chunk caches. */ status = -ENOBUFS; sctp_bucket_cachep = KMEM_CACHE(sctp_bind_bucket, SLAB_HWCACHE_ALIGN); if (!sctp_bucket_cachep) goto out;
sctp_chunk_cachep = KMEM_CACHE(sctp_chunk, SLAB_HWCACHE_ALIGN); 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] = PAGE_SIZE; /* 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] = PAGE_SIZE; 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 (nr_pages >= (128 * 1024)) goal = nr_pages >> (22 - PAGE_SHIFT); else goal = nr_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_objs(struct sctp_hashbucket, 64); 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 it's needed because * the hash function operates based on the assumption 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(); sctp_sched_ops_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;}
/* 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);}
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");