/* 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, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers <lksctp-developers@lists.sourceforge.net> * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * 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> * * 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 #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> /* Global data structures. */struct sctp_globals sctp_globals __read_mostly;DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics) __read_mostly; #ifdef CONFIG_PROC_FSstruct proc_dir_entry *proc_net_sctp;#endif struct idr sctp_assocs_id;DEFINE_SPINLOCK(sctp_assocs_id_lock); /* This is the global socket data structure used for responding to * the Out-of-the-blue (OOTB) packets. A control sock will be created * for this socket at the initialization time. */static struct sock *sctp_ctl_sock; 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]; /* Return the address of the control sock. */struct sock *sctp_get_ctl_sock(void){ return sctp_ctl_sock;} /* Set up the proc fs entry for the SCTP protocol. */static __init int sctp_proc_init(void){ if (percpu_counter_init(&sctp_sockets_allocated, 0)) goto out_nomem;#ifdef CONFIG_PROC_FS if (!proc_net_sctp) { proc_net_sctp = proc_mkdir("sctp", init_net.proc_net); if (!proc_net_sctp) goto out_free_percpu; } if (sctp_snmp_proc_init()) goto out_snmp_proc_init; if (sctp_eps_proc_init()) goto out_eps_proc_init; if (sctp_assocs_proc_init()) goto out_assocs_proc_init; if (sctp_remaddr_proc_init()) goto out_remaddr_proc_init; return 0; out_remaddr_proc_init: sctp_assocs_proc_exit();out_assocs_proc_init: sctp_eps_proc_exit();out_eps_proc_init: sctp_snmp_proc_exit();out_snmp_proc_init: if (proc_net_sctp) { proc_net_sctp = NULL; remove_proc_entry("sctp", init_net.proc_net); }out_free_percpu: percpu_counter_destroy(&sctp_sockets_allocated);#else return 0;#endif /* CONFIG_PROC_FS */ out_nomem: return -ENOMEM;} /* 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(void){#ifdef CONFIG_PROC_FS sctp_snmp_proc_exit(); sctp_eps_proc_exit(); sctp_assocs_proc_exit(); sctp_remaddr_proc_exit(); if (proc_net_sctp) { proc_net_sctp = NULL; remove_proc_entry("sctp", init_net.proc_net); }#endif percpu_counter_destroy(&sctp_sockets_allocated);} /* 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 = t_new(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; 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(void){ struct net_device *dev; struct list_head *pos; struct sctp_af *af; rcu_read_lock(); for_each_netdev_rcu(&init_net, dev) { __list_for_each(pos, &sctp_address_families) { af = list_entry(pos, struct sctp_af, list); af->copy_addrlist(&sctp_local_addr_list, dev); } } rcu_read_unlock();} /* Free the existing local addresses. */static void sctp_free_local_addr_list(void){ struct sctp_sockaddr_entry *addr; struct list_head *pos, *temp; list_for_each_safe(pos, temp, &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 sctp_bind_addr *bp, sctp_scope_t scope, gfp_t gfp, int copy_flags){ struct sctp_sockaddr_entry *addr; int error = 0; rcu_read_lock(); list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) { if (!addr->valid) continue; if (sctp_in_scope(&addr->a, scope)) { /* 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 ((((AF_INET == addr->a.sa.sa_family) && (copy_flags & SCTP_ADDR4_PEERSUPP))) || (((AF_INET6 == addr->a.sa.sa_family) && (copy_flags & SCTP_ADDR6_ALLOWED) && (copy_flags & SCTP_ADDR6_PEERSUPP)))) { error = sctp_add_bind_addr(bp, &addr->a, SCTP_ADDR_SRC, GFP_ATOMIC); if (error) goto end_copy; } } } end_copy: rcu_read_unlock(); return error;} /* 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){ void *from; __be16 *port; struct sctphdr *sh; port = &addr->v4.sin_port; addr->v4.sin_family = AF_INET; sh = sctp_hdr(skb); if (is_saddr) { *port = sh->source; from = &ip_hdr(skb)->saddr; } else { *port = sh->dest; from = &ip_hdr(skb)->daddr; } memcpy(&addr->v4.sin_addr.s_addr, from, sizeof(struct in_addr));} /* 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;} /* 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 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;} /* 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;} /* 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;} /* 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;} /* 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){ int ret = inet_addr_type(&init_net, addr->v4.sin_addr.s_addr); if (addr->v4.sin_addr.s_addr != htonl(INADDR_ANY) && ret != RTN_LOCAL && !sp->inet.freebind && !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 * 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;} /* 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; } SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ", __func__, &fl4->daddr, &fl4->saddr); rt = ip_route_output_key(&init_net, 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 bindLines 1–500 of 1531. Load more
/* 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, write to * the Free Software Foundation, 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * * Please send any bug reports or fixes you make to the * email address(es): * lksctp developers <lksctp-developers@lists.sourceforge.net> * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * * 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> * * 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 #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> /* Global data structures. */ struct sctp_globals sctp_globals __read_mostly; DEFINE_SNMP_STAT(struct sctp_mib, sctp_statistics) __read_mostly; #ifdef CONFIG_PROC_FS struct proc_dir_entry *proc_net_sctp; #endif struct idr sctp_assocs_id; DEFINE_SPINLOCK(sctp_assocs_id_lock); /* This is the global socket data structure used for responding to * the Out-of-the-blue (OOTB) packets. A control sock will be created * for this socket at the initialization time. */ static struct sock *sctp_ctl_sock; 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]; /* Return the address of the control sock. */ struct sock *sctp_get_ctl_sock(void) { return sctp_ctl_sock; } /* Set up the proc fs entry for the SCTP protocol. */ static __init int sctp_proc_init(void) { if (percpu_counter_init(&sctp_sockets_allocated, 0)) goto out_nomem; #ifdef CONFIG_PROC_FS if (!proc_net_sctp) { proc_net_sctp = proc_mkdir("sctp", init_net.proc_net); if (!proc_net_sctp) goto out_free_percpu; } if (sctp_snmp_proc_init()) goto out_snmp_proc_init; if (sctp_eps_proc_init()) goto out_eps_proc_init; if (sctp_assocs_proc_init()) goto out_assocs_proc_init; if (sctp_remaddr_proc_init()) goto out_remaddr_proc_init; return 0; out_remaddr_proc_init: sctp_assocs_proc_exit(); out_assocs_proc_init: sctp_eps_proc_exit(); out_eps_proc_init: sctp_snmp_proc_exit(); out_snmp_proc_init: if (proc_net_sctp) { proc_net_sctp = NULL; remove_proc_entry("sctp", init_net.proc_net); } out_free_percpu: percpu_counter_destroy(&sctp_sockets_allocated); #else return 0; #endif /* CONFIG_PROC_FS */ out_nomem: return -ENOMEM; } /* 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(void) { #ifdef CONFIG_PROC_FS sctp_snmp_proc_exit(); sctp_eps_proc_exit(); sctp_assocs_proc_exit(); sctp_remaddr_proc_exit(); if (proc_net_sctp) { proc_net_sctp = NULL; remove_proc_entry("sctp", init_net.proc_net); } #endif percpu_counter_destroy(&sctp_sockets_allocated); } /* 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 = t_new(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; 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(void) { struct net_device *dev; struct list_head *pos; struct sctp_af *af; rcu_read_lock(); for_each_netdev_rcu(&init_net, dev) { __list_for_each(pos, &sctp_address_families) { af = list_entry(pos, struct sctp_af, list); af->copy_addrlist(&sctp_local_addr_list, dev); } } rcu_read_unlock(); } /* Free the existing local addresses. */ static void sctp_free_local_addr_list(void) { struct sctp_sockaddr_entry *addr; struct list_head *pos, *temp; list_for_each_safe(pos, temp, &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 sctp_bind_addr *bp, sctp_scope_t scope, gfp_t gfp, int copy_flags) { struct sctp_sockaddr_entry *addr; int error = 0; rcu_read_lock(); list_for_each_entry_rcu(addr, &sctp_local_addr_list, list) { if (!addr->valid) continue; if (sctp_in_scope(&addr->a, scope)) { /* 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 ((((AF_INET == addr->a.sa.sa_family) && (copy_flags & SCTP_ADDR4_PEERSUPP))) || (((AF_INET6 == addr->a.sa.sa_family) && (copy_flags & SCTP_ADDR6_ALLOWED) && (copy_flags & SCTP_ADDR6_PEERSUPP)))) { error = sctp_add_bind_addr(bp, &addr->a, SCTP_ADDR_SRC, GFP_ATOMIC); if (error) goto end_copy; } } } end_copy: rcu_read_unlock(); return error; } /* 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) { void *from; __be16 *port; struct sctphdr *sh; port = &addr->v4.sin_port; addr->v4.sin_family = AF_INET; sh = sctp_hdr(skb); if (is_saddr) { *port = sh->source; from = &ip_hdr(skb)->saddr; } else { *port = sh->dest; from = &ip_hdr(skb)->daddr; } memcpy(&addr->v4.sin_addr.s_addr, from, sizeof(struct in_addr)); } /* 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; } /* 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 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; } /* 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; } /* 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; } /* 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; } /* 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) { int ret = inet_addr_type(&init_net, addr->v4.sin_addr.s_addr); if (addr->v4.sin_addr.s_addr != htonl(INADDR_ANY) && ret != RTN_LOCAL && !sp->inet.freebind && !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 * 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; } /* 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; } SCTP_DEBUG_PRINTK("%s: DST:%pI4, SRC:%pI4 - ", __func__, &fl4->daddr, &fl4->saddr); rt = ip_route_output_key(&init_net, 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