--- zzzz-none-000/linux-3.10.107/net/sctp/protocol.c 2017-06-27 09:49:32.000000000 +0000
+++ scorpion-7490-727/linux-3.10.107/net/sctp/protocol.c 2021-02-04 17:41:59.000000000 +0000
@@ -23,16 +23,12 @@
* 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, write to
- * the Free Software Foundation, 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * along with GNU CC; see the file COPYING. If not, see
+ * .
*
* Please send any bug reports or fixes you make to the
* email address(es):
- * lksctp developers
- *
- * Or submit a bug report through the following website:
- * http://www.sf.net/projects/lksctp
+ * lksctp developers
*
* Written or modified by:
* La Monte H.P. Yarroll
@@ -41,9 +37,6 @@
* Sridhar Samudrala
* Daisy Chang
* Ardelle Fan
- *
- * Any bugs reported given to us we will try to fix... any fixes shared will
- * be incorporated into the next SCTP release.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -67,6 +60,8 @@
#include
#include
+#define MAX_SCTP_PORT_HASH_ENTRIES (64 * 1024)
+
/* Global data structures. */
struct sctp_globals sctp_globals __read_mostly;
@@ -153,7 +148,7 @@
for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next) {
/* Add the address to the local list. */
- addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC);
+ addr = kzalloc(sizeof(*addr), GFP_ATOMIC);
if (addr) {
addr->a.v4.sin_family = AF_INET;
addr->a.v4.sin_port = 0;
@@ -178,7 +173,7 @@
rcu_read_lock();
for_each_netdev_rcu(net, dev) {
- __list_for_each(pos, &sctp_address_families) {
+ list_for_each(pos, &sctp_address_families) {
af = list_entry(pos, struct sctp_af, list);
af->copy_addrlist(&net->sctp.local_addr_list, dev);
}
@@ -373,7 +368,7 @@
if (addr->v4.sin_addr.s_addr != htonl(INADDR_ANY) &&
ret != RTN_LOCAL &&
!sp->inet.freebind &&
- !sysctl_ip_nonlocal_bind)
+ !net->ipv4.sysctl_ip_nonlocal_bind)
return 0;
if (ipv6_only_sock(sctp_opt2sk(sp)))
@@ -451,8 +446,8 @@
fl4->fl4_sport = saddr->v4.sin_port;
}
- SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ",
- __func__, &fl4->daddr, &fl4->saddr);
+ 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))
@@ -494,23 +489,43 @@
*/
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)) {
- 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)) {
- dst = &rt->dst;
- goto out_unlock;
- }
+ 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:
@@ -518,10 +533,10 @@
out:
t->dst = dst;
if (dst)
- SCTP_DEBUG_PRINTK("rt_dst:%pI4, rt_src:%pI4\n",
- &fl4->daddr, &fl4->saddr);
+ pr_debug("rt_dst:%pI4, rt_src:%pI4\n",
+ &fl4->daddr, &fl4->saddr);
else
- SCTP_DEBUG_PRINTK("NO ROUTE\n");
+ pr_debug("no route\n");
}
/* For v4, the source address is cached in the route entry(dst). So no need
@@ -557,7 +572,7 @@
struct sctp_association *asoc)
{
struct sock *newsk = sk_alloc(sock_net(sk), PF_INET, GFP_KERNEL,
- sk->sk_prot);
+ sk->sk_prot, 0);
struct inet_sock *newinet;
if (!newsk)
@@ -583,10 +598,10 @@
return newsk;
}
-/* Map address, empty for v4 family */
-static void sctp_v4_addr_v4map(struct sctp_sock *sp, union sctp_addr *addr)
+static int sctp_v4_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr)
{
- /* Empty */
+ /* No address mapping for V4 sockets */
+ return sizeof(struct sockaddr_in);
}
/* Dump the v4 addr to the seq file. */
@@ -609,9 +624,9 @@
spin_lock_bh(&net->sctp.addr_wq_lock);
list_for_each_entry_safe(addrw, temp, &net->sctp.addr_waitq, list) {
- SCTP_DEBUG_PRINTK_IPADDR("sctp_addrwq_timo_handler: the first ent in wq %p is ",
- " for cmd %d at entry %p\n", &net->sctp.addr_waitq, &addrw->a, addrw->state,
- addrw);
+ 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 */
@@ -628,8 +643,10 @@
addrw->state == SCTP_ADDR_NEW) {
unsigned long timeo_val;
- SCTP_DEBUG_PRINTK("sctp_timo_handler: this is on DAD, trying %d sec later\n",
- SCTP_ADDRESS_TICK_DELAY);
+ 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);
@@ -644,10 +661,10 @@
/* ignore bound-specific endpoints */
if (!sctp_is_ep_boundall(sk))
continue;
- sctp_bh_lock_sock(sk);
+ bh_lock_sock(sk);
if (sctp_asconf_mgmt(sp, addrw) < 0)
- SCTP_DEBUG_PRINTK("sctp_addrwq_timo_handler: sctp_asconf_mgmt failed\n");
- sctp_bh_unlock_sock(sk);
+ pr_debug("%s: sctp_asconf_mgmt failed\n", __func__);
+ bh_unlock_sock(sk);
}
#if IS_ENABLED(CONFIG_IPV6)
free_next:
@@ -712,9 +729,10 @@
addrw = sctp_addr_wq_lookup(net, addr);
if (addrw) {
if (addrw->state != cmd) {
- SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt offsets existing entry for %d ",
- " in wq %p\n", addrw->state, &addrw->a,
- &net->sctp.addr_waitq);
+ 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);
}
@@ -730,8 +748,9 @@
}
addrw->state = cmd;
list_add_tail(&addrw->list, &net->sctp.addr_waitq);
- SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt add new entry for cmd:%d ",
- " in wq %p\n", addrw->state, &addrw->a, &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;
@@ -957,16 +976,15 @@
{
struct inet_sock *inet = inet_sk(skb->sk);
- SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI4, dst:%pI4\n",
- __func__, skb, skb->len,
- &transport->fl.u.ip4.saddr,
- &transport->fl.u.ip4.daddr);
+ 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(skb, &transport->fl);
+
+ return ip_queue_xmit(&inet->sk, skb, &transport->fl);
}
static struct sctp_af sctp_af_inet;
@@ -980,7 +998,9 @@
.send_verify = sctp_inet_send_verify,
.supported_addrs = sctp_inet_supported_addrs,
.create_accept_sk = sctp_v4_create_accept_sk,
- .addr_v4map = sctp_v4_addr_v4map,
+ .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
};
@@ -1021,7 +1041,6 @@
.protocol = IPPROTO_SCTP,
.prot = &sctp_prot,
.ops = &inet_seqpacket_ops,
- .no_check = 0,
.flags = SCTP_PROTOSW_FLAG
};
static struct inet_protosw sctp_stream_protosw = {
@@ -1029,7 +1048,6 @@
.protocol = IPPROTO_SCTP,
.prot = &sctp_prot,
.ops = &inet_seqpacket_ops,
- .no_check = 0,
.flags = SCTP_PROTOSW_FLAG
};
@@ -1039,6 +1057,7 @@
.err_handler = sctp_v4_err,
.no_policy = 1,
.netns_ok = 1,
+ .icmp_strict_tag_validation = 1,
};
/* IPv4 address related functions. */
@@ -1052,8 +1071,6 @@
.copy_addrlist = sctp_v4_copy_addrlist,
.from_skb = sctp_v4_from_skb,
.from_sk = sctp_v4_from_sk,
- .to_sk_saddr = sctp_v4_to_sk_saddr,
- .to_sk_daddr = sctp_v4_to_sk_daddr,
.from_addr_param = sctp_v4_from_addr_param,
.to_addr_param = sctp_v4_to_addr_param,
.cmp_addr = sctp_v4_cmp_addr,
@@ -1074,8 +1091,8 @@
#endif
};
-struct sctp_pf *sctp_get_pf_specific(sa_family_t family) {
-
+struct sctp_pf *sctp_get_pf_specific(sa_family_t family)
+{
switch (family) {
case PF_INET:
return sctp_pf_inet_specific;
@@ -1108,14 +1125,15 @@
static inline int init_sctp_mibs(struct net *net)
{
- return snmp_mib_init((void __percpu **)net->sctp.sctp_statistics,
- sizeof(struct sctp_mib),
- __alignof__(struct sctp_mib));
+ 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)
{
- snmp_mib_free((void __percpu **)net->sctp.sctp_statistics);
+ free_percpu(net->sctp.sctp_statistics);
}
static void sctp_v4_pf_init(void)
@@ -1328,7 +1346,7 @@
};
/* Initialize the universe into something sensible. */
-SCTP_STATIC __init int sctp_init(void)
+static __init int sctp_init(void)
{
int i;
int status = -EINVAL;
@@ -1336,10 +1354,10 @@
unsigned long limit;
int max_share;
int order;
+ int num_entries;
+ int max_entry_order;
- /* SCTP_DEBUG sanity check. */
- if (!sctp_sanity_check())
- goto out;
+ sock_skb_cb_check_size(sizeof(struct sctp_ulpevent));
/* Allocate bind_bucket and chunk caches. */
status = -ENOBUFS;
@@ -1357,7 +1375,7 @@
if (!sctp_chunk_cachep)
goto err_chunk_cachep;
- status = percpu_counter_init(&sctp_sockets_allocated, 0);
+ status = percpu_counter_init(&sctp_sockets_allocated, 0, GFP_KERNEL);
if (status)
goto err_percpu_counter_init;
@@ -1390,14 +1408,24 @@
/* 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);
- for (order = 0; (1UL << order) < goal; order++)
- ;
+ /* 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);
do {
sctp_assoc_hashsize = (1UL << order) * PAGE_SIZE /
@@ -1431,20 +1459,35 @@
INIT_HLIST_HEAD(&sctp_ep_hashtable[i].chain);
}
- /* Allocate and initialize the SCTP port hash table. */
+ /* 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_hashsize = (1UL << order) * PAGE_SIZE /
- sizeof(struct sctp_bind_hashbucket);
- if ((sctp_port_hashsize > (64 * 1024)) && order > 0)
- continue;
sctp_port_hashtable = (struct sctp_bind_hashbucket *)
__get_free_pages(GFP_ATOMIC|__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);
@@ -1484,7 +1527,6 @@
if (status)
goto err_v6_add_protocol;
- status = 0;
out:
return status;
err_v6_add_protocol:
@@ -1520,7 +1562,7 @@
}
/* Exit handler for the SCTP protocol. */
-SCTP_STATIC __exit void sctp_exit(void)
+static __exit void sctp_exit(void)
{
/* BUG. This should probably do something useful like clean
* up all the remaining associations and all that memory.
@@ -1568,7 +1610,7 @@
*/
MODULE_ALIAS("net-pf-" __stringify(PF_INET) "-proto-132");
MODULE_ALIAS("net-pf-" __stringify(PF_INET6) "-proto-132");
-MODULE_AUTHOR("Linux Kernel SCTP developers ");
+MODULE_AUTHOR("Linux Kernel SCTP developers ");
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");