patch-2.4.26 linux-2.4.26/net/sctp/ipv6.c

Next file: linux-2.4.26/net/sctp/objcnt.c
Previous file: linux-2.4.26/net/sctp/inqueue.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.25/net/sctp/ipv6.c linux-2.4.26/net/sctp/ipv6.c
@@ -2,6 +2,7 @@
  * Copyright (c) 2001 Nokia, Inc.
  * Copyright (c) 2001 La Monte H.P. Yarroll
  * Copyright (c) 2002-2003 International Business Machines, Corp.
+ * Copyright (c) 2002-2003 Intel Corp.
  *
  * This file is part of the SCTP kernel reference Implementation
  *
@@ -15,7 +16,7 @@
  *
  * The SCTP reference 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.
  *
@@ -32,14 +33,15 @@
  *    http://www.sf.net/projects/lksctp
  *
  * Written or modified by:
- *    Le Yanqun             <yanqun.le@nokia.com>
+ *    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>
+ *    Jon Grimm		    <jgrimm@us.ibm.com>
+ *    Ardelle Fan	    <ardelle.fan@intel.com>
  *
  * Based on:
- *      linux/net/ipv6/tcp_ipv6.c
+ *	linux/net/ipv6/tcp_ipv6.c
  *
  * Any bugs reported given to us we will try to fix... any fixes shared will
  * be incorporated into the next SCTP release.
@@ -61,6 +63,7 @@
 #include <linux/ipv6.h>
 #include <linux/icmpv6.h>
 #include <linux/random.h>
+#include <linux/seq_file.h>
 
 #include <net/protocol.h>
 #include <net/tcp.h>
@@ -79,14 +82,14 @@
 
 /* FIXME: This macro needs to be moved to a common header file. */
 #define NIP6(addr) \
-        ntohs((addr)->s6_addr16[0]), \
-        ntohs((addr)->s6_addr16[1]), \
-        ntohs((addr)->s6_addr16[2]), \
-        ntohs((addr)->s6_addr16[3]), \
-        ntohs((addr)->s6_addr16[4]), \
-        ntohs((addr)->s6_addr16[5]), \
-        ntohs((addr)->s6_addr16[6]), \
-        ntohs((addr)->s6_addr16[7])
+	ntohs((addr)->s6_addr16[0]), \
+	ntohs((addr)->s6_addr16[1]), \
+	ntohs((addr)->s6_addr16[2]), \
+	ntohs((addr)->s6_addr16[3]), \
+	ntohs((addr)->s6_addr16[4]), \
+	ntohs((addr)->s6_addr16[5]), \
+	ntohs((addr)->s6_addr16[6]), \
+	ntohs((addr)->s6_addr16[7])
 
 /* ICMP error handler. */
 void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
@@ -134,10 +137,10 @@
 	np = inet6_sk(sk);
 	icmpv6_err_convert(type, code, &err);
 	if (!sock_owned_by_user(sk) && np->recverr) {
-		sk->err = err;
-		sk->error_report(sk);
+		sk->sk_err = err;
+		sk->sk_error_report(sk);
 	} else {  /* Only an error on timeout */
-		sk->err_soft = err;
+		sk->sk_err_soft = err;
 	}
 
 out_unlock:
@@ -155,7 +158,9 @@
 	struct ipv6_pinfo *np = inet6_sk(sk);
 	struct flowi fl;
 
