#include <asm/uaccess.h>
-extern int sctp_inetaddr_event(struct notifier_block *, unsigned long, void *);
+/* Event handler for inet6 address addition/deletion events. */
+static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
+ void *ptr)
+{
+ struct inet6_ifaddr *ifa = (struct inet6_ifaddr *)ptr;
+ struct sctp_sockaddr_entry *addr;
+ struct list_head *pos, *temp;
+
+ switch (ev) {
+ case NETDEV_UP:
+ addr = kmalloc(sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
+ if (addr) {
+ addr->a.v6.sin6_family = AF_INET6;
+ addr->a.v6.sin6_port = 0;
+ memcpy(&addr->a.v6.sin6_addr, &ifa->addr,
+ sizeof(struct in6_addr));
+ addr->a.v6.sin6_scope_id = ifa->idev->dev->ifindex;
+ list_add_tail(&addr->list, &sctp_local_addr_list);
+ }
+ break;
+ case NETDEV_DOWN:
+ list_for_each_safe(pos, temp, &sctp_local_addr_list) {
+ addr = list_entry(pos, struct sctp_sockaddr_entry, list);
+ if (ipv6_addr_equal(&addr->a.v6.sin6_addr, &ifa->addr)) {
+ list_del(pos);
+ kfree(addr);
+ break;
+ }
+ }
+
+ break;
+ }
+
+ return NOTIFY_DONE;
+}
+
static struct notifier_block sctp_inet6addr_notifier = {
- .notifier_call = sctp_inetaddr_event,
+ .notifier_call = sctp_inet6addr_event,
};
/* ICMP error handler. */
SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
- int type, int code, int offset, __u32 info)
+ int type, int code, int offset, __be32 info)
{
struct inet6_dev *idev;
struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
fl.oif = transport->saddr.v6.sin6_scope_id;
else
fl.oif = sk->sk_bound_dev_if;
- fl.fl_ip_sport = inet_sk(sk)->sport;
- fl.fl_ip_dport = transport->ipaddr.v6.sin6_port;
if (np->opt && np->opt->srcrt) {
struct rt0_hdr *rt0 = (struct rt0_hdr *) np->opt->srcrt;
}
dst = ip6_route_output(NULL, &fl);
- if (dst) {
+ 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));
- } else {
- SCTP_DEBUG_PRINTK("NO ROUTE\n");
+ return dst;
}
-
- return dst;
+ SCTP_DEBUG_PRINTK("NO ROUTE\n");
+ dst_release(dst);
+ return NULL;
}
/* Returns the number of consecutive initial bits that match in the 2 ipv6
int i, j;
for (i = 0; i < 4 ; i++) {
- __u32 a1xora2;
+ __be32 a1xora2;
a1xora2 = a1->s6_addr32[i] ^ a2->s6_addr32[i];
sctp_read_lock(addr_lock);
list_for_each(pos, &bp->address_list) {
laddr = list_entry(pos, struct sctp_sockaddr_entry, list);
- if ((laddr->a.sa.sa_family == AF_INET6) &&
+ if ((laddr->use_as_src) &&
+ (laddr->a.sa.sa_family == AF_INET6) &&
(scope <= sctp_scope(&laddr->a))) {
bmatchlen = sctp_v6_addr_match_len(daddr, &laddr->a);
if (!baddr || (matchlen < bmatchlen)) {
struct inet6_ifaddr *ifp;
struct sctp_sockaddr_entry *addr;
- read_lock(&addrconf_lock);
+ rcu_read_lock();
if ((in6_dev = __in6_dev_get(dev)) == NULL) {
- read_unlock(&addrconf_lock);
+ rcu_read_unlock();
return;
}
}
read_unlock(&in6_dev->lock);
- read_unlock(&addrconf_lock);
+ rcu_read_unlock();
}
/* Initialize a sockaddr_storage from in incoming skb. */
int is_saddr)
{
void *from;
- __u16 *port;
+ __be16 *port;
struct sctphdr *sh;
port = &addr->v6.sin6_port;
sh = (struct sctphdr *) skb->h.raw;
if (is_saddr) {
- *port = ntohs(sh->source);
+ *port = sh->source;
from = &skb->nh.ipv6h->saddr;
} else {
- *port = ntohs(sh->dest);
+ *port = sh->dest;
from = &skb->nh.ipv6h->daddr;
}
ipv6_addr_copy(&addr->v6.sin6_addr, from);
static void sctp_v6_from_sk(union sctp_addr *addr, struct sock *sk)
{
addr->v6.sin6_family = AF_INET6;
- addr->v6.sin6_port = inet_sk(sk)->num;
+ addr->v6.sin6_port = 0;
addr->v6.sin6_addr = inet6_sk(sk)->rcv_saddr;
}
/* 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)
+ __be16 port, int iif)
{
addr->v6.sin6_family = AF_INET6;
addr->v6.sin6_port = port;
int length = sizeof(sctp_ipv6addr_param_t);
param->v6.param_hdr.type = SCTP_PARAM_IPV6_ADDRESS;
- param->v6.param_hdr.length = ntohs(length);
+ param->v6.param_hdr.length = htons(length);
ipv6_addr_copy(¶m->v6.addr, &addr->v6.sin6_addr);
return length;
/* Initialize a sctp_addr from a dst_entry. */
static void sctp_v6_dst_saddr(union sctp_addr *addr, struct dst_entry *dst,
- unsigned short port)
+ __be16 port)
{
struct rt6_info *rt = (struct rt6_info *)dst;
addr->sa.sa_family = AF_INET6;
}
/* Initialize addr struct to INADDR_ANY. */
-static void sctp_v6_inaddr_any(union sctp_addr *addr, unsigned short port)
+static void sctp_v6_inaddr_any(union sctp_addr *addr, __be16 port)
{
memset(addr, 0x00, sizeof(union sctp_addr));
addr->v6.sin6_family = AF_INET6;
* Returns number of addresses supported.
*/
static int sctp_inet6_supported_addrs(const struct sctp_sock *opt,
- __u16 *types)
+ __be16 *types)
{
types[0] = SCTP_PARAM_IPV4_ADDRESS;
types[1] = SCTP_PARAM_IPV6_ADDRESS;
}
static const struct proto_ops inet6_seqpacket_ops = {
- .family = PF_INET6,
- .owner = THIS_MODULE,
- .release = inet6_release,
- .bind = inet6_bind,
- .connect = inet_dgram_connect,
- .socketpair = sock_no_socketpair,
- .accept = inet_accept,
- .getname = inet6_getname,
- .poll = sctp_poll,
- .ioctl = inet6_ioctl,
- .listen = sctp_inet_listen,
- .shutdown = inet_shutdown,
- .setsockopt = sock_common_setsockopt,
- .getsockopt = sock_common_getsockopt,
- .sendmsg = inet_sendmsg,
- .recvmsg = sock_common_recvmsg,
- .mmap = sock_no_mmap,
+ .family = PF_INET6,
+ .owner = THIS_MODULE,
+ .release = inet6_release,
+ .bind = inet6_bind,
+ .connect = inet_dgram_connect,
+ .socketpair = sock_no_socketpair,
+ .accept = inet_accept,
+ .getname = inet6_getname,
+ .poll = sctp_poll,
+ .ioctl = inet6_ioctl,
+ .listen = sctp_inet_listen,
+ .shutdown = inet_shutdown,
+ .setsockopt = sock_common_setsockopt,
+ .getsockopt = sock_common_getsockopt,
+ .sendmsg = inet_sendmsg,
+ .recvmsg = sock_common_recvmsg,
+ .mmap = sock_no_mmap,
+#ifdef CONFIG_COMPAT
+ .compat_setsockopt = compat_sock_common_setsockopt,
+ .compat_getsockopt = compat_sock_common_getsockopt,
+#endif
};
static struct inet_protosw sctpv6_seqpacket_protosw = {
};
static struct sctp_af sctp_ipv6_specific = {
- .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,
- .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,
- .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,
- .net_header_len = sizeof(struct ipv6hdr),
- .sockaddr_len = sizeof(struct sockaddr_in6),
- .sa_family = AF_INET6,
+ .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,
+ .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,
+ .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,
+ .net_header_len = sizeof(struct ipv6hdr),
+ .sockaddr_len = sizeof(struct sockaddr_in6),
+#ifdef CONFIG_COMPAT
+ .compat_setsockopt = compat_ipv6_setsockopt,
+ .compat_getsockopt = compat_ipv6_getsockopt,
+#endif
};
static struct sctp_pf sctp_pf_inet6_specific = {