Blame view

net/sctp/ipv6.c 30.1 KB
47505b8bc   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-or-later
60c778b25   Vlad Yasevich   [SCTP]: Stop clai...
2
  /* SCTP kernel implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
   * (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.
   *
60c778b25   Vlad Yasevich   [SCTP]: Stop clai...
8
   * This file is part of the SCTP kernel implementation
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
   *
   * SCTP over IPv6.
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
   * Please send any bug reports or fixes you make to the
   * email address(es):
91705c61b   Daniel Borkmann   net: sctp: trivia...
14
   *    lksctp developers <linux-sctp@vger.kernel.org>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
   *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
16
17
18
19
20
21
22
23
24
25
   * 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
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26
   */
145ce502e   Joe Perches   net/sctp: Use pr_...
27
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
31
32
33
  #include <linux/module.h>
  #include <linux/errno.h>
  #include <linux/types.h>
  #include <linux/socket.h>
  #include <linux/sockios.h>
  #include <linux/net.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
38
  #include <linux/in.h>
  #include <linux/in6.h>
  #include <linux/netdevice.h>
  #include <linux/init.h>
  #include <linux/ipsec.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
39
  #include <linux/slab.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
45
46
  
  #include <linux/ipv6.h>
  #include <linux/icmpv6.h>
  #include <linux/random.h>
  #include <linux/seq_file.h>
  
  #include <net/protocol.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
  #include <net/ndisc.h>
c752f0739   Arnaldo Carvalho de Melo   [TCP]: Move the t...
48
  #include <net/ip.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
49
50
51
52
53
54
55
  #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>
7c0f6ba68   Linus Torvalds   Replace <asm/uacc...
56
  #include <linux/uaccess.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
57

625034113   Weixing Shi   sctp: fix sctp to...
58
59
  static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
  					 union sctp_addr *s2);
9914ae3ca   Vlad Yasevich   sctp: cache the i...
60
61
62
63
  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);
625034113   Weixing Shi   sctp: fix sctp to...
64

293035479   Vlad Yasevich   [SCTP]: Add RCU s...
65
66
67
68
69
70
  /* 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.
   */
24123186f   Adrian Bunk   [SCTP]: make 2 fu...
71
72
  static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
  				void *ptr)
29c7cf961   Sridhar Samudrala   [SCTP]: Handle ad...
73
74
  {
  	struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
293035479   Vlad Yasevich   [SCTP]: Add RCU s...
75
76
  	struct sctp_sockaddr_entry *addr = NULL;
  	struct sctp_sockaddr_entry *temp;
4db67e808   Eric W. Biederman   sctp: Make the ad...
77
  	struct net *net = dev_net(ifa->idev->dev);
22626216c   Chidambar 'ilLogict' Zinnoury   [SCTP]: Fix local...
78
  	int found = 0;
29c7cf961   Sridhar Samudrala   [SCTP]: Handle ad...
79
80
81
  
  	switch (ev) {
  	case NETDEV_UP:
400b8b9a2   Xin Long   sctp: allocate sc...
82
  		addr = kzalloc(sizeof(*addr), GFP_ATOMIC);
29c7cf961   Sridhar Samudrala   [SCTP]: Handle ad...
83
84
  		if (addr) {
  			addr->a.v6.sin6_family = AF_INET6;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
85
  			addr->a.v6.sin6_addr = ifa->addr;
29c7cf961   Sridhar Samudrala   [SCTP]: Handle ad...
86
  			addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex;
293035479   Vlad Yasevich   [SCTP]: Add RCU s...
87
  			addr->valid = 1;
4db67e808   Eric W. Biederman   sctp: Make the ad...
88
89
90
91
  			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);
29c7cf961   Sridhar Samudrala   [SCTP]: Handle ad...
92
93
94
  		}
  		break;
  	case NETDEV_DOWN:
4db67e808   Eric W. Biederman   sctp: Make the ad...
95
  		spin_lock_bh(&net->sctp.local_addr_lock);
293035479   Vlad Yasevich   [SCTP]: Add RCU s...
96
  		list_for_each_entry_safe(addr, temp,
4db67e808   Eric W. Biederman   sctp: Make the ad...
97
  					&net->sctp.local_addr_list, list) {
a40a7d15b   Pavel Emelyanov   [SCTP]: IPv4 vs I...
98
99
100
  			if (addr->a.sa.sa_family == AF_INET6 &&
  					ipv6_addr_equal(&addr->a.v6.sin6_addr,
  						&ifa->addr)) {
4db67e808   Eric W. Biederman   sctp: Make the ad...
101
  				sctp_addr_wq_mgmt(net, addr, SCTP_ADDR_DEL);
22626216c   Chidambar 'ilLogict' Zinnoury   [SCTP]: Fix local...
102
  				found = 1;
293035479   Vlad Yasevich   [SCTP]: Add RCU s...
103
104
  				addr->valid = 0;
  				list_del_rcu(&addr->list);
29c7cf961   Sridhar Samudrala   [SCTP]: Handle ad...
105
106
107
  				break;
  			}
  		}
4db67e808   Eric W. Biederman   sctp: Make the ad...
108
  		spin_unlock_bh(&net->sctp.local_addr_lock);
22626216c   Chidambar 'ilLogict' Zinnoury   [SCTP]: Fix local...
109
  		if (found)
1231f0baa   Lai Jiangshan   net,rcu: convert ...
110
  			kfree_rcu(addr, rcu);
29c7cf961   Sridhar Samudrala   [SCTP]: Handle ad...
111
112
113
114
115
  		break;
  	}
  
  	return NOTIFY_DONE;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
  static struct notifier_block sctp_inet6addr_notifier = {
29c7cf961   Sridhar Samudrala   [SCTP]: Handle ad...
117
  	.notifier_call = sctp_inet6addr_event,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
  };
  
  /* ICMP error handler. */
32bbd8793   Stefano Brivio   net: Convert prot...
121
  static int sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