-	fl.proto = sk->protocol;
+	memset(&fl, 0, sizeof(fl));
+
+	fl.proto = sk->sk_protocol;
 
 	/* Fill in the dest address from the route entry passed with the skb
 	 * and the source address from the transport.
@@ -168,20 +173,20 @@
 	if (ipv6_addr_type(fl.fl6_src) & IPV6_ADDR_LINKLOCAL)
 		fl.oif = transport->saddr.v6.sin6_scope_id;
 	else
-		fl.oif = sk->bound_dev_if;
-	fl.uli_u.ports.sport = (sk)->sport;
+		fl.oif = sk->sk_bound_dev_if;
+	fl.uli_u.ports.sport = sk->sport;
 	fl.uli_u.ports.dport = transport->ipaddr.v6.sin6_port;
 
 	if (np->opt && np->opt->srcrt) {
 		struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
-		fl.nl_u.ip6_u.daddr = rt0->addr;
+		fl.fl6_dst = rt0->addr;
 	}
 
 	SCTP_DEBUG_PRINTK("%s: skb:%p, len:%d, "
 			  "src:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x "
 			  "dst:%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x\n",
-			  __FUNCTION__, skb, skb->len, NIP6(fl.fl6_src),
-			  NIP6(fl.fl6_dst));
+			  __FUNCTION__, skb, skb->len,
+			  NIP6(fl.fl6_src), NIP6(fl.fl6_dst));
 
 	SCTP_INC_STATS(SctpOutSCTPPacks);
 
@@ -196,8 +201,13 @@
 				  union sctp_addr *saddr)
 {
 	struct dst_entry *dst;
-	struct flowi fl = {
-		.nl_u = { .ip6_u = { .daddr = &daddr->v6.sin6_addr, } } };
+	struct flowi fl;
+
+	memset(&fl, 0, sizeof(fl));
+	fl.fl6_dst = &daddr->v6.sin6_addr;
+	if (ipv6_addr_type(&daddr->v6.sin6_addr) & IPV6_ADDR_LINKLOCAL)
+		fl.oif = daddr->v6.sin6_scope_id;
+	
 
 	SCTP_DEBUG_PRINTK("%s: DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
 			  __FUNCTION__, NIP6(fl.fl6_dst));
@@ -252,9 +262,9 @@
 void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst,
 		       union sctp_addr *daddr, union sctp_addr *saddr)
 {
-	sctp_bind_addr_t *bp;
+	struct sctp_bind_addr *bp;
 	rwlock_t *addr_lock;
-	struct sockaddr_storage_list *laddr;
+	struct sctp_sockaddr_entry *laddr;
 	struct list_head *pos;
 	sctp_scope_t scope;
 	union sctp_addr *baddr = NULL;
@@ -283,7 +293,7 @@
 	 */
 	sctp_read_lock(addr_lock);
 	list_for_each(pos, &bp->address_list) {
-		laddr = list_entry(pos, struct sockaddr_storage_list, list);
+		laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
 		if ((laddr->a.sa.sa_family == AF_INET6) &&
 		    (scope <= sctp_scope(&laddr->a))) {
 			bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
@@ -315,7 +325,7 @@
 {
 	struct inet6_dev *in6_dev;
 	struct inet6_ifaddr *ifp;
-	struct sockaddr_storage_list *addr;
+	struct sctp_sockaddr_entry *addr;
 
 	read_lock(&addrconf_lock);
 	if ((in6_dev = __in6_dev_get(dev)) == NULL) {
@@ -326,7 +336,7 @@
 	read_lock(&in6_dev->lock);
 	for (ifp = in6_dev->addr_list; ifp; ifp = ifp->if_next) {
 		/* Add the address to the local list.  */
-		addr = t_new(struct sockaddr_storage_list, GFP_ATOMIC);
+		addr = t_new(struct sctp_sockaddr_entry, GFP_ATOMIC);
 		if (addr) {
 			addr->a.v6.sin6_family = AF_INET6;
 			addr->a.v6.sin6_port = 0;
@@ -369,20 +379,62 @@
 static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
 {
 	addr->v6.sin6_family = AF_INET6;
-	addr->v6.sin6_port = (sk)->num;
+	addr->v6.sin6_port = sk->num;
 	addr->v6.sin6_addr = inet6_sk(sk)->rcv_saddr;
 }
 
-/* Initialize sk->rcv_saddr from sctp_addr. */
+/* Initialize sk->sk_rcv_saddr from sctp_addr. */
 static void sctp_v6_to_sk_saddr(union sctp_addr *addr, struct sock *sk)
 {
-	inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr;
+	if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) {
+		inet6_sk(sk)->rcv_saddr.s6_addr32[0] = 0;
+		inet6_sk(sk)->rcv_saddr.s6_addr32[1] = 0;
+		inet6_sk(sk)->rcv_saddr.s6_addr32[2] = htonl(0x0000ffff);
+		inet6_sk(sk)->rcv_saddr.s6_addr32[3] =
+			addr->v4.sin_addr.s_addr;
+	} else {
+		inet6_sk(sk)->rcv_saddr = addr->v6.sin6_addr;
+	}
 }
 
-/* Initialize sk->daddr from sctp_addr. */
+/* Initialize sk->sk_daddr from sctp_addr. */
 static void sctp_v6_to_sk_daddr(union sctp_addr *addr, struct sock *sk)
 {
-	inet6_sk(sk)->daddr = addr->v6.sin6_addr;
+	if (addr->sa.sa_family == AF_INET && sctp_sk(sk)->v4mapped) {
+		inet6_sk(sk)->daddr.s6_addr32[0] = 0;
+		inet6_sk(sk)->daddr.s6_addr32[1] = 0;
+		inet6_sk(sk)->daddr.s6_addr32[2] = htonl(0x0000ffff);
+		inet6_sk(sk)->daddr.s6_addr32[3] = addr->v4.sin_addr.s_addr;
+	} else {
+		inet6_sk(sk)->daddr = addr->v6.sin6_addr;
+	}
+}
+
+/* Initialize a sctp_addr from an address parameter. */
+static void sctp_v6_from_addr_param(union sctp_addr *addr,
+				    union sctp_addr_param *param,
+				    __u16 port, int iif)
+{
+	addr->v6.sin6_family = AF_INET6;
+	addr->v6.sin6_port = port;
+	addr->v6.sin6_flowinfo = 0; /* BUG */
+	ipv6_addr_copy(&addr->v6.sin6_addr, &param->v6.addr);
+	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)
+{
+	int length = sizeof(sctp_ipv6addr_param_t);
+
+	param->v6.param_hdr.type = SCTP_PARAM_IPV6_ADDRESS;
+	param->v6.param_hdr.length = ntohs(length);
+	ipv6_addr_copy(&param->v6.addr, &addr->v6.sin6_addr);
+
+	return length;
 }
 
 /* Initialize a sctp_addr from a dst_entry. */
@@ -396,13 +448,30 @@
 }
 
 /* Compare addresses exactly.
- * FIXME: v4-mapped-v6.
+ * 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 != addr2->sa.sa_family) {
+		if (addr1->sa.sa_family == AF_INET &&
+		    addr2->sa.sa_family == AF_INET6 &&
+		    IPV6_ADDR_MAPPED == ipv6_addr_type(&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_MAPPED == ipv6_addr_type(&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 (ipv6_addr_cmp(&addr1->v6.sin6_addr, &addr2->v6.sin6_addr))
 		return 0;
 	/* If this is a linklocal address, compare the scope_id. */
@@ -433,7 +502,7 @@
 }
 
 /* Should this be available for binding?   */
-static int sctp_v6_available(const union sctp_addr *addr)
+static int sctp_v6_available(union sctp_addr *addr, struct sctp_opt *sp)
 {
 	int type;
 	struct in6_addr *in6 = (struct in6_addr *)&addr->v6.sin6_addr;
@@ -441,6 +510,14 @@
 	type = ipv6_addr_type(in6);
 	if (IPV6_ADDR_ANY == type)
 		return 1;
+	if (type == IPV6_ADDR_MAPPED) {
+		if (sp && !sp->v4mapped)
+			return 0;
+		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;
 
@@ -454,11 +531,22 @@
  * 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)
+static int sctp_v6_addr_valid(union sctp_addr *addr, struct sctp_opt *sp)
 {
 	int ret = ipv6_addr_type(&addr->v6.sin6_addr);
 
-	/* FIXME:  v4-mapped-v6 address support. */
+	/* 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_opt.
+		 */
+		if (!sp || !sp->v4mapped)
+			return 0;
+		if (sp && ipv6_only_sock(sctp_opt2sk(sp)))
+			return 0;
+		sctp_v6_map_v4(addr);
+		return sctp_get_af_specific(AF_INET)->addr_valid(addr, sp);
+	}
 
 	/* Is this a non-unicast address */
 	if (!(ret & IPV6_ADDR_UNICAST))
@@ -511,18 +599,18 @@
 	sock_init_data(NULL, newsk);
 	sk_set_owner(newsk, THIS_MODULE);
 
-	newsk->type = SOCK_STREAM;
+	newsk->sk_type = SOCK_STREAM;
 
-	newsk->prot = sk->prot;
-	newsk->no_check = sk->no_check;
-	newsk->reuse = sk->reuse;
-
-	newsk->destruct = inet_sock_destruct;
-	newsk->zapped = 0;
-	newsk->family = PF_INET6;
-	newsk->protocol = IPPROTO_SCTP;
-	newsk->backlog_rcv = sk->prot->backlog_rcv;
-	newsk->shutdown = sk->shutdown;
+	newsk->sk_prot = sk->sk_prot;
+	newsk->sk_no_check = sk->sk_no_check;
+	newsk->sk_reuse = sk->sk_reuse;
+
+	newsk->sk_destruct = inet_sock_destruct;
+	newsk->sk_zapped = 0;
+	newsk->sk_family = PF_INET6;
+	newsk->sk_protocol = IPPROTO_SCTP;
+	newsk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
+	newsk->sk_shutdown = sk->sk_shutdown;
 
 	newinet = inet_sk(newsk);
 	newnp = inet6_sk(newsk);
@@ -533,17 +621,31 @@
 	 * and getpeername().
 	 */
 	newsk->sport = sk->sport;
-	newnp->saddr = np->saddr;
+	newsk->saddr = sk->saddr;
 	newnp->rcv_saddr = np->rcv_saddr;
 	newsk->dport = htons(asoc->peer.port);
-	newnp->daddr =  asoc->peer.primary_addr.v6.sin6_addr;
+	sctp_v6_to_sk_daddr(&asoc->peer.primary_addr, newsk);
+
+	/* Init the ipv4 part of the socket since we can have sockets
+	 * using v6 API for ipv4.
+	 */
+	newinet->ttl = sysctl_ip_default_ttl;
+	newinet->mc_loop = 1;
+	newinet->mc_ttl = 1;
+	newinet->mc_index = 0;
+	newinet->mc_list = NULL;
+
+	if (ipv4_config.no_pmtu_disc)
+		newinet->pmtudisc = IP_PMTUDISC_DONT;
+	else
+		newinet->pmtudisc = IP_PMTUDISC_WANT;
 
 #ifdef INET_REFCNT_DEBUG
 	atomic_inc(&inet6_sock_nr);
 	atomic_inc(&inet_sock_nr);
 #endif
 
-	if (0 != newsk->prot->init(newsk)) {
+	if (newsk->sk_prot->init(newsk)) {
 		inet_sock_release(newsk);
 		newsk = NULL;
 	}
@@ -552,6 +654,13 @@
 	return newsk;
 }
 
+/* Map v4 address to mapped v6 address */
+static void sctp_v6_addr_v4map(struct sctp_opt *sp, union sctp_addr *addr)
+{
+	if (sp->v4mapped && AF_INET == addr->sa.sa_family)
+		sctp_v4_map_v6(addr);
+}
+
 /* Where did this skb come from?  */
 static int sctp_v6_skb_iif(const struct sk_buff *skb)
 {
@@ -559,6 +668,19 @@
 	return opt->iif;
 }
 
+/* Was this packet marked by Explicit Congestion Notification? */
+static int sctp_v6_is_ce(const struct sk_buff *skb)
+{
+	return *((__u32 *)(skb->nh.ipv6h)) & htonl(1<<20);
+}
+
+/* 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, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ",
+		   NIP6(&addr->v6.sin6_addr));
+}
+
 /* Initialize a PF_INET6 socket msg_name. */
 static void sctp_inet6_msgname(char *msgname, int *addr_len)
 {
@@ -579,25 +701,28 @@
 
 	if (msgname) {
 		union sctp_addr *addr;
+		struct sctp_association *asoc;
 
+		asoc = event->sndrcvinfo.sinfo_assoc_id;
 		sctp_inet6_msgname(msgname, addrlen);
 		sin6 = (struct sockaddr_in6 *)msgname;
-		sin6->sin6_port = htons(event->event_asoc->peer.port);
-		addr = &event->event_asoc->peer.primary_addr;
+		sin6->sin6_port = htons(asoc->peer.port);
+		addr = &asoc->peer.primary_addr;
 
 		/* Note: If we go to a common v6 format, this code
 		 * will change.
 		 */
 
 		/* Map ipv4 address into v4-mapped-on-v6 address.  */
-		if (AF_INET == addr->sa.sa_family) {
-			/* FIXME: Easy, but there was no way to test this
-			 * yet.
-			 */
+		if (sctp_sk(asoc->base.sk)->v4mapped &&
+		    AF_INET == addr->sa.sa_family) {
+			sctp_v4_map_v6((union sctp_addr *)sin6);
+			sin6->sin6_addr.s6_addr32[3] =
+				addr->v4.sin_addr.s_addr;
 			return;
 		}
 
-		sin6from = &event->event_asoc->peer.primary_addr.v6;
+		sin6from = &asoc->peer.primary_addr.v6;
 		ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr);
 		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL)
 			sin6->sin6_scope_id = sin6from->sin6_scope_id;
@@ -617,16 +742,15 @@
 		sh = (struct sctphdr *)skb->h.raw;
 		sin6->sin6_port = sh->source;
 
-		/* FIXME: Map ipv4 address into v4-mapped-on-v6 address. */
-		if (__constant_htons(ETH_P_IP) == skb->protocol) {
-			/* FIXME:  The latest I-D added options for two
-			 * behaviors.
-			 */
+		/* Map ipv4 address into v4-mapped-on-v6 address. */
+		if (sctp_sk(skb->sk)->v4mapped &&
+		    skb->nh.iph->version == 4) {
+			sctp_v4_map_v6((union sctp_addr *)sin6);
+			sin6->sin6_addr.s6_addr32[3] = skb->nh.iph->saddr;
 			return;
 		}
 
 		/* Otherwise, just copy the v6 address. */
-
 		ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
 		if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
 			struct sctp_ulpevent *ev = sctp_skb2event(skb);
@@ -636,16 +760,15 @@
 }
 
 /* Do we support this AF? */
-static int sctp_inet6_af_supported(sa_family_t family)
+static int sctp_inet6_af_supported(sa_family_t family, struct sctp_opt *sp)
 {
-	/* FIXME:  v4-mapped-v6 addresses.  The I-D is still waffling
-	 * on what to do with sockaddr formats for PF_INET6 sockets.
-	 * For now assume we'll support both.
-	 */
 	switch (family) {
 	case AF_INET6:
-	case AF_INET:
 		return 1;
+	/* v4-mapped-v6 addresses */
+	case AF_INET:
+		if (!__ipv6_only_sock(sctp_opt2sk(sp)) && sp->v4mapped)
+			return 1;
 	default:
 		return 0;
 	}
@@ -689,7 +812,7 @@
 	else {
 		struct sock *sk;
 		int type = ipv6_addr_type(&addr->v6.sin6_addr);
-		sk = container_of(opt, struct sock, tp_pinfo.af_sctp);
+		sk = sctp_opt2sk(opt);
 		if (type & IPV6_ADDR_LINKLOCAL) {
 			/* Note: Behavior similar to af_inet6.c:
 			 *  1) Overrides previous bound_dev_if
@@ -697,13 +820,13 @@
 			 */
 
 			if (addr->v6.sin6_scope_id)
-				sk->bound_dev_if = addr->v6.sin6_scope_id;
-			if (!sk->bound_dev_if)
+				sk->sk_bound_dev_if = addr->v6.sin6_scope_id;
+			if (!sk->sk_bound_dev_if)
 				return 0;
 		}
 		af = opt->pf->af;
 	}
-	return af->available(addr);
+	return af->available(addr, opt);
 }
 
 /* Verify that the provided sockaddr looks bindable.   Common verification,
@@ -719,7 +842,7 @@
 	else {
 		struct sock *sk;
 		int type = ipv6_addr_type(&addr->v6.sin6_addr);
-		sk = container_of(opt, struct sock, tp_pinfo.af_sctp);
+		sk = sctp_opt2sk(opt);
 		if (type & IPV6_ADDR_LINKLOCAL) {
 			/* Note: Behavior similar to af_inet6.c:
 			 *  1) Overrides previous bound_dev_if
@@ -727,8 +850,8 @@
 			 */
 
 			if (addr->v6.sin6_scope_id)
-				sk->bound_dev_if = addr->v6.sin6_scope_id;
-			if (!sk->bound_dev_if)
+				sk->sk_bound_dev_if = addr->v6.sin6_scope_id;
+			if (!sk->sk_bound_dev_if)
 				return 0;
 		}
 		af = opt->pf->af;
@@ -810,6 +933,8 @@
 	.from_sk         = sctp_v6_from_sk,
 	.to_sk_saddr     = sctp_v6_to_sk_saddr,
 	.to_sk_daddr     = sctp_v6_to_sk_daddr,
+	.from_addr_param = sctp_v6_from_addr_param,
+	.to_addr_param   = sctp_v6_to_addr_param,
 	.dst_saddr       = sctp_v6_dst_saddr,
 	.cmp_addr        = sctp_v6_cmp_addr,
 	.scope           = sctp_v6_scope,
@@ -818,6 +943,8 @@
 	.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,
 	.net_header_len  = sizeof(struct ipv6hdr),
 	.sockaddr_len    = sizeof(struct sockaddr_in6),
 	.sa_family       = AF_INET6,
@@ -832,6 +959,7 @@
 	.send_verify   = sctp_inet6_send_verify,
 	.supported_addrs = sctp_inet6_supported_addrs,
 	.create_accept_sk = sctp_v6_create_accept_sk,
+	.addr_v4map    = sctp_v6_addr_v4map,
 	.af            = &sctp_ipv6_specific,
 };
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)