Release 4.11 net/sctp/ipv6.c
/* SCTP kernel implementation
* (C) Copyright IBM Corp. 2002, 2004
* Copyright (c) 2001 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll
* Copyright (c) 2002-2003 Intel Corp.
*
* This file is part of the SCTP kernel implementation
*
* SCTP over IPv6.
*
* 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:
* Le Yanqun <yanqun.le@nokia.com>
* Hui Huang <hui.huang@nokia.com>
* La Monte H.P. Yarroll <piggy@acm.org>
* Sridhar Samudrala <sri@us.ibm.com>
* Jon Grimm <jgrimm@us.ibm.com>
* Ardelle Fan <ardelle.fan@intel.com>
*
* Based on:
* linux/net/ipv6/tcp_ipv6.c
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/net.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/netdevice.h>
#include <linux/init.h>
#include <linux/ipsec.h>
#include <linux/slab.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <linux/random.h>
#include <linux/seq_file.h>
#include <net/protocol.h>
#include <net/ndisc.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/transp_v6.h>
#include <net/addrconf.h>
#include <net/ip6_route.h>
#include <net/inet_common.h>
#include <net/inet_ecn.h>
#include <net/sctp/sctp.h>
#include <linux/uaccess.h>
static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
union sctp_addr *s2);
static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
__be16 port);
static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2);
/* Event handler for inet6 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_inet6addr_event(struct notifier_block *this, unsigned long ev,
void *ptr)
{
struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
struct sctp_sockaddr_entry *addr = NULL;
struct sctp_sockaddr_entry *temp;
struct net *net = dev_net(ifa->idev->dev);
int found = 0;
switch (ev) {
case NETDEV_UP:
addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
if (addr) {
addr->a.v6.sin6_family = AF_INET6;
addr->a.v6.sin6_port = 0;
addr->a.v6.sin6_addr = ifa->addr;
addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex;
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_INET6 &&
ipv6_addr_equal(&addr->a.v6.sin6_addr,
&ifa->addr)) {
sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL);
found = 1;
addr->valid = 0;
list_del_rcu(&addr->list);
break;
}
}
spin_unlock_bh(&net->sctp.local_addr_lock);
if (found)
kfree_rcu(addr, rcu);
break;
}
return NOTIFY_DONE;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 165 | 55.37% | 1 | 11.11% |
Vladislav Yasevich | 51 | 17.11% | 1 | 11.11% |
Eric W. Biedermann | 44 | 14.77% | 1 | 11.11% |
Michio Honda | 14 | 4.70% | 1 | 11.11% |
Pavel Emelyanov | 10 | 3.36% | 1 | 11.11% |
Chidambar 'ilLogict' Zinnoury | 10 | 3.36% | 1 | 11.11% |
Lai Jiangshan | 2 | 0.67% | 1 | 11.11% |
Alexey Dobriyan | 1 | 0.34% | 1 | 11.11% |
Adrian Bunk | 1 | 0.34% | 1 | 11.11% |
Total | 298 | 100.00% | 9 | 100.00% |
static struct notifier_block sctp_inet6addr_notifier = {
.notifier_call = sctp_inet6addr_event,
};
/* ICMP error handler. */
static void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
u8 type, u8 code, int offset, __be32 info)
{
struct inet6_dev *idev;
struct sock *sk;
struct sctp_association *asoc;
struct sctp_transport *transport;
struct ipv6_pinfo *np;
__u16 saveip, savesctp;
int err;
struct net *net = dev_net(skb->dev);
idev = in6_dev_get(skb->dev);
/* Fix up skb to look at the embedded net header. */
saveip = skb->network_header;
savesctp = skb->transport_header;
skb_reset_network_header(skb);
skb_set_transport_header(skb, offset);
sk = sctp_err_lookup(net, AF_INET6, skb, sctp_hdr(skb), &asoc, &transport);
/* Put back, the original pointers. */
skb->network_header = saveip;
skb->transport_header = savesctp;
if (!sk) {
__ICMP6_INC_STATS(net, idev, ICMP6_MIB_INERRORS);
goto out;
}
/* Warning: The sock lock is held. Remember to call
* sctp_err_finish!
*/
switch (type) {
case ICMPV6_PKT_TOOBIG:
if (ip6_sk_accept_pmtu(sk))
sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info));
goto out_unlock;
case ICMPV6_PARAMPROB:
if (ICMPV6_UNK_NEXTHDR == code) {
sctp_icmp_proto_unreachable(sk, asoc, transport);
goto out_unlock;
}
break;
case NDISC_REDIRECT:
sctp_icmp_redirect(sk, transport, skb);
goto out_unlock;
default:
break;
}
np = inet6_sk(sk);
icmpv6_err_convert(type, code, &err);
if (!sock_owned_by_user(sk) && np->recverr) {
sk->sk_err = err;
sk->sk_error_report(sk);
} else { /* Only an error on timeout */
sk->sk_err_soft = err;
}
out_unlock:
sctp_err_finish(sk, transport);
out:
if (likely(idev != NULL))
in6_dev_put(idev);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 191 | 60.63% | 3 | 13.64% |
David S. Miller | 47 | 14.92% | 2 | 9.09% |
Sridhar Samudrala | 24 | 7.62% | 1 | 4.55% |
Arnaldo Carvalho de Melo | 19 | 6.03% | 4 | 18.18% |
Eric W. Biedermann | 15 | 4.76% | 2 | 9.09% |
Hannes Frederic Sowa | 7 | 2.22% | 1 | 4.55% |
Daniel Borkmann | 4 | 1.27% | 2 | 9.09% |
Brian Haley | 2 | 0.63% | 1 | 4.55% |
Hideaki Yoshifuji / 吉藤英明 | 1 | 0.32% | 1 | 4.55% |
Xin Long | 1 | 0.32% | 1 | 4.55% |
Eric Dumazet | 1 | 0.32% | 1 | 4.55% |
Al Viro | 1 | 0.32% | 1 | 4.55% |
Denis V. Lunev | 1 | 0.32% | 1 | 4.55% |
Simon Horman | 1 | 0.32% | 1 | 4.55% |
Total | 315 | 100.00% | 22 | 100.00% |
static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
{
struct sock *sk = skb->sk;
struct ipv6_pinfo *np = inet6_sk(sk);
struct flowi6 *fl6 = &transport->fl.u.ip6;
int res;
pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", __func__, skb,
skb->len, &fl6->saddr, &fl6->daddr);
IP6_ECN_flow_xmit(sk, fl6->flowlabel);
if (!(transport->param_flags & SPP_PMTUD_ENABLE))
skb->ignore_df = 1;
SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
rcu_read_lock();
res = ip6_xmit(sk, skb, fl6, sk->sk_mark, rcu_dereference(np->opt),
np->tclass);
rcu_read_unlock();
return res;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 49 | 33.56% | 2 | 11.76% |
Daniel Borkmann | 22 | 15.07% | 2 | 11.76% |
Eric Dumazet | 21 | 14.38% | 2 | 11.76% |
Sridhar Samudrala | 19 | 13.01% | 3 | 17.65% |
Herbert Xu | 16 | 10.96% | 1 | 5.88% |
David S. Miller | 7 | 4.79% | 1 | 5.88% |
Pablo Neira Ayuso | 4 | 2.74% | 1 | 5.88% |
Harvey Harrison | 4 | 2.74% | 3 | 17.65% |
Eric W. Biedermann | 3 | 2.05% | 1 | 5.88% |
Américo Wang | 1 | 0.68% | 1 | 5.88% |
Total | 146 | 100.00% | 17 | 100.00% |
/* Returns the dst cache entry for the given source and destination ip
* addresses.
*/
static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
struct flowi *fl, struct sock *sk)
{
struct sctp_association *asoc = t->asoc;
struct dst_entry *dst = NULL;
struct flowi6 *fl6 = &fl->u.ip6;
struct sctp_bind_addr *bp;
struct ipv6_pinfo *np = inet6_sk(sk);
struct sctp_sockaddr_entry *laddr;
union sctp_addr *baddr = NULL;
union sctp_addr *daddr = &t->ipaddr;
union sctp_addr dst_saddr;
struct in6_addr *final_p, final;
__u8 matchlen = 0;
__u8 bmatchlen;
sctp_scope_t scope;
memset(fl6, 0, sizeof(struct flowi6));
fl6->daddr = daddr->v6.sin6_addr;
fl6->fl6_dport = daddr->v6.sin6_port;
fl6->flowi6_proto = IPPROTO_SCTP;
if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
fl6->flowi6_oif = daddr->v6.sin6_scope_id;
pr_debug("%s: dst=%pI6 ", __func__, &fl6->daddr);
if (asoc)
fl6->fl6_sport = htons(asoc->base.bind_addr.port);
if (saddr) {
fl6->saddr = saddr->v6.sin6_addr;
fl6->fl6_sport = saddr->v6.sin6_port;
pr_debug("src=%pI6 - ", &fl6->saddr);
}
rcu_read_lock();
final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
rcu_read_unlock();
dst = ip6_dst_lookup_flow(sk, fl6, final_p);
if (!asoc || saddr)
goto out;
bp = &asoc->base.bind_addr;
scope = sctp_scope(daddr);
/* ip6_dst_lookup has filled in the fl6->saddr for us. Check
* to see if we can use it.
*/
if (!IS_ERR(dst)) {
/* Walk through the bind address list and look for a bind
* address that matches the source address of the returned dst.
*/
sctp_v6_to_addr(&dst_saddr, &fl6->saddr, 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;
/* Do not compare against v4 addrs */
if ((laddr->a.sa.sa_family == AF_INET6) &&
(sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) {
rcu_read_unlock();
goto out;
}
}
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 the
* best source address for a given destination.
*/
rcu_read_lock();
list_for_each_entry_rcu(laddr, &bp->address_list, list) {
if (!laddr->valid)
continue;
if ((laddr->state == SCTP_ADDR_SRC) &&
(laddr->a.sa.sa_family == AF_INET6) &&
(scope <= sctp_scope(&laddr->a))) {
bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
if (!baddr || (matchlen < bmatchlen)) {
baddr = &laddr->a;
matchlen = bmatchlen;
}
}
}
if (baddr) {
fl6->saddr = baddr->v6.sin6_addr;
fl6->fl6_sport = baddr->v6.sin6_port;
final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
dst = ip6_dst_lookup_flow(sk, fl6, final_p);
}
rcu_read_unlock();
out:
if (!IS_ERR_OR_NULL(dst)) {
struct rt6_info *rt;
rt = (struct rt6_info *)dst;
t->dst = dst;
t->dst_cookie = rt6_get_cookie(rt);
pr_debug("rt6_dst:%pI6/%d rt6_src:%pI6\n",
&rt->rt6i_dst.addr, rt->rt6i_dst.plen,
&fl6->saddr);
} else {
t->dst = NULL;
pr_debug("no route\n");
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Vladislav Yasevich | 197 | 30.26% | 4 | 11.11% |
Sridhar Samudrala | 152 | 23.35% | 4 | 11.11% |
Weixing Shi | 79 | 12.14% | 1 | 2.78% |
Daniel Borkmann | 73 | 11.21% | 4 | 11.11% |
Jon Grimm | 64 | 9.83% | 4 | 11.11% |
David S. Miller | 31 | 4.76% | 3 | 8.33% |
Eric Dumazet | 15 | 2.30% | 2 | 5.56% |
Martin KaFai Lau | 10 | 1.54% | 2 | 5.56% |
Harvey Harrison | 7 | 1.08% | 2 | 5.56% |
Fan Du | 6 | 0.92% | 1 | 2.78% |
Hideaki Yoshifuji / 吉藤英明 | 5 | 0.77% | 3 | 8.33% |
Al Viro | 4 | 0.61% | 2 | 5.56% |
Alexey Dobriyan | 3 | 0.46% | 1 | 2.78% |
Ville Nuorvala | 3 | 0.46% | 1 | 2.78% |
Tommi Rantala | 1 | 0.15% | 1 | 2.78% |
Daniel Lezcano | 1 | 0.15% | 1 | 2.78% |
Total | 651 | 100.00% | 36 | 100.00% |
/* Returns the number of consecutive initial bits that match in the 2 ipv6
* addresses.
*/
static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
union sctp_addr *s2)
{
return ipv6_addr_diff(&s1->v6.sin6_addr, &s2->v6.sin6_addr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 31 | 88.57% | 2 | 66.67% |
Hideaki Yoshifuji / 吉藤英明 | 4 | 11.43% | 1 | 33.33% |
Total | 35 | 100.00% | 3 | 100.00% |
/* Fills in the source address(saddr) based on the destination address(daddr)
* and asoc's bind address list.
*/
static void sctp_v6_get_saddr(struct sctp_sock *sk,
struct sctp_transport *t,
struct flowi *fl)
{
struct flowi6 *fl6 = &fl->u.ip6;
union sctp_addr *saddr = &t->saddr;
pr_debug("%s: asoc:%p dst:%p\n", __func__, t->asoc, t->dst);
if (t->dst) {
saddr->v6.sin6_family = AF_INET6;
saddr->v6.sin6_addr = fl6->saddr;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 44 | 52.38% | 2 | 20.00% |
Vladislav Yasevich | 30 | 35.71% | 2 | 20.00% |
Hideaki Yoshifuji / 吉藤英明 | 5 | 5.95% | 1 | 10.00% |
Jon Grimm | 2 | 2.38% | 2 | 20.00% |
Daniel Borkmann | 1 | 1.19% | 1 | 10.00% |
Harvey Harrison | 1 | 1.19% | 1 | 10.00% |
Alexey Dobriyan | 1 | 1.19% | 1 | 10.00% |
Total | 84 | 100.00% | 10 | 100.00% |
/* Make a copy of all potential local addresses. */
static void sctp_v6_copy_addrlist(struct list_head *addrlist,
struct net_device *dev)
{
struct inet6_dev *in6_dev;
struct inet6_ifaddr *ifp;
struct sctp_sockaddr_entry *addr;
rcu_read_lock();
if ((in6_dev = __in6_dev_get(dev)) == NULL) {
rcu_read_unlock();
return;
}
read_lock_bh(&in6_dev->lock);
list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
/* Add the address to the local list. */
addr = kzalloc(sizeof(*addr), GFP_ATOMIC);
if (addr) {
addr->a.v6.sin6_family = AF_INET6;
addr->a.v6.sin6_port = 0;
addr->a.v6.sin6_addr = ifp->addr;
addr->a.v6.sin6_scope_id = dev->ifindex;
addr->valid = 1;
INIT_LIST_HEAD(&addr->list);
list_add_tail(&addr->list, addrlist);
}
}
read_unlock_bh(&in6_dev->lock);
rcu_read_unlock();
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 137 | 80.59% | 3 | 30.00% |
Stephen Hemminger | 8 | 4.71% | 1 | 10.00% |
Hideaki Yoshifuji / 吉藤英明 | 6 | 3.53% | 1 | 10.00% |
Daniel Borkmann | 6 | 3.53% | 1 | 10.00% |
Vladislav Yasevich | 6 | 3.53% | 1 | 10.00% |
Al Viro | 4 | 2.35% | 1 | 10.00% |
Jarek Poplawski | 2 | 1.18% | 1 | 10.00% |
Alexey Dobriyan | 1 | 0.59% | 1 | 10.00% |
Total | 170 | 100.00% | 10 | 100.00% |
/* Initialize a sockaddr_storage from in incoming skb. */
static void sctp_v6_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_in6 *sa = &addr->v6;
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_flowinfo = 0; /* FIXME */
addr->v6.sin6_scope_id = ((struct inet6_skb_parm *)skb->cb)->iif;
if (is_saddr) {
sa->sin6_port = sh->source;
sa->sin6_addr = ipv6_hdr(skb)->saddr;
} else {
sa->sin6_port = sh->dest;
sa->sin6_addr = ipv6_hdr(skb)->daddr;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 93 | 75.61% | 2 | 40.00% |
Marcelo Ricardo Leitner | 20 | 16.26% | 1 | 20.00% |
Arnaldo Carvalho de Melo | 6 | 4.88% | 1 | 20.00% |
Alexey Dobriyan | 4 | 3.25% | 1 | 20.00% |
Total | 123 | 100.00% | 5 | 100.00% |
/* Initialize an sctp_addr from a socket. */
static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
{
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_port = 0;
addr->v6.sin6_addr = sk->sk_v6_rcv_saddr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 39 | 92.86% | 1 | 25.00% |
Al Viro | 1 | 2.38% | 1 | 25.00% |
Alexey Dobriyan | 1 | 2.38% | 1 | 25.00% |
Eric Dumazet | 1 | 2.38% | 1 | 25.00% |
Total | 42 | 100.00% | 4 | 100.00% |
/* Initialize sk->sk_rcv_saddr from sctp_addr. */
static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
{
if (addr->sa.sa_family == AF_INET) {
sk->sk_v6_rcv_saddr.s6_addr32[0] = 0;
sk->sk_v6_rcv_saddr.s6_addr32[1] = 0;
sk->sk_v6_rcv_saddr.s6_addr32[2] = htonl(0x0000ffff);
sk->sk_v6_rcv_saddr.s6_addr32[3] =
addr->v4.sin_addr.s_addr;
} else {
sk->sk_v6_rcv_saddr = addr->v6.sin6_addr;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 87 | 92.55% | 2 | 40.00% |
Eric Dumazet | 5 | 5.32% | 1 | 20.00% |
Sridhar Samudrala | 1 | 1.06% | 1 | 20.00% |
Alexey Dobriyan | 1 | 1.06% | 1 | 20.00% |
Total | 94 | 100.00% | 5 | 100.00% |
/* Initialize sk->sk_daddr from sctp_addr. */
static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
{
if (addr->sa.sa_family == AF_INET) {
sk->sk_v6_daddr.s6_addr32[0] = 0;
sk->sk_v6_daddr.s6_addr32[1] = 0;
sk->sk_v6_daddr.s6_addr32[2] = htonl(0x0000ffff);
sk->sk_v6_daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
} else {
sk->sk_v6_daddr = addr->v6.sin6_addr;
}
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 64 | 68.09% | 1 | 25.00% |
Sridhar Samudrala | 24 | 25.53% | 1 | 25.00% |
Eric Dumazet | 5 | 5.32% | 1 | 25.00% |
Alexey Dobriyan | 1 | 1.06% | 1 | 25.00% |
Total | 94 | 100.00% | 4 | 100.00% |
/* Initialize a sctp_addr from an address parameter. */
static void sctp_v6_from_addr_param(union sctp_addr *addr,
union sctp_addr_param *param,
__be16 port, int iif)
{
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_port = port;
addr->v6.sin6_flowinfo = 0; /* BUG */
addr->v6.sin6_addr = param->v6.addr;
addr->v6.sin6_scope_id = iif;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 65 | 97.01% | 1 | 33.33% |
Al Viro | 1 | 1.49% | 1 | 33.33% |
Alexey Dobriyan | 1 | 1.49% | 1 | 33.33% |
Total | 67 | 100.00% | 3 | 100.00% |
/* Initialize an address parameter from a sctp_addr and return the length
* of the address parameter.
*/
static int sctp_v6_to_addr_param(const union sctp_addr *addr,
union sctp_addr_param *param)
{
int length = sizeof(sctp_ipv6addr_param_t);
param->v6.param_hdr.type = SCTP_PARAM_IPV6_ADDRESS;
param->v6.param_hdr.length = htons(length);
param->v6.addr = addr->v6.sin6_addr;
return length;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Sridhar Samudrala | 61 | 96.83% | 1 | 33.33% |
Al Viro | 1 | 1.59% | 1 | 33.33% |
Alexey Dobriyan | 1 | 1.59% | 1 | 33.33% |
Total | 63 | 100.00% | 3 | 100.00% |
/* Initialize a sctp_addr from struct in6_addr. */
static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
__be16 port)
{
addr->sa.sa_family = AF_INET6;
addr->v6.sin6_port = port;
addr->v6.sin6_addr = *saddr;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 22 | 50.00% | 2 | 28.57% |
Sridhar Samudrala | 15 | 34.09% | 2 | 28.57% |
Vladislav Yasevich | 4 | 9.09% | 1 | 14.29% |
Alexey Dobriyan | 2 | 4.55% | 1 | 14.29% |
Al Viro | 1 | 2.27% | 1 | 14.29% |
Total | 44 | 100.00% | 7 | 100.00% |
/* Compare addresses exactly.
* v4-mapped-v6 is also in consideration.
*/
static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
const union sctp_addr *addr2)
{
if (addr1->sa.sa_family != addr2->sa.sa_family) {
if (addr1->sa.sa_family == AF_INET &&
addr2->sa.sa_family == AF_INET6 &&
ipv6_addr_v4mapped(&addr2->v6.sin6_addr)) {
if (addr2->v6.sin6_port == addr1->v4.sin_port &&
addr2->v6.sin6_addr.s6_addr32[3] ==
addr1->v4.sin_addr.s_addr)
return 1;
}
if (addr2->sa.sa_family == AF_INET &&
addr1->sa.sa_family == AF_INET6 &&
ipv6_addr_v4mapped(&addr1->v6.sin6_addr)) {
if (addr1->v6.sin6_port == addr2->v4.sin_port &&
addr1->v6.sin6_addr.s6_addr32[3] ==
addr2->v4.sin_addr.s_addr)
return 1;
}
return 0;
}
if (addr1->v6.sin6_port != addr2->v6.sin6_port)
return 0;
if (!ipv6_addr_equal(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr))
return 0;
/* If this is a linklocal address, compare the scope_id. */
if (ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) {
if (addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id &&
(addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id)) {
return 0;
}
}
return 1;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 234 | 89.31% | 4 | 50.00% |
Xin Long | 17 | 6.49% | 1 | 12.50% |
Sridhar Samudrala | 7 | 2.67% | 1 | 12.50% |
Hideaki Yoshifuji / 吉藤英明 | 2 | 0.76% | 1 | 12.50% |
Brian Haley | 2 | 0.76% | 1 | 12.50% |
Total | 262 | 100.00% | 8 | 100.00% |
/* Initialize addr struct to INADDR_ANY. */
static void sctp_v6_inaddr_any(union sctp_addr *addr, __be16 port)
{
memset(addr, 0x00, sizeof(union sctp_addr));
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_port = port;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 42 | 97.67% | 2 | 66.67% |
Al Viro | 1 | 2.33% | 1 | 33.33% |
Total | 43 | 100.00% | 3 | 100.00% |
/* Is this a wildcard address? */
static int sctp_v6_is_any(const union sctp_addr *addr)
{
return ipv6_addr_any(&addr->v6.sin6_addr);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 21 | 91.30% | 1 | 50.00% |
Brian Haley | 2 | 8.70% | 1 | 50.00% |
Total | 23 | 100.00% | 2 | 100.00% |
/* Should this be available for binding? */
static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
{
int type;
struct net *net = sock_net(&sp->inet.sk);
const struct in6_addr *in6 = (const struct in6_addr *)&addr->v6.sin6_addr;
type = ipv6_addr_type(in6);
if (IPV6_ADDR_ANY == type)
return 1;
if (type == IPV6_ADDR_MAPPED) {
if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
return 0;
sctp_v6_map_v4(addr);
return sctp_get_af_specific(AF_INET)->available(addr, sp);
}
if (!(type & IPV6_ADDR_UNICAST))
return 0;
return sp->inet.freebind || net->ipv6.sysctl.ip_nonlocal_bind ||
ipv6_chk_addr(net, in6, NULL, 0);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Jon Grimm | 99 | 66.89% | 2 | 22.22% |
Xin Long | 28 | 18.92% | 1 | 11.11% |
Sridhar Samudrala | 11 | 7.43% | 1 | 11.11% |
Eric W. Biedermann | 4 | 2.70% | 1 | 11.11% |
Ville Nuorvala | 2 | 1.35% | 1 | 11.11% |
Eric Dumazet | 2 | 1.35% | 1 | 11.11% |
Daniel Lezcano | 1 | 0.68% | 1 | 11.11% |
Arnaldo Carvalho de Melo | 1 | 0.68% | 1 | 11.11% |
Total | 148 | 100.00% | 9 | 100.00% |
/* This function checks if the address is a valid address to be used for
* SCTP.
*
* 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_v6_addr_valid(union sctp_addr *addr,
struct sctp_sock *sp,
const struct sk_buff *skb)
{
int ret = ipv6_addr_type(&addr->v6.sin6_addr);
/* Support v4-mapped-v6 address. */
if