dda919285   Daniel Borkmann   net: sctp: remove...
122
  			u8 type, u8 code, int offset, __be32 info)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
  {
  	struct inet6_dev *idev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  	struct sock *sk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
128
  	struct sctp_association *asoc;
  	struct sctp_transport *transport;
  	struct ipv6_pinfo *np;
2c928e0e8   Simon Horman   sctp: Correct byt...
129
  	__u16 saveip, savesctp;
32bbd8793   Stefano Brivio   net: Convert prot...
130
  	int err, ret = 0;
4110cc255   Eric W. Biederman   sctp: Make the as...
131
  	struct net *net = dev_net(skb->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
135
  
  	idev = in6_dev_get(skb->dev);
  
  	/* Fix up skb to look at the embedded net header. */
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
136
137
  	saveip	 = skb->network_header;
  	savesctp = skb->transport_header;
1ced98e81   Arnaldo Carvalho de Melo   [SK_BUFF] ipv6: M...
138
  	skb_reset_network_header(skb);
a27ef749e   Arnaldo Carvalho de Melo   [SCTP]: Eliminate...
139
  	skb_set_transport_header(skb, offset);
4110cc255   Eric W. Biederman   sctp: Make the as...
140
  	sk = sctp_err_lookup(net, AF_INET6, skb, sctp_hdr(skb), &asoc, &transport);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
  	/* Put back, the original pointers. */
b0e380b1d   Arnaldo Carvalho de Melo   [SK_BUFF]: unions...
142
143
  	skb->network_header   = saveip;
  	skb->transport_header = savesctp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
  	if (!sk) {
a16292a0f   Eric Dumazet   net: rename ICMP6...
145
  		__ICMP6_INC_STATS(net, idev, ICMP6_MIB_INERRORS);
32bbd8793   Stefano Brivio   net: Convert prot...
146
  		ret = -ENOENT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
148
149
150
151
152
153
154
155
  		goto out;
  	}
  
  	/* Warning:  The sock lock is held.  Remember to call
  	 * sctp_err_finish!
  	 */
  
  	switch (type) {
  	case ICMPV6_PKT_TOOBIG:
790e38bc2   Hannes Frederic Sowa   ipv6: move ip6_sk...
156
157
  		if (ip6_sk_accept_pmtu(sk))
  			sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
160
  		goto out_unlock;
  	case ICMPV6_PARAMPROB:
  		if (ICMPV6_UNK_NEXTHDR == code) {
d1ad1ff29   Sridhar Samudrala   [SCTP]: Fix poten...
161
  			sctp_icmp_proto_unreachable(sk, asoc, transport);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162
163
164
  			goto out_unlock;
  		}
  		break;
ec18d9a26   David S. Miller   ipv6: Add redirec...
165
166
  	case NDISC_REDIRECT:
  		sctp_icmp_redirect(sk, transport, skb);
3f96a5321   Daniel Borkmann   net: sctp: rfc444...
167
  		goto out_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
170
171
172
173
174
175
176
177
178
179
180
181
  	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:
dae399d7f   Xin Long   sctp: hold transp...
182
  	sctp_err_finish(sk, transport);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
183
184
185
  out:
  	if (likely(idev != NULL))
  		in6_dev_put(idev);
32bbd8793   Stefano Brivio   net: Convert prot...
186
187
  
  	return ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
188
  }
f880374c2   Herbert Xu   sctp: Drop ipfarg...
189
  static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
192
  {
  	struct sock *sk = skb->sk;
  	struct ipv6_pinfo *np = inet6_sk(sk);
95ee62083   Daniel Borkmann   net: sctp: fix ip...
193
  	struct flowi6 *fl6 = &transport->fl.u.ip6;
8a9c58d28   Xin Long   sctp: add support...
194
  	__u8 tclass = np->tclass;
c836a8ba9   Eric Dumazet   ipv6: sctp: add r...
195
  	int res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196

bb33381d0   Daniel Borkmann   net: sctp: rework...
197
198
  	pr_debug("%s: skb:%p, len:%d, src:%pI6 dst:%pI6
  ", __func__, skb,
95ee62083   Daniel Borkmann   net: sctp: fix ip...
199
  		 skb->len, &fl6->saddr, &fl6->daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200

8a9c58d28   Xin Long   sctp: add support...
201
202
203
204
205
  	if (transport->dscp & SCTP_DSCP_SET_MASK)
  		tclass = transport->dscp & SCTP_DSCP_VAL_MASK;
  
  	if (INET_ECN_is_capable(tclass))
  		IP6_ECN_flow_xmit(sk, fl6->flowlabel);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
206

f880374c2   Herbert Xu   sctp: Drop ipfarg...
207
  	if (!(transport->param_flags & SPP_PMTUD_ENABLE))
60ff74673   WANG Cong   net: rename local...
208
  		skb->ignore_df = 1;
f880374c2   Herbert Xu   sctp: Drop ipfarg...
209

95ee62083   Daniel Borkmann   net: sctp: fix ip...
210
  	SCTP_INC_STATS(sock_net(sk), SCTP_MIB_OUTSCTPPACKS);
c836a8ba9   Eric Dumazet   ipv6: sctp: add r...
211
  	rcu_read_lock();
92e55f412   Pablo Neira   tcp: don't annota...
212
  	res = ip6_xmit(sk, skb, fl6, sk->sk_mark, rcu_dereference(np->opt),
4f6570d72   Eric Dumazet   ipv6: add priorit...
213
  		       tclass, sk->sk_priority);
c836a8ba9   Eric Dumazet   ipv6: sctp: add r...
214
215
  	rcu_read_unlock();
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
217
218
219
220
  }
  
  /* Returns the dst cache entry for the given source and destination ip
   * addresses.
   */
da0420bee   Vlad Yasevich   sctp: clean up ro...
221
222
  static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
  			    struct flowi *fl, struct sock *sk)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  {
da0420bee   Vlad Yasevich   sctp: clean up ro...
224
  	struct sctp_association *asoc = t->asoc;
625034113   Weixing Shi   sctp: fix sctp to...
225
  	struct dst_entry *dst = NULL;
9914ae3ca   Vlad Yasevich   sctp: cache the i...
226
  	struct flowi6 *fl6 = &fl->u.ip6;
625034113   Weixing Shi   sctp: fix sctp to...
227
  	struct sctp_bind_addr *bp;
95ee62083   Daniel Borkmann   net: sctp: fix ip...
228
  	struct ipv6_pinfo *np = inet6_sk(sk);
625034113   Weixing Shi   sctp: fix sctp to...
229
  	struct sctp_sockaddr_entry *laddr;
da0420bee   Vlad Yasevich   sctp: clean up ro...
230
  	union sctp_addr *daddr = &t->ipaddr;
9914ae3ca   Vlad Yasevich   sctp: cache the i...
231
  	union sctp_addr dst_saddr;
95ee62083   Daniel Borkmann   net: sctp: fix ip...
232
  	struct in6_addr *final_p, final;
1c662018d   Xin Long   sctp: remove the ...
233
  	enum sctp_scope scope;
625034113   Weixing Shi   sctp: fix sctp to...
234
  	__u8 matchlen = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235

9914ae3ca   Vlad Yasevich   sctp: cache the i...
236
  	memset(fl6, 0, sizeof(struct flowi6));
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
237
  	fl6->daddr = daddr->v6.sin6_addr;
9c6a02f41   Vlad Yasevich   sctp: make sctp o...
238
239
  	fl6->fl6_dport = daddr->v6.sin6_port;
  	fl6->flowi6_proto = IPPROTO_SCTP;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
240
  	if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
9914ae3ca   Vlad Yasevich   sctp: cache the i...
241
  		fl6->flowi6_oif = daddr->v6.sin6_scope_id;
25e7f2de9   Zheng Li   sctp: set the val...
242
243
  	else if (asoc)
  		fl6->flowi6_oif = asoc->base.sk->sk_bound_dev_if;
8a9c58d28   Xin Long   sctp: add support...
244
245
  	if (t->flowlabel & SCTP_FLOWLABEL_SET_MASK)
  		fl6->flowlabel = htonl(t->flowlabel & SCTP_FLOWLABEL_VAL_MASK);
d808ad9ab   YOSHIFUJI Hideaki   [NET] SCTP: Fix w...
246

0999f021c   Xin Long   sctp: check for i...
247
248
249
250
  	if (np->sndflow && (fl6->flowlabel & IPV6_FLOWLABEL_MASK)) {
  		struct ip6_flowlabel *flowlabel;
  
  		flowlabel = fl6_sock_lookup(sk, fl6->flowlabel);
59c820b23   Willem de Bruijn   ipv6: elide flowl...
251
  		if (IS_ERR(flowlabel))
0999f021c   Xin Long   sctp: check for i...
252
253
254
  			goto out;
  		fl6_sock_release(flowlabel);
  	}
bb33381d0   Daniel Borkmann   net: sctp: rework...
255
  	pr_debug("%s: dst=%pI6 ", __func__, &fl6->daddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
256

9c6a02f41   Vlad Yasevich   sctp: make sctp o...
257
258
  	if (asoc)
  		fl6->fl6_sport = htons(asoc->base.bind_addr.port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259
260
  
  	if (saddr) {
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
261
  		fl6->saddr = saddr->v6.sin6_addr;
ecf938fe7   Xin Long   sctp: set flow sp...
262
263
  		if (!fl6->fl6_sport)
  			fl6->fl6_sport = saddr->v6.sin6_port;
bb33381d0   Daniel Borkmann   net: sctp: rework...
264
265
  
  		pr_debug("src=%pI6 - ", &fl6->saddr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  	}
c836a8ba9   Eric Dumazet   ipv6: sctp: add r...
267
268
269
  	rcu_read_lock();
  	final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
  	rcu_read_unlock();
c4e85f73a   Sabrina Dubroca   net: ipv6: add ne...
270
  	dst = ip6_dst_lookup_flow(sock_net(sk), sk, fl6, final_p);
625034113   Weixing Shi   sctp: fix sctp to...
271
272
  	if (!asoc || saddr)
  		goto out;
9914ae3ca   Vlad Yasevich   sctp: cache the i...
273
274
275
276
277
  	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.
  	 */
9c6a02f41   Vlad Yasevich   sctp: make sctp o...
278
  	if (!IS_ERR(dst)) {
9914ae3ca   Vlad Yasevich   sctp: cache the i...
279
280
  		/* Walk through the bind address list and look for a bind
  		 * address that matches the source address of the returned dst.
625034113   Weixing Shi   sctp: fix sctp to...
281
  		 */
9914ae3ca   Vlad Yasevich   sctp: cache the i...
282
  		sctp_v6_to_addr(&dst_saddr, &fl6->saddr, htons(bp->port));
625034113   Weixing Shi   sctp: fix sctp to...
283
284
  		rcu_read_lock();
  		list_for_each_entry_rcu(laddr, &bp->address_list, list) {
fecda0349   Daniel Borkmann   net: sctp: fix AS...
285
286
287
  			if (!laddr->valid || laddr->state == SCTP_ADDR_DEL ||
  			    (laddr->state != SCTP_ADDR_SRC &&
  			     !asoc->src_out_of_asoc_ok))
625034113   Weixing Shi   sctp: fix sctp to...
288
  				continue;
9914ae3ca   Vlad Yasevich   sctp: cache the i...
289
290
291
292
293
294
  
  			/* 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;
625034113   Weixing Shi   sctp: fix sctp to...
295
296
297
  			}
  		}
  		rcu_read_unlock();
9914ae3ca   Vlad Yasevich   sctp: cache the i...
298
299
300
301
302
  		/* None of the bound addresses match the source address of the
  		 * dst. So release it.
  		 */
  		dst_release(dst);
  		dst = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
  	}
9914ae3ca   Vlad Yasevich   sctp: cache the i...
304
305
306
307
308
  	/* 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) {
dbc2b5e9a   Xin Long   sctp: fix src add...
309
310
311
312
313
314
315
  		struct dst_entry *bdst;
  		__u8 bmatchlen;
  
  		if (!laddr->valid ||
  		    laddr->state != SCTP_ADDR_SRC ||
  		    laddr->a.sa.sa_family != AF_INET6 ||
  		    scope > sctp_scope(&laddr->a))
9914ae3ca   Vlad Yasevich   sctp: cache the i...
316
  			continue;
dbc2b5e9a   Xin Long   sctp: fix src add...
317
318
319
  
  		fl6->saddr = laddr->a.v6.sin6_addr;
  		fl6->fl6_sport = laddr->a.v6.sin6_port;
c836a8ba9   Eric Dumazet   ipv6: sctp: add r...
320
  		final_p = fl6_update_dst(fl6, rcu_dereference(np->opt), &final);
c4e85f73a   Sabrina Dubroca   net: ipv6: add ne...
321
  		bdst = ip6_dst_lookup_flow(sock_net(sk), sk, fl6, final_p);
dbc2b5e9a   Xin Long   sctp: fix src add...
322

957d761cf   Alexey Kodanev   sctp: fix dst ref...
323
324
325
326
  		if (IS_ERR(bdst))
  			continue;
  
  		if (ipv6_chk_addr(dev_net(bdst->dev),
dbc2b5e9a   Xin Long   sctp: fix src add...
327
328
329
330
331
332
333
334
  				  &laddr->a.v6.sin6_addr, bdst->dev, 1)) {
  			if (!IS_ERR_OR_NULL(dst))
  				dst_release(dst);
  			dst = bdst;
  			break;
  		}
  
  		bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
957d761cf   Alexey Kodanev   sctp: fix dst ref...
335
336
  		if (matchlen > bmatchlen) {
  			dst_release(bdst);
dbc2b5e9a   Xin Long   sctp: fix src add...
337
  			continue;
957d761cf   Alexey Kodanev   sctp: fix dst ref...
338
  		}
dbc2b5e9a   Xin Long   sctp: fix src add...
339
340
341
342
343
  
  		if (!IS_ERR_OR_NULL(dst))
  			dst_release(dst);
  		dst = bdst;
  		matchlen = bmatchlen;
9914ae3ca   Vlad Yasevich   sctp: cache the i...
344
  	}
69ce6487d   Eric Dumazet   ipv6: sctp: fix l...
345
  	rcu_read_unlock();
9914ae3ca   Vlad Yasevich   sctp: cache the i...
346

625034113   Weixing Shi   sctp: fix sctp to...
347
  out:
ee3f34e85   Tommi Rantala   sctp: fix CONFIG_...
348
  	if (!IS_ERR_OR_NULL(dst)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349
  		struct rt6_info *rt;
bb33381d0   Daniel Borkmann   net: sctp: rework...
350

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
351
  		rt = (struct rt6_info *)dst;
da0420bee   Vlad Yasevich   sctp: clean up ro...
352
  		t->dst = dst;
b197df4f0   Martin KaFai Lau   ipv6: Add rt6_get...
353
  		t->dst_cookie = rt6_get_cookie(rt);
fd0273d79   Martin KaFai Lau   ipv6: Remove exte...
354
355
356
  		pr_debug("rt6_dst:%pI6/%d rt6_src:%pI6
  ",
  			 &rt->rt6i_dst.addr, rt->rt6i_dst.plen,
bb33381d0   Daniel Borkmann   net: sctp: rework...
357
  			 &fl6->saddr);
da0420bee   Vlad Yasevich   sctp: clean up ro...
358
359
  	} else {
  		t->dst = NULL;
bb33381d0   Daniel Borkmann   net: sctp: rework...
360
361
362
  
  		pr_debug("no route
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
364
365
366
367
368
369
370
371
  }
  
  /* 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)
  {
de7737e05   YOSHIFUJI Hideaki / 吉藤英明   sctp: Use ipv6_ad...
372
  	return ipv6_addr_diff(&s1->v6.sin6_addr, &s2->v6.sin6_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
373
374
375
376
377
  }
  
  /* Fills in the source address(saddr) based on the destination address(daddr)
   * and asoc's bind address list.
   */
e51171019   YOSHIFUJI Hideaki   [SCTP]: Fix NULL ...
378
  static void sctp_v6_get_saddr(struct sctp_sock *sk,
9914ae3ca   Vlad Yasevich   sctp: cache the i...
379
  			      struct sctp_transport *t,
9914ae3ca   Vlad Yasevich   sctp: cache the i...
380
  			      struct flowi *fl)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
381
  {
9914ae3ca   Vlad Yasevich   sctp: cache the i...
382
383
  	struct flowi6 *fl6 = &fl->u.ip6;
  	union sctp_addr *saddr = &t->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
384

bb33381d0   Daniel Borkmann   net: sctp: rework...
385
386
  	pr_debug("%s: asoc:%p dst:%p
  ", __func__, t->asoc, t->dst);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387

9914ae3ca   Vlad Yasevich   sctp: cache the i...
388
389
  	if (t->dst) {
  		saddr->v6.sin6_family = AF_INET6;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
390
  		saddr->v6.sin6_addr = fl6->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
392
393
394
395
396
397
398
399
400
  }
  
  /* 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;
8814c4b53   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
401
  	rcu_read_lock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
402
  	if ((in6_dev = __in6_dev_get(dev)) == NULL) {
8814c4b53   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
403
  		rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
404
405
  		return;
  	}
e2eb8d452   Jarek Poplawski   [SCTP] ipv6: inco...
406
  	read_lock_bh(&in6_dev->lock);
502a2ffd7   stephen hemminger   ipv6: convert ide...
407
  	list_for_each_entry(ifp, &in6_dev->addr_list, if_list) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  		/* Add the address to the local list.  */
939cfa75a   Daniel Borkmann   net: sctp: get ri...
409
  		addr = kzalloc(sizeof(*addr), GFP_ATOMIC);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
410
  		if (addr) {
2a6fd78ad   Al Viro   [SCTP] embedded s...
411
  			addr->a.v6.sin6_family = AF_INET6;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
412
  			addr->a.v6.sin6_addr = ifp->addr;
2a6fd78ad   Al Viro   [SCTP] embedded s...
413
  			addr->a.v6.sin6_scope_id = dev->ifindex;
293035479   Vlad Yasevich   [SCTP]: Add RCU s...
414
  			addr->valid = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
415
416
417
418
  			INIT_LIST_HEAD(&addr->list);
  			list_add_tail(&addr->list, addrlist);
  		}
  	}
e2eb8d452   Jarek Poplawski   [SCTP] ipv6: inco...
419
  	read_unlock_bh(&in6_dev->lock);
8814c4b53   YOSHIFUJI Hideaki   [IPV6] ADDRCONF: ...
420
  	rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
  }
b7e10c25b   Richard Haines   sctp: Add ip opti...
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
  /* Copy over any ip options */
  static void sctp_v6_copy_ip_options(struct sock *sk, struct sock *newsk)
  {
  	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
  	struct ipv6_txoptions *opt;
  
  	newnp = inet6_sk(newsk);
  
  	rcu_read_lock();
  	opt = rcu_dereference(np->opt);
  	if (opt) {
  		opt = ipv6_dup_options(newsk, opt);
  		if (!opt)
  			pr_err("%s: Failed to copy ip options
  ", __func__);
  	}
  	RCU_INIT_POINTER(newnp->opt, opt);
  	rcu_read_unlock();
  }
  
  /* Account for the IP options */
  static int sctp_v6_ip_options_len(struct sock *sk)
  {
  	struct ipv6_pinfo *np = inet6_sk(sk);
  	struct ipv6_txoptions *opt;
  	int len = 0;
  
  	rcu_read_lock();
  	opt = rcu_dereference(np->opt);
  	if (opt)
  		len = opt->opt_flen + opt->opt_nflen;
  
  	rcu_read_unlock();
  	return len;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
457
  /* Initialize a sockaddr_storage from in incoming skb. */
cb3f837ba   wangweidong   sctp: fix checkpa...
458
  static void sctp_v6_from_skb(union sctp_addr *addr, struct sk_buff *skb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
459
460
  			     int is_saddr)
  {
0630c56e4   Marcelo Ricardo Leitner   sctp: simplify ad...
461
462
463
  	/* Always called on head skb, so this is safe */
  	struct sctphdr *sh = sctp_hdr(skb);
  	struct sockaddr_in6 *sa = &addr->v6;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
465
466
467
  	addr->v6.sin6_family = AF_INET6;
  	addr->v6.sin6_flowinfo = 0; /* FIXME */
  	addr->v6.sin6_scope_id = ((struct inet6_skb_parm *)skb->cb)->iif;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
468
  	if (is_saddr) {
0630c56e4   Marcelo Ricardo Leitner   sctp: simplify ad...
469
470
  		sa->sin6_port = sh->source;
  		sa->sin6_addr = ipv6_hdr(skb)->saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
471
  	} else {
0630c56e4   Marcelo Ricardo Leitner   sctp: simplify ad...
472
473
  		sa->sin6_port = sh->dest;
  		sa->sin6_addr = ipv6_hdr(skb)->daddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
474
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
475
476
477
478
479
480
  }
  
  /* 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;
7dcdbd957   Al Viro   [SCTP]: Don't bot...
481
  	addr->v6.sin6_port = 0;
efe4208f4   Eric Dumazet   ipv6: make lookup...
482
  	addr->v6.sin6_addr = sk->sk_v6_rcv_saddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
483
484
485
486
487
  }
  
  /* Initialize sk->sk_rcv_saddr from sctp_addr. */
  static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
  {
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
488
  	if (addr->sa.sa_family == AF_INET) {
efe4208f4   Eric Dumazet   ipv6: make lookup...
489
490
491
492
  		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] =
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
  			addr->v4.sin_addr.s_addr;
  	} else {
efe4208f4   Eric Dumazet   ipv6: make lookup...
495
  		sk->sk_v6_rcv_saddr = addr->v6.sin6_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
496
497
498
499
500
501
  	}
  }
  
  /* Initialize sk->sk_daddr from sctp_addr. */
  static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
  {
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
502
  	if (addr->sa.sa_family == AF_INET) {
efe4208f4   Eric Dumazet   ipv6: make lookup...
503
504
505
506
  		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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
  	} else {
efe4208f4   Eric Dumazet   ipv6: make lookup...
508
  		sk->sk_v6_daddr = addr->v6.sin6_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
509
510
511
512
513
514
  	}
  }
  
  /* Initialize a sctp_addr from an address parameter. */
  static void sctp_v6_from_addr_param(union sctp_addr *addr,
  				    union sctp_addr_param *param,
dd86d136f   Al Viro   [SCTP]: Switch ->...
515
  				    __be16 port, int iif)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
518
519
  {
  	addr->v6.sin6_family = AF_INET6;
  	addr->v6.sin6_port = port;
  	addr->v6.sin6_flowinfo = 0; /* BUG */
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
520
  	addr->v6.sin6_addr = param->v6.addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
521
522
523
524
525
526
527
528
529
  	addr->v6.sin6_scope_id = iif;
  }
  
  /* 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)
  {
00987cc07   Xin Long   sctp: remove the ...
530
  	int length = sizeof(struct sctp_ipv6addr_param);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
  
  	param->v6.param_hdr.type = SCTP_PARAM_IPV6_ADDRESS;
dbc16db1e   Al Viro   [SCTP]: Trivial s...
533
  	param->v6.param_hdr.length = htons(length);
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
534
  	param->v6.addr = addr->v6.sin6_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
535
536
537
  
  	return length;
  }
9914ae3ca   Vlad Yasevich   sctp: cache the i...
538
539
  /* Initialize a sctp_addr from struct in6_addr. */
  static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
854d43a46   Al Viro   [SCTP]: Annotate ...
540
  			      __be16 port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
541
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
542
543
  	addr->sa.sa_family = AF_INET6;
  	addr->v6.sin6_port = port;
15339e441   Alexander Potapenko   sctp: fully initi...
544
  	addr->v6.sin6_flowinfo = 0;
4e3fd7a06   Alexey Dobriyan   net: remove ipv6_...
545
  	addr->v6.sin6_addr = *saddr;
15339e441   Alexander Potapenko   sctp: fully initi...
546
  	addr->v6.sin6_scope_id = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
  }
1071ec9d4   Xin Long   sctp: do not chec...
548
549
  static int __sctp_v6_cmp_addr(const union sctp_addr *addr1,
  			      const union sctp_addr *addr2)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
550
551
552
553
  {
  	if (addr1->sa.sa_family != addr2->sa.sa_family) {
  		if (addr1->sa.sa_family == AF_INET &&
  		    addr2->sa.sa_family == AF_INET6 &&
1071ec9d4   Xin Long   sctp: do not chec...
554
555
556
557
  		    ipv6_addr_v4mapped(&addr2->v6.sin6_addr) &&
  		    addr2->v6.sin6_addr.s6_addr32[3] ==
  		    addr1->v4.sin_addr.s_addr)
  			return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
  		if (addr2->sa.sa_family == AF_INET &&
  		    addr1->sa.sa_family == AF_INET6 &&
1071ec9d4   Xin Long   sctp: do not chec...
560
561
562
563
  		    ipv6_addr_v4mapped(&addr1->v6.sin6_addr) &&
  		    addr1->v6.sin6_addr.s6_addr32[3] ==
  		    addr2->v4.sin_addr.s_addr)
  			return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
564
565
  		return 0;
  	}
1071ec9d4   Xin Long   sctp: do not chec...
566

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
567
568
  	if (!ipv6_addr_equal(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr))
  		return 0;
1071ec9d4   Xin Long   sctp: do not chec...
569

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
570
  	/* If this is a linklocal address, compare the scope_id. */
1071ec9d4   Xin Long   sctp: do not chec...
571
572
573
574
  	if ((ipv6_addr_type(&addr1->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) &&
  	    addr1->v6.sin6_scope_id && addr2->v6.sin6_scope_id &&
  	    addr1->v6.sin6_scope_id != addr2->v6.sin6_scope_id)
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575
576
577
  
  	return 1;
  }
1071ec9d4   Xin Long   sctp: do not chec...
578
579
580
581
582
583
584
585
586
  /* 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)
  {
  	return __sctp_v6_cmp_addr(addr1, addr2) &&
  	       addr1->v6.sin6_port == addr2->v6.sin6_port;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
587
  /* Initialize addr struct to INADDR_ANY. */
6fbfa9f95   Al Viro   [SCTP]: Annotate ...
588
  static void sctp_v6_inaddr_any(union sctp_addr *addr, __be16 port)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
592
593
594
595
596
597
  {
  	memset(addr, 0x00, sizeof(union sctp_addr));
  	addr->v6.sin6_family = AF_INET6;
  	addr->v6.sin6_port = port;
  }
  
  /* Is this a wildcard address? */
  static int sctp_v6_is_any(const union sctp_addr *addr)
  {
b9b9e10f1   Brian Haley   [SCTP] Use ipv6_a...
598
  	return ipv6_addr_any(&addr->v6.sin6_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
599
600
601
602
603
604
  }
  
  /* Should this be available for binding?   */
  static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
  {
  	int type;
9b9742022   Xin Long   sctp: support ipv...
605
  	struct net *net = sock_net(&sp->inet.sk);
b71d1d426   Eric Dumazet   inet: constify ip...
606
  	const struct in6_addr *in6 = (const struct in6_addr *)&addr->v6.sin6_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
607
608
609
610
611
  
  	type = ipv6_addr_type(in6);
  	if (IPV6_ADDR_ANY == type)
  		return 1;
  	if (type == IPV6_ADDR_MAPPED) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
612
613
614
615
616
617
618
  		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;
9b9742022   Xin Long   sctp: support ipv...
619
620
  	return sp->inet.freebind || net->ipv6.sysctl.ip_nonlocal_bind ||
  		ipv6_chk_addr(net, in6, NULL, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
621
622
623
624
625
626
627
628
629
  }
  
  /* 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.
   */
5636bef73   Vlad Yasevich   [SCTP]: Reject sc...
630
631
632
  static int sctp_v6_addr_valid(union sctp_addr *addr,
  			      struct sctp_sock *sp,
  			      const struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
633
634
635
636
637
638
639
640
  {
  	int ret = ipv6_addr_type(&addr->v6.sin6_addr);
  
  	/* Support v4-mapped-v6 address. */
  	if (ret == IPV6_ADDR_MAPPED) {
  		/* Note: This routine is used in input, so v4-mapped-v6
  		 * are disallowed here when there is no sctp_sock.
  		 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
641
642
643
  		if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
  			return 0;
  		sctp_v6_map_v4(addr);
5636bef73   Vlad Yasevich   [SCTP]: Reject sc...
644
  		return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp, skb);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
645
646
647
648
649
650
651
652
653
654
  	}
  
  	/* Is this a non-unicast address */
  	if (!(ret & IPV6_ADDR_UNICAST))
  		return 0;
  
  	return 1;
  }
  
  /* What is the scope of 'addr'?  */
1c662018d   Xin Long   sctp: remove the ...
655
  static enum sctp_scope sctp_v6_scope(union sctp_addr *addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
656
  {
1c662018d   Xin Long   sctp: remove the ...
657
  	enum sctp_scope retval;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
658
  	int v6scope;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
  
  	/* The IPv6 scope is really a set of bit fields.
  	 * See IFA_* in <net/if_inet6.h>.  Map to a generic SCTP scope.
  	 */
  
  	v6scope = ipv6_addr_scope(&addr->v6.sin6_addr);
  	switch (v6scope) {
  	case IFA_HOST:
  		retval = SCTP_SCOPE_LOOPBACK;
  		break;
  	case IFA_LINK:
  		retval = SCTP_SCOPE_LINK;
  		break;
  	case IFA_SITE:
  		retval = SCTP_SCOPE_PRIVATE;
  		break;
  	default:
  		retval = SCTP_SCOPE_GLOBAL;
  		break;
3ff50b799   Stephen Hemminger   [NET]: cleanup ex...
678
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
679
680
681
682
683
684
  
  	return retval;
  }
  
  /* Create and initialize a new sk for the socket to be returned by accept(). */
  static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
cdfbabfb2   David Howells   net: Work around ...
685
686
  					     struct sctp_association *asoc,
  					     bool kern)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
688
  	struct sock *newsk;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
  	struct ipv6_pinfo *newnp, *np = inet6_sk(sk);
  	struct sctp6_sock *newsctp6sk;
cdfbabfb2   David Howells   net: Work around ...
691
  	newsk = sk_alloc(sock_net(sk), PF_INET6, GFP_KERNEL, sk->sk_prot, kern);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
694
695
  	if (!newsk)
  		goto out;
  
  	sock_init_data(NULL, newsk);
914e1c8b6   Vlad Yasevich   sctp: Inherit all...
696
  	sctp_copy_sock(newsk, sk, asoc);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
699
700
  	sock_reset_flag(sk, SOCK_ZAPPED);
  
  	newsctp6sk = (struct sctp6_sock *)newsk;
  	inet_sk(newsk)->pinet6 = &newsctp6sk->inet6;
b225b884a   Dave Johnson   SCTP: IPv4 mapped...
701
  	sctp_sk(newsk)->v4mapped = sctp_sk(sk)->v4mapped;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
702
703
704
  	newnp = inet6_sk(newsk);
  
  	memcpy(newnp, np, sizeof(struct ipv6_pinfo));
fdcee2cbb   Eric Dumazet   sctp: do not inhe...
705
706
707
  	newnp->ipv6_mc_list = NULL;
  	newnp->ipv6_ac_list = NULL;
  	newnp->ipv6_fl_list = NULL;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
708

b7e10c25b   Richard Haines   sctp: Add ip opti...
709
  	sctp_v6_copy_ip_options(sk, newsk);
9470e24f3   Eric Dumazet   ipv6: sctp: clone...
710

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
713
  	/* Initialize sk's sport, dport, rcv_saddr and daddr for getsockname()
  	 * and getpeername().
  	 */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
714
  	sctp_v6_to_sk_daddr(&asoc->peer.primary_addr, newsk);
661dbf341   Matija Glavinic Pecotic   net: sctp: fix in...
715
  	newsk->sk_v6_rcv_saddr = sk->sk_v6_rcv_saddr;
e6848976b   Arnaldo Carvalho de Melo   [NET]: Cleanup IN...
716
  	sk_refcnt_debug_inc(newsk);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
717
718
719
720
721
722
723
724
725
  
  	if (newsk->sk_prot->init(newsk)) {
  		sk_common_release(newsk);
  		newsk = NULL;
  	}
  
  out:
  	return newsk;
  }
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
726
727
728
729
  /* Format a sockaddr for return to user space. This makes sure the return is
   * AF_INET or AF_INET6 depending on the SCTP_I_WANT_MAPPED_V4_ADDR option.
   */
  static int sctp_v6_addr_to_user(struct sctp_sock *sp, union sctp_addr *addr)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
730
  {
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
731
732
733
734
735
736
737
738
  	if (sp->v4mapped) {
  		if (addr->sa.sa_family == AF_INET)
  			sctp_v4_map_v6(addr);
  	} else {
  		if (addr->sa.sa_family == AF_INET6 &&
  		    ipv6_addr_v4mapped(&addr->v6.sin6_addr))
  			sctp_v6_map_v4(addr);
  	}
6780db244   Eric Dumazet   sctp: do not leak...
739
740
  	if (addr->sa.sa_family == AF_INET) {
  		memset(addr->v4.sin_zero, 0, sizeof(addr->v4.sin_zero));
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
741
  		return sizeof(struct sockaddr_in);
6780db244   Eric Dumazet   sctp: do not leak...
742
  	}
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
743
  	return sizeof(struct sockaddr_in6);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
744
745
746
747
748
  }
  
  /* Where did this skb come from?  */
  static int sctp_v6_skb_iif(const struct sk_buff *skb)
  {
1f45f78f8   Marcelo Ricardo Leitner   sctp: allow GSO f...
749
  	return IP6CB(skb)->iif;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
750
751
752
753
754
  }
  
  /* Was this packet marked by Explicit Congestion Notification? */
  static int sctp_v6_is_ce(const struct sk_buff *skb)
  {
978aa0474   Xin Long   sctp: fix some ty...
755
  	return *((__u32 *)(ipv6_hdr(skb))) & (__force __u32)htonl(1 << 20);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
756
757
758
759
760
  }
  
  /* Dump the v6 addr to the seq file. */
  static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
  {
5b095d989   Harvey Harrison   net: replace %p6 ...
761
  	seq_printf(seq, "%pI6 ", &addr->v6.sin6_addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
  }
b9031d9d8   Vlad Yasevich   sctp: Fix ECN mar...
763
764
765
766
  static void sctp_v6_ecn_capable(struct sock *sk)
  {
  	inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
767
768
769
770
  /* Initialize a PF_INET msgname from a ulpevent. */
  static void sctp_inet6_event_msgname(struct sctp_ulpevent *event,
  				     char *msgname, int *addrlen)
  {
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
771
772
773
  	union sctp_addr *addr;
  	struct sctp_association *asoc;
  	union sctp_addr *paddr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
774

299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
775
776
  	if (!msgname)
  		return;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
777

299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
778
779
780
  	addr = (union sctp_addr *)msgname;
  	asoc = event->asoc;
  	paddr = &asoc->peer.primary_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
781

299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
782
783
784
785
786
787
788
789
790
791
792
793
794
  	if (paddr->sa.sa_family == AF_INET) {
  		addr->v4.sin_family = AF_INET;
  		addr->v4.sin_port = htons(asoc->peer.port);
  		addr->v4.sin_addr = paddr->v4.sin_addr;
  	} else {
  		addr->v6.sin6_family = AF_INET6;
  		addr->v6.sin6_flowinfo = 0;
  		if (ipv6_addr_type(&paddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
  			addr->v6.sin6_scope_id = paddr->v6.sin6_scope_id;
  		else
  			addr->v6.sin6_scope_id = 0;
  		addr->v6.sin6_port = htons(asoc->peer.port);
  		addr->v6.sin6_addr = paddr->v6.sin6_addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
  	}
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
796
797
  
  	*addrlen = sctp_v6_addr_to_user(sctp_sk(asoc->base.sk), addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
798
799
800
801
802
803
  }
  
  /* Initialize a msg_name from an inbound skb. */
  static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
  				   int *addr_len)
  {
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
804
  	union sctp_addr *addr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
  	struct sctphdr *sh;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
806

299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
807
808
809
810
811
812
813
814
815
  	if (!msgname)
  		return;
  
  	addr = (union sctp_addr *)msgname;
  	sh = sctp_hdr(skb);
  
  	if (ip_hdr(skb)->version == 4) {
  		addr->v4.sin_family = AF_INET;
  		addr->v4.sin_port = sh->source;
1f45f78f8   Marcelo Ricardo Leitner   sctp: allow GSO f...
816
  		addr->v4.sin_addr.s_addr = ip_hdr(skb)->saddr;
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
817
818
819
820
821
  	} else {
  		addr->v6.sin6_family = AF_INET6;
  		addr->v6.sin6_flowinfo = 0;
  		addr->v6.sin6_port = sh->source;
  		addr->v6.sin6_addr = ipv6_hdr(skb)->saddr;
7c8a61d9e   Eric W. Biederman   net/sctp: Always ...
822
  		if (ipv6_addr_type(&addr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
1f45f78f8   Marcelo Ricardo Leitner   sctp: allow GSO f...
823
  			addr->v6.sin6_scope_id = sctp_v6_skb_iif(skb);
7c8a61d9e   Eric W. Biederman   net/sctp: Always ...
824
825
  		else
  			addr->v6.sin6_scope_id = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
826
  	}
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
827
828
  
  	*addr_len = sctp_v6_addr_to_user(sctp_sk(skb->sk), addr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
829
830
831
832
833
834
835
836
837
838
  }
  
  /* Do we support this AF? */
  static int sctp_inet6_af_supported(sa_family_t family, struct sctp_sock *sp)
  {
  	switch (family) {
  	case AF_INET6:
  		return 1;
  	/* v4-mapped-v6 addresses */
  	case AF_INET:
7dab83de5   Vlad Yasevich   sctp: Support ipv...
839
  		if (!__ipv6_only_sock(sctp_opt2sk(sp)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
840
  			return 1;
37f47bc90   Marcelo Ricardo Leitner   sctp: avoid compi...
841
  		/* fallthru */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
842
843
844
845
846
847
848
849
850
851
852
853
854
  	default:
  		return 0;
  	}
  }
  
  /* Address matching with wildcards allowed.  This extra level
   * of indirection lets us choose whether a PF_INET6 should
   * disallow any v4 addresses if we so choose.
   */
  static int sctp_inet6_cmp_addr(const union sctp_addr *addr1,
  			       const union sctp_addr *addr2,
  			       struct sctp_sock *opt)
  {
52cae8f06   Vlad Yasevich   sctp: try harder ...
855
  	struct sock *sk = sctp_opt2sk(opt);
1071ec9d4   Xin Long   sctp: do not chec...
856
  	struct sctp_af *af1, *af2;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
857
858
859
860
861
862
  
  	af1 = sctp_get_af_specific(addr1->sa.sa_family);
  	af2 = sctp_get_af_specific(addr2->sa.sa_family);
  
  	if (!af1 || !af2)
  		return 0;
7dab83de5   Vlad Yasevich   sctp: Support ipv...
863
864
  
  	/* If the socket is IPv6 only, v4 addrs will not match */
52cae8f06   Vlad Yasevich   sctp: try harder ...
865
  	if (__ipv6_only_sock(sk) && af1 != af2)
7dab83de5   Vlad Yasevich   sctp: Support ipv...
866
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
867
  	/* Today, wildcard AF_INET/AF_INET6. */
52cae8f06   Vlad Yasevich   sctp: try harder ...
868
  	if (sctp_is_any(sk, addr1) || sctp_is_any(sk, addr2))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
869
  		return 1;
d625329b0   Xin Long   sctp: handle two ...
870
871
  	if (addr1->sa.sa_family == AF_INET && addr2->sa.sa_family == AF_INET)
  		return addr1->v4.sin_addr.s_addr == addr2->v4.sin_addr.s_addr;
1071ec9d4   Xin Long   sctp: do not chec...
872
  	return __sctp_v6_cmp_addr(addr1, addr2);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
873
874
875
876
877
878
879
880
881
882
883
884
885
  }
  
  /* Verify that the provided sockaddr looks bindable.   Common verification,
   * has already been taken care of.
   */
  static int sctp_inet6_bind_verify(struct sctp_sock *opt, union sctp_addr *addr)
  {
  	struct sctp_af *af;
  
  	/* ASSERT: address family has already been verified. */
  	if (addr->sa.sa_family != AF_INET6)
  		af = sctp_get_af_specific(addr->sa.sa_family);
  	else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
886
  		int type = ipv6_addr_type(&addr->v6.sin6_addr);
6a6ddb2a9   Sridhar Samudrala   [SCTP] Fix incorr...
887
  		struct net_device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
  		if (type & IPV6_ADDR_LINKLOCAL) {
bb2db45b5   Eric W. Biederman   sctp: Enable sctp...
889
  			struct net *net;
6a6ddb2a9   Sridhar Samudrala   [SCTP] Fix incorr...
890
891
  			if (!addr->v6.sin6_scope_id)
  				return 0;
bb2db45b5   Eric W. Biederman   sctp: Enable sctp...
892
  			net = sock_net(&opt->inet.sk);
40c9c31e3   Eric Dumazet   sctp: ipv6: avoid...
893
  			rcu_read_lock();
bb2db45b5   Eric W. Biederman   sctp: Enable sctp...
894
  			dev = dev_get_by_index_rcu(net, addr->v6.sin6_scope_id);
b71d21c27   Laszlo Toth   sctp: full suppor...
895
896
897
898
  			if (!dev || !(opt->inet.freebind ||
  				      net->ipv6.sysctl.ip_nonlocal_bind ||
  				      ipv6_chk_addr(net, &addr->v6.sin6_addr,
  						    dev, 0))) {
40c9c31e3   Eric Dumazet   sctp: ipv6: avoid...
899
  				rcu_read_unlock();
1669d857a   Vlad Yasevich   SCTP: Add scope_i...
900
901
  				return 0;
  			}
40c9c31e3   Eric Dumazet   sctp: ipv6: avoid...
902
  			rcu_read_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
903
  		}
7dab83de5   Vlad Yasevich   sctp: Support ipv...
904

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
905
906
907
908
  		af = opt->pf->af;
  	}
  	return af->available(addr, opt);
  }
6a6ddb2a9   Sridhar Samudrala   [SCTP] Fix incorr...
909
  /* Verify that the provided sockaddr looks sendable.   Common verification,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
910
911
912
913
914
915
916
917
918
919
   * has already been taken care of.
   */
  static int sctp_inet6_send_verify(struct sctp_sock *opt, union sctp_addr *addr)
  {
  	struct sctp_af *af = NULL;
  
  	/* ASSERT: address family has already been verified. */
  	if (addr->sa.sa_family != AF_INET6)
  		af = sctp_get_af_specific(addr->sa.sa_family);
  	else {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
920
  		int type = ipv6_addr_type(&addr->v6.sin6_addr);
6a6ddb2a9   Sridhar Samudrala   [SCTP] Fix incorr...
921
  		struct net_device *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
922
  		if (type & IPV6_ADDR_LINKLOCAL) {
6a6ddb2a9   Sridhar Samudrala   [SCTP] Fix incorr...
923
924
  			if (!addr->v6.sin6_scope_id)
  				return 0;
40c9c31e3   Eric Dumazet   sctp: ipv6: avoid...
925
  			rcu_read_lock();
bb2db45b5   Eric W. Biederman   sctp: Enable sctp...
926
  			dev = dev_get_by_index_rcu(sock_net(&opt->inet.sk),
40c9c31e3   Eric Dumazet   sctp: ipv6: avoid...
927
928
  						   addr->v6.sin6_scope_id);
  			rcu_read_unlock();
6a6ddb2a9   Sridhar Samudrala   [SCTP] Fix incorr...
929
  			if (!dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
  				return 0;
  		}
  		af = opt->pf->af;
  	}
  
  	return af != NULL;
  }
  
  /* Fill in Supported Address Type information for INIT and INIT-ACK
   * chunks.   Note: In the future, we may want to look at sock options
   * to determine whether a PF_INET6 socket really wants to have IPV4
   * addresses.
   * Returns number of addresses supported.
   */
  static int sctp_inet6_supported_addrs(const struct sctp_sock *opt,
3dbe86566   Al Viro   [SCTP]: Annotate ...
945
  				      __be16 *types)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
946
  {
7dab83de5   Vlad Yasevich   sctp: Support ipv...
947
948
949
950
951
952
  	types[0] = SCTP_PARAM_IPV6_ADDRESS;
  	if (!opt || !ipv6_only_sock(sctp_opt2sk(opt))) {
  		types[1] = SCTP_PARAM_IPV4_ADDRESS;
  		return 2;
  	}
  	return 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
953
  }
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
954
955
  /* Handle SCTP_I_WANT_MAPPED_V4_ADDR for getpeername() and getsockname() */
  static int sctp_getname(struct socket *sock, struct sockaddr *uaddr,
9b2c45d47   Denys Vlasenko   net: make getname...
956
  			int peer)
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
957
958
  {
  	int rc;
9b2c45d47   Denys Vlasenko   net: make getname...
959
  	rc = inet6_getname(sock, uaddr, peer);
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
960

9b2c45d47   Denys Vlasenko   net: make getname...
961
  	if (rc < 0)
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
962
  		return rc;
9b2c45d47   Denys Vlasenko   net: make getname...
963
  	rc = sctp_v6_addr_to_user(sctp_sk(sock->sk),
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
964
965
966
967
  					  (union sctp_addr *)uaddr);
  
  	return rc;
  }
90ddc4f04   Eric Dumazet   [NET]: move struc...
968
  static const struct proto_ops inet6_seqpacket_ops = {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
969
970
971
972
  	.family		   = PF_INET6,
  	.owner		   = THIS_MODULE,
  	.release	   = inet6_release,
  	.bind		   = inet6_bind,
644fbdeac   Xin Long   sctp: fix the iss...
973
  	.connect	   = sctp_inet_connect,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
974
975
  	.socketpair	   = sock_no_socketpair,
  	.accept		   = inet_accept,
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
976
  	.getname	   = sctp_getname,
a11e1d432   Linus Torvalds   Revert changes to...
977
  	.poll		   = sctp_poll,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
978
  	.ioctl		   = inet6_ioctl,
c7cbdbf29   Arnd Bergmann   net: rework SIOCG...
979
  	.gettstamp	   = sock_gettstamp,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
980
981
982
983
984
  	.listen		   = sctp_inet_listen,
  	.shutdown	   = inet_shutdown,
  	.setsockopt	   = sock_common_setsockopt,
  	.getsockopt	   = sock_common_getsockopt,
  	.sendmsg	   = inet_sendmsg,
fd2d180a2   Xin Long   sctp: use inet_re...
985
  	.recvmsg	   = inet_recvmsg,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
986
  	.mmap		   = sock_no_mmap,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
987
  #ifdef CONFIG_COMPAT
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
988
989
  	.compat_setsockopt = compat_sock_common_setsockopt,
  	.compat_getsockopt = compat_sock_common_getsockopt,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
990
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
991
992
993
994
995
996
997
  };
  
  static struct inet_protosw sctpv6_seqpacket_protosw = {
  	.type          = SOCK_SEQPACKET,
  	.protocol      = IPPROTO_SCTP,
  	.prot 	       = &sctpv6_prot,
  	.ops           = &inet6_seqpacket_ops,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
998
999
1000
1001
1002
1003
1004
  	.flags         = SCTP_PROTOSW_FLAG
  };
  static struct inet_protosw sctpv6_stream_protosw = {
  	.type          = SOCK_STREAM,
  	.protocol      = IPPROTO_SCTP,
  	.prot 	       = &sctpv6_prot,
  	.ops           = &inet6_seqpacket_ops,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1005
1006
  	.flags         = SCTP_PROTOSW_FLAG,
  };
e5bbef20e   Herbert Xu   [IPV6]: Replace s...
1007
  static int sctp6_rcv(struct sk_buff *skb)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1008
  {
e5bbef20e   Herbert Xu   [IPV6]: Replace s...
1009
  	return sctp_rcv(skb) ? -1 : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1010
  }
41135cc83   Alexey Dobriyan   net: constify str...
1011
  static const struct inet6_protocol sctpv6_protocol = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1012
1013
1014
1015
  	.handler      = sctp6_rcv,
  	.err_handler  = sctp_v6_err,
  	.flags        = INET6_PROTO_NOPOLICY | INET6_PROTO_FINAL,
  };
15efbe763   Neil Horman   [SCTP]: Clean up ...
1016
  static struct sctp_af sctp_af_inet6 = {
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1017
1018
1019
1020
1021
1022
1023
1024
1025
  	.sa_family	   = AF_INET6,
  	.sctp_xmit	   = sctp_v6_xmit,
  	.setsockopt	   = ipv6_setsockopt,
  	.getsockopt	   = ipv6_getsockopt,
  	.get_dst	   = sctp_v6_get_dst,
  	.get_saddr	   = sctp_v6_get_saddr,
  	.copy_addrlist	   = sctp_v6_copy_addrlist,
  	.from_skb	   = sctp_v6_from_skb,
  	.from_sk	   = sctp_v6_from_sk,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1026
1027
  	.from_addr_param   = sctp_v6_from_addr_param,
  	.to_addr_param	   = sctp_v6_to_addr_param,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1028
1029
1030
1031
1032
1033
1034
1035
1036
  	.cmp_addr	   = sctp_v6_cmp_addr,
  	.scope		   = sctp_v6_scope,
  	.addr_valid	   = sctp_v6_addr_valid,
  	.inaddr_any	   = sctp_v6_inaddr_any,
  	.is_any		   = sctp_v6_is_any,
  	.available	   = sctp_v6_available,
  	.skb_iif	   = sctp_v6_skb_iif,
  	.is_ce		   = sctp_v6_is_ce,
  	.seq_dump_addr	   = sctp_v6_seq_dump_addr,
b9031d9d8   Vlad Yasevich   sctp: Fix ECN mar...
1037
  	.ecn_capable	   = sctp_v6_ecn_capable,
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1038
1039
  	.net_header_len	   = sizeof(struct ipv6hdr),
  	.sockaddr_len	   = sizeof(struct sockaddr_in6),
b7e10c25b   Richard Haines   sctp: Add ip opti...
1040
  	.ip_options_len	   = sctp_v6_ip_options_len,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1041
  #ifdef CONFIG_COMPAT
543d9cfee   Arnaldo Carvalho de Melo   [NET]: Identation...
1042
1043
  	.compat_setsockopt = compat_ipv6_setsockopt,
  	.compat_getsockopt = compat_ipv6_getsockopt,
3fdadf7d2   Dmitry Mishin   [NET]: {get|set}s...
1044
  #endif
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1045
  };
15efbe763   Neil Horman   [SCTP]: Clean up ...
1046
  static struct sctp_pf sctp_pf_inet6 = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1047
1048
1049
1050
1051
1052
1053
1054
  	.event_msgname = sctp_inet6_event_msgname,
  	.skb_msgname   = sctp_inet6_skb_msgname,
  	.af_supported  = sctp_inet6_af_supported,
  	.cmp_addr      = sctp_inet6_cmp_addr,
  	.bind_verify   = sctp_inet6_bind_verify,
  	.send_verify   = sctp_inet6_send_verify,
  	.supported_addrs = sctp_inet6_supported_addrs,
  	.create_accept_sk = sctp_v6_create_accept_sk,
299ee123e   Jason Gunthorpe   sctp: Fixup v4map...
1055
1056
1057
  	.addr_to_user  = sctp_v6_addr_to_user,
  	.to_sk_saddr   = sctp_v6_to_sk_saddr,
  	.to_sk_daddr   = sctp_v6_to_sk_daddr,
b7e10c25b   Richard Haines   sctp: Add ip opti...
1058
  	.copy_ip_options = sctp_v6_copy_ip_options,
15efbe763   Neil Horman   [SCTP]: Clean up ...
1059
  	.af            = &sctp_af_inet6,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1060
  };
827bf1223   Sridhar Samudrala   [SCTP]: Re-order ...
1061
  /* Initialize IPv6 support and register with socket layer.  */
270637abf   Vlad Yasevich   [SCTP]: Fix a rac...
1062
  void sctp_v6_pf_init(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1063
  {
827bf1223   Sridhar Samudrala   [SCTP]: Re-order ...
1064
  	/* Register the SCTP specific PF_INET6 functions. */
15efbe763   Neil Horman   [SCTP]: Clean up ...
1065
  	sctp_register_pf(&sctp_pf_inet6, PF_INET6);
827bf1223   Sridhar Samudrala   [SCTP]: Re-order ...
1066
1067
  
  	/* Register the SCTP specific AF_INET6 functions. */
15efbe763   Neil Horman   [SCTP]: Clean up ...
1068
  	sctp_register_af(&sctp_af_inet6);
270637abf   Vlad Yasevich   [SCTP]: Fix a rac...
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
  }
  
  void sctp_v6_pf_exit(void)
  {
  	list_del(&sctp_af_inet6.list);
  }
  
  /* Initialize IPv6 support and register with socket layer.  */
  int sctp_v6_protosw_init(void)
  {
  	int rc;
827bf1223   Sridhar Samudrala   [SCTP]: Re-order ...
1080
1081
  
  	rc = proto_register(&sctpv6_prot, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1082
  	if (rc)
827bf1223   Sridhar Samudrala   [SCTP]: Re-order ...
1083
  		return rc;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1084
1085
1086
1087
  
  	/* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */
  	inet6_register_protosw(&sctpv6_seqpacket_protosw);
  	inet6_register_protosw(&sctpv6_stream_protosw);
827bf1223   Sridhar Samudrala   [SCTP]: Re-order ...
1088
1089
  	return 0;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1090

270637abf   Vlad Yasevich   [SCTP]: Fix a rac...
1091
1092
1093
1094
1095
1096
  void sctp_v6_protosw_exit(void)
  {
  	inet6_unregister_protosw(&sctpv6_seqpacket_protosw);
  	inet6_unregister_protosw(&sctpv6_stream_protosw);
  	proto_unregister(&sctpv6_prot);
  }
827bf1223   Sridhar Samudrala   [SCTP]: Re-order ...
1097
1098
1099
  /* Register with inet6 layer. */
  int sctp_v6_add_protocol(void)
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1100
1101
  	/* Register notifier for inet6 address additions/deletions. */
  	register_inet6addr_notifier(&sctp_inet6addr_notifier);
827bf1223   Sridhar Samudrala   [SCTP]: Re-order ...
1102
1103
1104
1105
1106
  
  	if (inet6_add_protocol(&sctpv6_protocol, IPPROTO_SCTP) < 0)
  		return -EAGAIN;
  
  	return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1107
  }
827bf1223   Sridhar Samudrala   [SCTP]: Re-order ...
1108
1109
1110
1111
1112
  /* Unregister with inet6 layer. */
  void sctp_v6_del_protocol(void)
  {
  	inet6_del_protocol(&sctpv6_protocol, IPPROTO_SCTP);
  	unregister_inet6addr_notifier(&sctp_inet6addr_notifier);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1113
  }