aboutsummaryrefslogtreecommitdiffstats
path: root/net/sctp/ipv6.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sctp/ipv6.c')
-rw-r--r--net/sctp/ipv6.c215
1 files changed, 123 insertions, 92 deletions
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c
index 732689140fb8..0bb0d7cb9f10 100644
--- a/net/sctp/ipv6.c
+++ b/net/sctp/ipv6.c
@@ -47,6 +47,8 @@
47 * be incorporated into the next SCTP release. 47 * be incorporated into the next SCTP release.
48 */ 48 */
49 49
50#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
51
50#include <linux/module.h> 52#include <linux/module.h>
51#include <linux/errno.h> 53#include <linux/errno.h>
52#include <linux/types.h> 54#include <linux/types.h>
@@ -78,6 +80,13 @@
78 80
79#include <asm/uaccess.h> 81#include <asm/uaccess.h>
80 82
83static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
84 union sctp_addr *s2);
85static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
86 __be16 port);
87static int sctp_v6_cmp_addr(const union sctp_addr *addr1,
88 const union sctp_addr *addr2);
89
81/* Event handler for inet6 address addition/deletion events. 90/* Event handler for inet6 address addition/deletion events.
82 * The sctp_local_addr_list needs to be protocted by a spin lock since 91 * The sctp_local_addr_list needs to be protocted by a spin lock since
83 * multiple notifiers (say IPv4 and IPv6) may be running at the same 92 * multiple notifiers (say IPv4 and IPv6) may be running at the same
@@ -121,7 +130,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
121 } 130 }
122 spin_unlock_bh(&sctp_local_addr_lock); 131 spin_unlock_bh(&sctp_local_addr_lock);
123 if (found) 132 if (found)
124 call_rcu(&addr->rcu, sctp_local_addr_free); 133 kfree_rcu(addr, rcu);
125 break; 134 break;
126 } 135 }
127 136
@@ -199,76 +208,146 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport)
199{ 208{
200 struct sock *sk = skb->sk; 209 struct sock *sk = skb->sk;
201 struct ipv6_pinfo *np = inet6_sk(sk); 210 struct ipv6_pinfo *np = inet6_sk(sk);
202 struct flowi fl; 211 struct flowi6 fl6;
203 212
204 memset(&fl, 0, sizeof(fl)); 213 memset(&fl6, 0, sizeof(fl6));
205 214
206 fl.proto = sk->sk_protocol; 215 fl6.flowi6_proto = sk->sk_protocol;
207 216
208 /* Fill in the dest address from the route entry passed with the skb 217 /* Fill in the dest address from the route entry passed with the skb
209 * and the source address from the transport. 218 * and the source address from the transport.
210 */ 219 */
211 ipv6_addr_copy(&fl.fl6_dst, &transport->ipaddr.v6.sin6_addr); 220 ipv6_addr_copy(&fl6.daddr, &transport->ipaddr.v6.sin6_addr);
212 ipv6_addr_copy(&fl.fl6_src, &transport->saddr.v6.sin6_addr); 221 ipv6_addr_copy(&fl6.saddr, &transport->saddr.v6.sin6_addr);
213 222
214 fl.fl6_flowlabel = np->flow_label; 223 fl6.flowlabel = np->flow_label;
215 IP6_ECN_flow_xmit(sk, fl.fl6_flowlabel); 224 IP6_ECN_flow_xmit(sk, fl6.flowlabel);
216 if (ipv6_addr_type(&fl.fl6_src) & IPV6_ADDR_LINKLOCAL) 225 if (ipv6_addr_type(&fl6.saddr) & IPV6_ADDR_LINKLOCAL)
217 fl.oif = transport->saddr.v6.sin6_scope_id; 226 fl6.flowi6_oif = transport->saddr.v6.sin6_scope_id;
218 else 227 else
219 fl.oif = sk->sk_bound_dev_if; 228 fl6.flowi6_oif = sk->sk_bound_dev_if;
220 229
221 if (np->opt && np->opt->srcrt) { 230 if (np->opt && np->opt->srcrt) {
222 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt; 231 struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
223 ipv6_addr_copy(&fl.fl6_dst, rt0->addr); 232 ipv6_addr_copy(&fl6.daddr, rt0->addr);
224 } 233 }
225 234
226 SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n", 235 SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n",
227 __func__, skb, skb->len, 236 __func__, skb, skb->len,
228 &fl.fl6_src, &fl.fl6_dst); 237 &fl6.saddr, &fl6.daddr);
229 238
230 SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS); 239 SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
231 240
232 if (!(transport->param_flags & SPP_PMTUD_ENABLE)) 241 if (!(transport->param_flags & SPP_PMTUD_ENABLE))
233 skb->local_df = 1; 242 skb->local_df = 1;
234 243
235 return ip6_xmit(sk, skb, &fl, np->opt); 244 return ip6_xmit(sk, skb, &fl6, np->opt);
236} 245}
237 246
238/* Returns the dst cache entry for the given source and destination ip 247/* Returns the dst cache entry for the given source and destination ip
239 * addresses. 248 * addresses.
240 */ 249 */
241static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc, 250static void sctp_v6_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
242 union sctp_addr *daddr, 251 struct flowi *fl, struct sock *sk)
243 union sctp_addr *saddr)
244{ 252{
245 struct dst_entry *dst; 253 struct sctp_association *asoc = t->asoc;
246 struct flowi fl; 254 struct dst_entry *dst = NULL;
255 struct flowi6 *fl6 = &fl->u.ip6;
256 struct sctp_bind_addr *bp;
257 struct sctp_sockaddr_entry *laddr;
258 union sctp_addr *baddr = NULL;
259 union sctp_addr *daddr = &t->ipaddr;
260 union sctp_addr dst_saddr;
261 __u8 matchlen = 0;
262 __u8 bmatchlen;
263 sctp_scope_t scope;
247 264
248 memset(&fl, 0, sizeof(fl)); 265 memset(fl6, 0, sizeof(struct flowi6));
249 ipv6_addr_copy(&fl.fl6_dst, &daddr->v6.sin6_addr); 266 ipv6_addr_copy(&fl6->daddr, &daddr->v6.sin6_addr);
267 fl6->fl6_dport = daddr->v6.sin6_port;
268 fl6->flowi6_proto = IPPROTO_SCTP;
250 if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL) 269 if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
251 fl.oif = daddr->v6.sin6_scope_id; 270 fl6->flowi6_oif = daddr->v6.sin6_scope_id;
252 271
272 SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl6->daddr);
253 273
254 SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl.fl6_dst); 274 if (asoc)
275 fl6->fl6_sport = htons(asoc->base.bind_addr.port);
255 276
256 if (saddr) { 277 if (saddr) {
257 ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr); 278 ipv6_addr_copy(&fl6->saddr, &saddr->v6.sin6_addr);
258 SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl.fl6_src); 279 fl6->fl6_sport = saddr->v6.sin6_port;
280 SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl6->saddr);
281 }
282
283 dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
284 if (!asoc || saddr)
285 goto out;
286
287 bp = &asoc->base.bind_addr;
288 scope = sctp_scope(daddr);
289 /* ip6_dst_lookup has filled in the fl6->saddr for us. Check
290 * to see if we can use it.
291 */
292 if (!IS_ERR(dst)) {
293 /* Walk through the bind address list and look for a bind
294 * address that matches the source address of the returned dst.
295 */
296 sctp_v6_to_addr(&dst_saddr, &fl6->saddr, htons(bp->port));
297 rcu_read_lock();
298 list_for_each_entry_rcu(laddr, &bp->address_list, list) {
299 if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
300 continue;
301
302 /* Do not compare against v4 addrs */
303 if ((laddr->a.sa.sa_family == AF_INET6) &&
304 (sctp_v6_cmp_addr(&dst_saddr, &laddr->a))) {
305 rcu_read_unlock();
306 goto out;
307 }
308 }
309 rcu_read_unlock();
310 /* None of the bound addresses match the source address of the
311 * dst. So release it.
312 */
313 dst_release(dst);
314 dst = NULL;
315 }
316
317 /* Walk through the bind address list and try to get the
318 * best source address for a given destination.
319 */
320 rcu_read_lock();
321 list_for_each_entry_rcu(laddr, &bp->address_list, list) {
322 if (!laddr->valid && laddr->state != SCTP_ADDR_SRC)
323 continue;
324 if ((laddr->a.sa.sa_family == AF_INET6) &&
325 (scope <= sctp_scope(&laddr->a))) {
326 bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
327 if (!baddr || (matchlen < bmatchlen)) {
328 baddr = &laddr->a;
329 matchlen = bmatchlen;
330 }
331 }
332 }
333 rcu_read_unlock();
334 if (baddr) {
335 ipv6_addr_copy(&fl6->saddr, &baddr->v6.sin6_addr);
336 fl6->fl6_sport = baddr->v6.sin6_port;
337 dst = ip6_dst_lookup_flow(sk, fl6, NULL, false);
259 } 338 }
260 339
261 dst = ip6_route_output(&init_net, NULL, &fl); 340out:
262 if (!dst->error) { 341 if (!IS_ERR(dst)) {
263 struct rt6_info *rt; 342 struct rt6_info *rt;
264 rt = (struct rt6_info *)dst; 343 rt = (struct rt6_info *)dst;
344 t->dst = dst;
265 SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n", 345 SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n",
266 &rt->rt6i_dst.addr, &rt->rt6i_src.addr); 346 &rt->rt6i_dst.addr, &fl6->saddr);
267 return dst; 347 } else {
348 t->dst = NULL;
349 SCTP_DEBUG_PRINTK("NO ROUTE\n");
268 } 350 }
269 SCTP_DEBUG_PRINTK("NO ROUTE\n");
270 dst_release(dst);
271 return NULL;
272} 351}
273 352
274/* Returns the number of consecutive initial bits that match in the 2 ipv6 353/* Returns the number of consecutive initial bits that match in the 2 ipv6
@@ -284,64 +363,18 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
284 * and asoc's bind address list. 363 * and asoc's bind address list.
285 */ 364 */
286static void sctp_v6_get_saddr(struct sctp_sock *sk, 365static void sctp_v6_get_saddr(struct sctp_sock *sk,
287 struct sctp_association *asoc, 366 struct sctp_transport *t,
288 struct dst_entry *dst, 367 struct flowi *fl)
289 union sctp_addr *daddr,
290 union sctp_addr *saddr)
291{ 368{
292 struct sctp_bind_addr *bp; 369 struct flowi6 *fl6 = &fl->u.ip6;
293 struct sctp_sockaddr_entry *laddr; 370 union sctp_addr *saddr = &t->saddr;
294 sctp_scope_t scope;
295 union sctp_addr *baddr = NULL;
296 __u8 matchlen = 0;
297 __u8 bmatchlen;
298 371
299 SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ", 372 SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p\n", __func__, t->asoc, t->dst);
300 __func__, asoc, dst, &daddr->v6.sin6_addr);
301
302 if (!asoc) {
303 ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)),
304 dst ? ip6_dst_idev(dst)->dev : NULL,
305 &daddr->v6.sin6_addr,
306 inet6_sk(&sk->inet.sk)->srcprefs,
307 &saddr->v6.sin6_addr);
308 SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n",
309 &saddr->v6.sin6_addr);
310 return;
311 }
312
313 scope = sctp_scope(daddr);
314
315 bp = &asoc->base.bind_addr;
316 373
317 /* Go through the bind address list and find the best source address 374 if (t->dst) {
318 * that matches the scope of the destination address. 375 saddr->v6.sin6_family = AF_INET6;
319 */ 376 ipv6_addr_copy(&saddr->v6.sin6_addr, &fl6->saddr);
320 rcu_read_lock();
321 list_for_each_entry_rcu(laddr, &bp->address_list, list) {
322 if (!laddr->valid)
323 continue;
324 if ((laddr->state == SCTP_ADDR_SRC) &&
325 (laddr->a.sa.sa_family == AF_INET6) &&
326 (scope <= sctp_scope(&laddr->a))) {
327 bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
328 if (!baddr || (matchlen < bmatchlen)) {
329 baddr = &laddr->a;
330 matchlen = bmatchlen;
331 }
332 }
333 }
334
335 if (baddr) {
336 memcpy(saddr, baddr, sizeof(union sctp_addr));
337 SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
338 } else {
339 printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
340 "address for the dest:%pI6\n",
341 __func__, asoc, &daddr->v6.sin6_addr);
342 } 377 }
343
344 rcu_read_unlock();
345} 378}
346 379
347/* Make a copy of all potential local addresses. */ 380/* Make a copy of all potential local addresses. */
@@ -463,14 +496,13 @@ static int sctp_v6_to_addr_param(const union sctp_addr *addr,
463 return length; 496 return length;
464} 497}
465 498
466/* Initialize a sctp_addr from a dst_entry. */ 499/* Initialize a sctp_addr from struct in6_addr. */
467static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst, 500static void sctp_v6_to_addr(union sctp_addr *addr, struct in6_addr *saddr,
468 __be16 port) 501 __be16 port)
469{ 502{
470 struct rt6_info *rt = (struct rt6_info *)dst;
471 addr->sa.sa_family = AF_INET6; 503 addr->sa.sa_family = AF_INET6;
472 addr->v6.sin6_port = port; 504 addr->v6.sin6_port = port;
473 ipv6_addr_copy(&addr->v6.sin6_addr, &rt->rt6i_src.addr); 505 ipv6_addr_copy(&addr->v6.sin6_addr, saddr);
474} 506}
475 507
476/* Compare addresses exactly. 508/* Compare addresses exactly.
@@ -529,7 +561,7 @@ static int sctp_v6_is_any(const union sctp_addr *addr)
529static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp) 561static int sctp_v6_available(union sctp_addr *addr, struct sctp_sock *sp)
530{ 562{
531 int type; 563 int type;
532 struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr; 564 const struct in6_addr *in6 = (const struct in6_addr *)&addr->v6.sin6_addr;
533 565
534 type = ipv6_addr_type(in6); 566 type = ipv6_addr_type(in6);
535 if (IPV6_ADDR_ANY == type) 567 if (IPV6_ADDR_ANY == type)
@@ -957,7 +989,6 @@ static struct sctp_af sctp_af_inet6 = {
957 .to_sk_daddr = sctp_v6_to_sk_daddr, 989 .to_sk_daddr = sctp_v6_to_sk_daddr,
958 .from_addr_param = sctp_v6_from_addr_param, 990 .from_addr_param = sctp_v6_from_addr_param,
959 .to_addr_param = sctp_v6_to_addr_param, 991 .to_addr_param = sctp_v6_to_addr_param,
960 .dst_saddr = sctp_v6_dst_saddr,
961 .cmp_addr = sctp_v6_cmp_addr, 992 .cmp_addr = sctp_v6_cmp_addr,
962 .scope = sctp_v6_scope, 993 .scope = sctp_v6_scope,
963 .addr_valid = sctp_v6_addr_valid, 994 .addr_valid = sctp_v6_addr_valid,