skb->network_header = saveip;
skb->transport_header = savesctp;
if (!sk) {
- ICMP6_INC_STATS_BH(idev, ICMP6_MIB_INERRORS);
+ ICMP6_INC_STATS_BH(dev_net(skb->dev), idev, ICMP6_MIB_INERRORS);
goto out;
}
}
/* Based on tcp_v6_xmit() in tcp_ipv6.c. */
-static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
- int ipfragok)
+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);
ipv6_addr_copy(&fl.fl6_dst, rt0->addr);
}
- SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
- "src:" NIP6_FMT " dst:" NIP6_FMT "\n",
+ SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, src:%pI6 dst:%pI6\n",
__func__, skb, skb->len,
- NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
+ &fl.fl6_src, &fl.fl6_dst);
SCTP_INC_STATS(SCTP_MIB_OUTSCTPPACKS);
- return ip6_xmit(sk, skb, &fl, np->opt, ipfragok);
+ if (!(transport->param_flags & SPP_PMTUD_ENABLE))
+ skb->local_df = 1;
+
+ return ip6_xmit(sk, skb, &fl, np->opt, 0);
}
/* Returns the dst cache entry for the given source and destination ip
fl.oif = daddr->v6.sin6_scope_id;
- SCTP_DEBUG_PRINTK("%s: DST=" NIP6_FMT " ",
- __func__, NIP6(fl.fl6_dst));
+ SCTP_DEBUG_PRINTK("%s: DST=%pI6 ", __func__, &fl.fl6_dst);
if (saddr) {
ipv6_addr_copy(&fl.fl6_src, &saddr->v6.sin6_addr);
- SCTP_DEBUG_PRINTK(
- "SRC=" NIP6_FMT " - ",
- NIP6(fl.fl6_src));
+ SCTP_DEBUG_PRINTK("SRC=%pI6 - ", &fl.fl6_src);
}
dst = ip6_route_output(&init_net, NULL, &fl);
if (!dst->error) {
struct rt6_info *rt;
rt = (struct rt6_info *)dst;
- SCTP_DEBUG_PRINTK(
- "rt6_dst:" NIP6_FMT " rt6_src:" NIP6_FMT "\n",
- NIP6(rt->rt6i_dst.addr), NIP6(rt->rt6i_src.addr));
+ SCTP_DEBUG_PRINTK("rt6_dst:%pI6 rt6_src:%pI6\n",
+ &rt->rt6i_dst.addr, &rt->rt6i_src.addr);
return dst;
}
SCTP_DEBUG_PRINTK("NO ROUTE\n");
/* 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_association *asoc,
+static void sctp_v6_get_saddr(struct sctp_sock *sk,
+ struct sctp_association *asoc,
struct dst_entry *dst,
union sctp_addr *daddr,
union sctp_addr *saddr)
__u8 matchlen = 0;
__u8 bmatchlen;
- SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p "
- "daddr:" NIP6_FMT " ",
- __func__, asoc, dst, NIP6(daddr->v6.sin6_addr));
+ SCTP_DEBUG_PRINTK("%s: asoc:%p dst:%p daddr:%pI6 ",
+ __func__, asoc, dst, &daddr->v6.sin6_addr);
if (!asoc) {
- ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL,
+ ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)),
+ dst ? ip6_dst_idev(dst)->dev : NULL,
&daddr->v6.sin6_addr,
- inet6_sk(asoc->base.sk)->srcprefs,
+ inet6_sk(&sk->inet.sk)->srcprefs,
&saddr->v6.sin6_addr);
- SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n",
- NIP6(saddr->v6.sin6_addr));
+ SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: %pI6\n",
+ &saddr->v6.sin6_addr);
return;
}
if (baddr) {
memcpy(saddr, baddr, sizeof(union sctp_addr));
- SCTP_DEBUG_PRINTK("saddr: " NIP6_FMT "\n",
- NIP6(saddr->v6.sin6_addr));
+ SCTP_DEBUG_PRINTK("saddr: %pI6\n", &saddr->v6.sin6_addr);
} else {
printk(KERN_ERR "%s: asoc:%p Could not find a valid source "
- "address for the dest:" NIP6_FMT "\n",
- __func__, asoc, NIP6(daddr->v6.sin6_addr));
+ "address for the dest:%pI6\n",
+ __func__, asoc, &daddr->v6.sin6_addr);
}
rcu_read_unlock();
/* Dump the v6 addr to the seq file. */
static void sctp_v6_seq_dump_addr(struct seq_file *seq, union sctp_addr *addr)
{
- seq_printf(seq, NIP6_FMT " ", NIP6(addr->v6.sin6_addr));
+ seq_printf(seq, "%pI6 ", &addr->v6.sin6_addr);
+}
+
+static void sctp_v6_ecn_capable(struct sock *sk)
+{
+ inet6_sk(sk)->tclass |= INET_ECN_ECT_0;
}
/* Initialize a PF_INET6 socket msg_name. */
return 1;
/* v4-mapped-v6 addresses */
case AF_INET:
- if (!__ipv6_only_sock(sctp_opt2sk(sp)) && sp->v4mapped)
+ if (!__ipv6_only_sock(sctp_opt2sk(sp)))
return 1;
default:
return 0;
struct sctp_sock *opt)
{
struct sctp_af *af1, *af2;
+ struct sock *sk = sctp_opt2sk(opt);
af1 = sctp_get_af_specific(addr1->sa.sa_family);
af2 = sctp_get_af_specific(addr2->sa.sa_family);
if (!af1 || !af2)
return 0;
+
+ /* If the socket is IPv6 only, v4 addrs will not match */
+ if (__ipv6_only_sock(sk) && af1 != af2)
+ return 0;
+
/* Today, wildcard AF_INET/AF_INET6. */
- if (sctp_is_any(addr1) || sctp_is_any(addr2))
+ if (sctp_is_any(sk, addr1) || sctp_is_any(sk, addr2))
return 1;
if (addr1->sa.sa_family != addr2->sa.sa_family)
return 0;
}
dev_put(dev);
+ } else if (type == IPV6_ADDR_MAPPED) {
+ if (!opt->v4mapped)
+ return 0;
}
+
af = opt->pf->af;
}
return af->available(addr, opt);
static int sctp_inet6_supported_addrs(const struct sctp_sock *opt,
__be16 *types)
{
- types[0] = SCTP_PARAM_IPV4_ADDRESS;
- types[1] = SCTP_PARAM_IPV6_ADDRESS;
- return 2;
+ types[0] = SCTP_PARAM_IPV6_ADDRESS;
+ if (!opt || !ipv6_only_sock(sctp_opt2sk(opt))) {
+ types[1] = SCTP_PARAM_IPV4_ADDRESS;
+ return 2;
+ }
+ return 1;
}
static const struct proto_ops inet6_seqpacket_ops = {
.skb_iif = sctp_v6_skb_iif,
.is_ce = sctp_v6_is_ce,
.seq_dump_addr = sctp_v6_seq_dump_addr,
+ .ecn_capable = sctp_v6_ecn_capable,
.net_header_len = sizeof(struct ipv6hdr),
.sockaddr_len = sizeof(struct sockaddr_in6),
#ifdef CONFIG_COMPAT