diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
---|---|---|
committer | Ralf Baechle <ralf@linux-mips.org> | 1998-08-25 09:12:35 +0000 |
commit | c7fc24dc4420057f103afe8fc64524ebc25c5d37 (patch) | |
tree | 3682407a599b8f9f03fc096298134cafba1c9b2f /net/ipv6 | |
parent | 1d793fade8b063fde3cf275bf1a5c2d381292cd9 (diff) |
o Merge with Linux 2.1.116.
o New Newport console code.
o New G364 console code.
Diffstat (limited to 'net/ipv6')
-rw-r--r-- | net/ipv6/addrconf.c | 25 | ||||
-rw-r--r-- | net/ipv6/af_inet6.c | 97 | ||||
-rw-r--r-- | net/ipv6/icmp.c | 43 | ||||
-rw-r--r-- | net/ipv6/ip6_fib.c | 9 | ||||
-rw-r--r-- | net/ipv6/ip6_input.c | 11 | ||||
-rw-r--r-- | net/ipv6/ip6_output.c | 102 | ||||
-rw-r--r-- | net/ipv6/ipv6_sockglue.c | 83 | ||||
-rw-r--r-- | net/ipv6/mcast.c | 39 | ||||
-rw-r--r-- | net/ipv6/ndisc.c | 37 | ||||
-rw-r--r-- | net/ipv6/protocol.c | 4 | ||||
-rw-r--r-- | net/ipv6/raw.c | 4 | ||||
-rw-r--r-- | net/ipv6/route.c | 90 | ||||
-rw-r--r-- | net/ipv6/tcp_ipv6.c | 25 | ||||
-rw-r--r-- | net/ipv6/udp.c | 37 |
14 files changed, 453 insertions, 153 deletions
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c index 5571c04c7..329807093 100644 --- a/net/ipv6/addrconf.c +++ b/net/ipv6/addrconf.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: addrconf.c,v 1.38 1998/03/20 09:12:14 davem Exp $ + * $Id: addrconf.c,v 1.43 1998/07/15 05:05:32 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -53,6 +53,7 @@ #include <linux/rtnetlink.h> #include <asm/uaccess.h> +#include <asm/delay.h> /* Set to 3 to get tracing... */ #define ACONF_DEBUG 2 @@ -1033,7 +1034,7 @@ static void addrconf_dev_config(struct device *dev) struct inet6_dev * idev; if (dev->type != ARPHRD_ETHER) { - /* Alas, we support only ethernet autoconfiguration. */ + /* Alas, we support only Ethernet autoconfiguration. */ return; } @@ -1157,13 +1158,6 @@ static int addrconf_ifdown(struct device *dev, int how) start_bh_atomic(); - /* Discard multicast list */ - - if (how == 1) - ipv6_mc_destroy_dev(idev); - else - ipv6_mc_down(idev); - /* Discard address list */ idev->addr_list = NULL; @@ -1187,6 +1181,13 @@ static int addrconf_ifdown(struct device *dev, int how) } } + /* Discard multicast list */ + + if (how == 1) + ipv6_mc_destroy_dev(idev); + else + ipv6_mc_down(idev); + /* Delete device from device hash table (if unregistered) */ if (how == 1) { @@ -1608,7 +1609,7 @@ static struct rtnetlink_link inet6_rtnetlink_table[RTM_MAX-RTM_BASE+1] = { inet6_rtm_newroute, NULL, }, { inet6_rtm_delroute, NULL, }, - { NULL, inet6_dump_fib, }, + { inet6_rtm_getroute, inet6_dump_fib, }, { NULL, NULL, }, }; #endif @@ -1808,7 +1809,7 @@ __initfunc(void addrconf_init(void)) addr_chk_timer.expires = jiffies + ADDR_CHECK_FREQUENCY; add_timer(&addr_chk_timer); #ifdef CONFIG_RTNETLINK - rtnetlink_links[AF_INET6] = inet6_rtnetlink_table; + rtnetlink_links[PF_INET6] = inet6_rtnetlink_table; #endif #ifdef CONFIG_SYSCTL addrconf_sysctl.sysctl_header = @@ -1825,7 +1826,7 @@ void addrconf_cleanup(void) int i; #ifdef CONFIG_RTNETLINK - rtnetlink_links[AF_INET6] = NULL; + rtnetlink_links[PF_INET6] = NULL; #endif #ifdef CONFIG_SYSCTL addrconf_sysctl_unregister(&ipv6_devconf_dflt); diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c index c1b2e9d14..051f9a28e 100644 --- a/net/ipv6/af_inet6.c +++ b/net/ipv6/af_inet6.c @@ -1,5 +1,5 @@ /* - * AF_INET6 socket family + * PF_INET6 socket protocol family * Linux INET6 implementation * * Authors: @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/af_inet.c * - * $Id: af_inet6.c,v 1.30 1998/03/25 00:23:05 davem Exp $ + * $Id: af_inet6.c,v 1.36 1998/06/10 07:29:25 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -66,12 +66,17 @@ extern int udp6_get_info(char *, char **, off_t, int, int); extern int afinet6_get_info(char *, char **, off_t, int, int); #endif +#ifdef CONFIG_SYSCTL +extern void ipv6_sysctl_register(void); +extern void ipv6_sysctl_unregister(void); +#endif + static int inet6_create(struct socket *sock, int protocol) { struct sock *sk; struct proto *prot; - sk = sk_alloc(AF_INET6, GFP_KERNEL, 1); + sk = sk_alloc(PF_INET6, GFP_KERNEL, 1); if (sk == NULL) goto do_oom; @@ -105,7 +110,7 @@ static int inet6_create(struct socket *sock, int protocol) sk->destruct = NULL; sk->zapped = 0; - sk->family = AF_INET6; + sk->family = PF_INET6; sk->protocol = protocol; sk->prot = prot; @@ -336,7 +341,7 @@ static int inet6_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) } struct proto_ops inet6_stream_ops = { - AF_INET6, + PF_INET6, sock_no_dup, inet6_release, @@ -357,7 +362,7 @@ struct proto_ops inet6_stream_ops = { }; struct proto_ops inet6_dgram_ops = { - AF_INET6, + PF_INET6, sock_no_dup, inet6_release, @@ -378,7 +383,7 @@ struct proto_ops inet6_dgram_ops = { }; struct net_proto_family inet6_family_ops = { - AF_INET6, + PF_INET6, inet6_create }; @@ -412,10 +417,16 @@ static struct proc_dir_entry proc_net_sockstat6 = { #ifdef MODULE int ipv6_unload(void) { - return 0; + /* We keep internally 3 raw sockets */ + return __this_module.usecount - 3; } #endif +#if defined(MODULE) && defined(CONFIG_SYSCTL) +extern void ipv6_sysctl_register(void); +extern void ipv6_sysctl_unregister(void); +#endif + #ifdef MODULE int init_module(void) #else @@ -423,6 +434,7 @@ __initfunc(void inet6_proto_init(struct net_proto *pro)) #endif { struct sk_buff *dummy_skb; + int err; #ifdef MODULE if (!mod_member_present(&__this_module, can_unload)) @@ -443,8 +455,6 @@ __initfunc(void inet6_proto_init(struct net_proto *pro)) #endif } - (void) sock_register(&inet6_family_ops); - /* * ipngwg API draft makes clear that the correct semantics * for TCP and UDP is to consider one TCP and UDP instance @@ -452,19 +462,26 @@ __initfunc(void inet6_proto_init(struct net_proto *pro)) * able to communicate via both network protocols. */ - ipv6_init(); - - icmpv6_init(&inet6_family_ops); - - addrconf_init(); - - sit_init(); - - /* init v6 transport protocols */ - +#if defined(MODULE) && defined(CONFIG_SYSCTL) + ipv6_sysctl_register(); +#endif + err = icmpv6_init(&inet6_family_ops); + if (err) + goto icmp_fail; + err = ndisc_init(&inet6_family_ops); + if (err) + goto ndisc_fail; + err = igmp6_init(&inet6_family_ops); + if (err) + goto igmp_fail; + ipv6_netdev_notif_init(); + ipv6_packet_init(); + ip6_route_init(); + addrconf_init(); + sit_init(); + + /* Init v6 transport protocols. */ udpv6_init(); - /* add /proc entries here */ - tcpv6_init(); /* Create /proc/foo6 entries. */ @@ -475,22 +492,52 @@ __initfunc(void inet6_proto_init(struct net_proto *pro)) proc_net_register(&proc_net_sockstat6); #endif + /* Now the userspace is allowed to create INET6 sockets. */ + (void) sock_register(&inet6_family_ops); + #ifdef MODULE return 0; +#else + return; +#endif + +igmp_fail: + ndisc_cleanup(); +ndisc_fail: + icmpv6_cleanup(); +icmp_fail: +#if defined(MODULE) && defined(CONFIG_SYSCTL) + ipv6_sysctl_unregister(); +#endif +#ifdef MODULE + return err; +#else + return; #endif } #ifdef MODULE void cleanup_module(void) { - sit_cleanup(); - ipv6_cleanup(); - sock_unregister(AF_INET6); + /* First of all disallow new sockets creation. */ + sock_unregister(PF_INET6); #ifdef CONFIG_PROC_FS proc_net_unregister(proc_net_raw6.low_ino); proc_net_unregister(proc_net_tcp6.low_ino); proc_net_unregister(proc_net_udp6.low_ino); proc_net_unregister(proc_net_sockstat6.low_ino); #endif + /* Cleanup code parts. */ + sit_cleanup(); + ipv6_netdev_notif_cleanup(); + addrconf_cleanup(); + ip6_route_cleanup(); + ipv6_packet_cleanup(); + igmp6_cleanup(); + ndisc_cleanup(); + icmpv6_cleanup(); +#ifdef CONFIG_SYSCTL + ipv6_sysctl_unregister(); +#endif } #endif /* MODULE */ diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c index 104895936..c3b6f7b6b 100644 --- a/net/ipv6/icmp.c +++ b/net/ipv6/icmp.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: icmp.c,v 1.17 1998/05/01 10:31:41 davem Exp $ + * $Id: icmp.c,v 1.18 1998/05/07 15:42:59 davem Exp $ * * Based on net/ipv4/icmp.c * @@ -62,8 +62,7 @@ * ICMP socket for flow control. */ -struct inode icmpv6_inode; -struct socket *icmpv6_socket=&icmpv6_inode.u.socket_i; +struct socket *icmpv6_socket; int icmpv6_rcv(struct sk_buff *skb, struct device *dev, struct in6_addr *saddr, struct in6_addr *daddr, @@ -557,19 +556,23 @@ __initfunc(int icmpv6_init(struct net_proto_family *ops)) struct sock *sk; int err; - icmpv6_inode.i_mode = S_IFSOCK; - icmpv6_inode.i_sock = 1; - icmpv6_inode.i_uid = 0; - icmpv6_inode.i_gid = 0; - - icmpv6_socket->inode = &icmpv6_inode; - icmpv6_socket->state = SS_UNCONNECTED; - icmpv6_socket->type=SOCK_RAW; - - if((err=ops->create(icmpv6_socket, IPPROTO_ICMPV6))<0) { - printk(KERN_DEBUG + icmpv6_socket = sock_alloc(); + if (icmpv6_socket == NULL) { + printk(KERN_ERR "Failed to create the ICMP6 control socket.\n"); - return 1; + return -1; + } + icmpv6_socket->inode->i_uid = 0; + icmpv6_socket->inode->i_gid = 0; + icmpv6_socket->type = SOCK_RAW; + + if ((err = ops->create(icmpv6_socket, IPPROTO_ICMPV6)) < 0) { + printk(KERN_ERR + "Failed to initialize the ICMP6 control socket (err %d).\n", + err); + sock_release(icmpv6_socket); + icmpv6_socket = NULL; /* for safety */ + return err; } sk = icmpv6_socket->sk; @@ -578,18 +581,14 @@ __initfunc(int icmpv6_init(struct net_proto_family *ops)) inet6_add_protocol(&icmpv6_protocol); - ndisc_init(ops); - igmp6_init(ops); - return 0; + return 0; } void icmpv6_cleanup(void) { + sock_release(icmpv6_socket); + icmpv6_socket = NULL; /* For safety. */ inet6_del_protocol(&icmpv6_protocol); -#if 0 - ndisc_cleanup(); -#endif - igmp6_cleanup(); } static struct icmp6_err { diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c index 693caaf3b..e7e12e3ae 100644 --- a/net/ipv6/ip6_fib.c +++ b/net/ipv6/ip6_fib.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_fib.c,v 1.13 1998/04/28 06:22:03 davem Exp $ + * $Id: ip6_fib.c,v 1.14 1998/05/07 15:43:03 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1077,3 +1077,10 @@ void fib6_run_gc(unsigned long dummy) ip6_fib_timer.expires = 0; } } + +#ifdef MODULE +void fib6_gc_cleanup(void) +{ + del_timer(&ip6_fib_timer); +} +#endif diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c index 5f024dddb..6ab4d2c08 100644 --- a/net/ipv6/ip6_input.c +++ b/net/ipv6/ip6_input.c @@ -6,7 +6,7 @@ * Pedro Roque <roque@di.fc.ul.pt> * Ian P. Morris <I.P.Morris@soton.ac.uk> * - * $Id: ip6_input.c,v 1.9 1998/04/30 16:24:24 freitag Exp $ + * $Id: ip6_input.c,v 1.10 1998/07/15 05:05:34 davem Exp $ * * Based in linux/net/ipv4/ip_input.c * @@ -65,11 +65,6 @@ struct hdrtype_proc { /* New header structures */ -struct ipv6_tlvtype { - u8 type; - u8 len; -}; - struct tlvtype_proc { u8 type; int (*func) (struct sk_buff *, struct device *dev, __u8 *ptr, @@ -82,7 +77,7 @@ struct tlvtype_proc { {255, NULL} }; -static int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr) +int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr) { struct in6_addr *daddr; int pos; @@ -91,7 +86,7 @@ static int ip6_dstopt_unknown(struct sk_buff *skb, struct ipv6_tlvtype *hdr) * unkown destination option type */ - pos = (__u8 *) skb->h.raw - (__u8 *) skb->nh.raw; + pos = (__u8 *) hdr - (__u8 *) skb->nh.raw; /* I think this is correct please check - IPM */ diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c index eb3984f55..aa13c2074 100644 --- a/net/ipv6/ip6_output.c +++ b/net/ipv6/ip6_output.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: ip6_output.c,v 1.12 1998/04/11 22:11:06 davem Exp $ + * $Id: ip6_output.c,v 1.13 1998/07/15 05:05:38 davem Exp $ * * Based on linux/net/ipv4/ip_output.c * @@ -32,6 +32,7 @@ #include <net/protocol.h> #include <net/ip6_route.h> #include <net/addrconf.h> +#include <net/rawv6.h> static u32 ipv6_fragmentation_id = 1; @@ -519,25 +520,104 @@ int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data, return err; } +int ip6_call_ra_chain(struct sk_buff *skb, int sel) +{ + struct ip6_ra_chain *ra; + struct sock *last = NULL; + + for (ra = ip6_ra_chain; ra; ra = ra->next) { + struct sock *sk = ra->sk; + if (sk && ra->sel == sel) { + if (last) { + struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC); + if (skb2) { + skb2->sk = last; + rawv6_rcv(skb2, skb2->dev, &skb2->nh.ipv6h->saddr, + &skb2->nh.ipv6h->daddr, NULL, skb2->len); + } + } + last = sk; + } + } + + if (last) { + skb->sk = last; + rawv6_rcv(skb, skb->dev, &skb->nh.ipv6h->saddr, + &skb->nh.ipv6h->daddr, NULL, skb->len); + return 1; + } + return 0; +} + int ip6_forward(struct sk_buff *skb) { struct dst_entry *dst = skb->dst; struct ipv6hdr *hdr = skb->nh.ipv6h; int size; - if (ipv6_devconf.forwarding == 0) { - kfree_skb(skb); - return -EINVAL; - } + if (ipv6_devconf.forwarding == 0) + goto drop; /* * check hop-by-hop options present */ -#if 0 - if (hdr->nexthdr == NEXTHDR_HOP) - { + /* + * Note, that NEXTHDR_HOP header must be checked + * always at the most beginning of ipv6_rcv. + * The result should be saved somewhere, but + * we do not it for now. Alas. Let's do it here. --ANK + * + * Second note: we DO NOT make any processing on + * RA packets, pushing them to user level AS IS + * without ane WARRANTY that application will able + * to interpret them. The reson is that we + * cannot make anything clever here. + * + * We are not end-node, so that if packet contains + * AH/ESP, we cannot make anything. + * Defragmentation also would be mistake, RA packets + * cannot be fragmented, because there is no warranty + * that different fragments will go along one path. --ANK + */ + if (hdr->nexthdr == NEXTHDR_HOP) { + int ra_value = -1; + u8 *ptr = (u8*)(skb->nh.ipv6h+1); + int len = (ptr[1]+1)<<3; + + if (len + sizeof(struct ipv6hdr) > skb->len) + goto drop; + + ptr += 2; + len -= 2; + while (len > 0) { + u8 *opt; + int optlen; + + if (ptr[0] == 0) { + len--; + ptr++; + continue; + } + opt = ptr; + optlen = ptr[1]+1; + + len -= optlen; + ptr += optlen; + if (len < 0) + goto drop; + + if (opt[0] == 20) { + /* Router Alert as of draft-ietf-ipngwg-ipv6router-alert-04 */ + if (optlen < 4) + goto drop; + ra_value = opt[2] + (opt[3]<<8); + } else if (!ip6_dstopt_unknown(skb, (struct ipv6_tlvtype*)opt)) + goto drop; + } + if (ra_value>=0 && ip6_call_ra_chain(skb, ra_value)) + return 0; } -#endif + /* * check and decrement ttl */ @@ -589,4 +669,8 @@ int ip6_forward(struct sk_buff *skb) dst->output(skb); return 0; + +drop: + kfree_skb(skb); + return -EINVAL; } diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c index ebd3365cd..b31c07c00 100644 --- a/net/ipv6/ipv6_sockglue.c +++ b/net/ipv6/ipv6_sockglue.c @@ -7,7 +7,7 @@ * * Based on linux/net/ipv4/ip_sockglue.c * - * $Id: ipv6_sockglue.c,v 1.19 1998/04/30 16:24:26 freitag Exp $ + * $Id: ipv6_sockglue.c,v 1.22 1998/07/15 05:05:39 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -67,6 +67,45 @@ static struct notifier_block ipv6_dev_notf = { 0 }; +struct ip6_ra_chain *ip6_ra_chain; + +int ip6_ra_control(struct sock *sk, int sel, void (*destructor)(struct sock *)) +{ + struct ip6_ra_chain *ra, *new_ra, **rap; + + /* RA packet may be delivered ONLY to IPPROTO_RAW socket */ + if (sk->type != SOCK_RAW || sk->num != IPPROTO_RAW) + return -EINVAL; + + new_ra = (sel>=0) ? kmalloc(sizeof(*new_ra), GFP_KERNEL) : NULL; + + for (rap = &ip6_ra_chain; (ra=*rap) != NULL; rap = &ra->next) { + if (ra->sk == sk) { + if (sel>=0) { + if (new_ra) + kfree(new_ra); + return -EADDRINUSE; + } + *rap = ra->next; + if (ra->destructor) + ra->destructor(sk); + kfree(ra); + return 0; + } + } + if (new_ra == NULL) + return -ENOBUFS; + new_ra->sk = sk; + new_ra->sel = sel; + new_ra->destructor = destructor; + start_bh_atomic(); + new_ra->next = ra; + *rap = new_ra; + end_bh_atomic(); + return 0; +} + + int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) { @@ -74,6 +113,9 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, int val, err; int retv = -ENOPROTOOPT; + if(level==SOL_IP && sk->type != SOCK_RAW) + return udp_prot.setsockopt(sk, level, optname, optval, optlen); + if(level!=SOL_IPV6) goto out; @@ -110,7 +152,7 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, sk->prot = &tcp_prot; tp->af_specific = &ipv4_specific; sk->socket->ops = &inet_stream_ops; - sk->family = AF_INET; + sk->family = PF_INET; } else { sk->prot = &udp_prot; sk->socket->ops = &inet_dgram_ops; @@ -197,7 +239,11 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval, retv = ipv6_sock_mc_join(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); else retv = ipv6_sock_mc_drop(sk, mreq.ipv6mr_ifindex, &mreq.ipv6mr_multiaddr); + break; } + case IPV6_ROUTER_ALERT: + retv = ip6_ra_control(sk, val, NULL); + break; }; out: @@ -207,7 +253,11 @@ out: int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) { - return 0; + if(level==SOL_IP && sk->type != SOCK_RAW) + return udp_prot.getsockopt(sk, level, optname, optval, optlen); + if(level!=SOL_IPV6) + return -ENOPROTOOPT; + return -EINVAL; } #if defined(MODULE) && defined(CONFIG_SYSCTL) @@ -220,31 +270,24 @@ extern void ipv6_sysctl_register(void); extern void ipv6_sysctl_unregister(void); #endif -__initfunc(void ipv6_init(void)) +__initfunc(void ipv6_packet_init(void)) { dev_add_pack(&ipv6_packet_type); +} -#if defined(MODULE) && defined(CONFIG_SYSCTL) - ipv6_sysctl_register(); -#endif - +__initfunc(void ipv6_netdev_notif_init(void)) +{ register_netdevice_notifier(&ipv6_dev_notf); - - ip6_route_init(); } #ifdef MODULE -void ipv6_cleanup(void) +void ipv6_packet_cleanup(void) { - unregister_netdevice_notifier(&ipv6_dev_notf); dev_remove_pack(&ipv6_packet_type); -#ifdef CONFIG_SYSCTL - ipv6_sysctl_unregister(); -#endif - ip6_route_cleanup(); - icmpv6_cleanup(); - addrconf_cleanup(); } -#endif - +void ipv6_netdev_notif_cleanup(void) +{ + unregister_netdevice_notifier(&ipv6_dev_notf); +} +#endif diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c index 0e10dcf0b..c50f37fcf 100644 --- a/net/ipv6/mcast.c +++ b/net/ipv6/mcast.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: mcast.c,v 1.15 1998/04/30 16:24:28 freitag Exp $ + * $Id: mcast.c,v 1.16 1998/05/07 15:43:10 davem Exp $ * * Based on linux/ipv4/igmp.c and linux/ipv4/ip_sockglue.c * @@ -52,8 +52,7 @@ #define MDBG(x) #endif -static struct inode igmp6_inode; -static struct socket *igmp6_socket=&igmp6_inode.u.socket_i; +static struct socket *igmp6_socket; static void igmp6_join_group(struct ifmcaddr6 *ma); static void igmp6_leave_group(struct ifmcaddr6 *ma); @@ -598,7 +597,7 @@ done: } #endif -__initfunc(void igmp6_init(struct net_proto_family *ops)) +__initfunc(int igmp6_init(struct net_proto_family *ops)) { #ifdef CONFIG_PROC_FS struct proc_dir_entry *ent; @@ -606,18 +605,24 @@ __initfunc(void igmp6_init(struct net_proto_family *ops)) struct sock *sk; int err; - igmp6_inode.i_mode = S_IFSOCK; - igmp6_inode.i_sock = 1; - igmp6_inode.i_uid = 0; - igmp6_inode.i_gid = 0; - - igmp6_socket->inode = &igmp6_inode; - igmp6_socket->state = SS_UNCONNECTED; + igmp6_socket = sock_alloc(); + if (igmp6_socket == NULL) { + printk(KERN_ERR + "Failed to create the IGMP6 control socket.\n"); + return -1; + } + igmp6_socket->inode->i_uid = 0; + igmp6_socket->inode->i_gid = 0; igmp6_socket->type = SOCK_RAW; - if((err=ops->create(igmp6_socket, IPPROTO_ICMPV6))<0) + if((err = ops->create(igmp6_socket, IPPROTO_ICMPV6)) < 0) { printk(KERN_DEBUG - "Failed to create the IGMP6 control socket.\n"); + "Failed to initialize the IGMP6 control socket (err %d).\n", + err); + sock_release(igmp6_socket); + igmp6_socket = NULL; /* For safety. */ + return err; + } sk = igmp6_socket->sk; sk->allocation = GFP_ATOMIC; @@ -628,11 +633,17 @@ __initfunc(void igmp6_init(struct net_proto_family *ops)) ent = create_proc_entry("net/igmp6", 0, 0); ent->read_proc = igmp6_read_proc; #endif + + return 0; } +#ifdef MODULE void igmp6_cleanup(void) { + sock_release(igmp6_socket); + igmp6_socket = NULL; /* for safety */ #ifdef CONFIG_PROC_FS - remove_proc_entry("net/igmp6", 0); + remove_proc_entry("net/igmp6", 0); #endif } +#endif diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c index e69d90332..26e42a1ed 100644 --- a/net/ipv6/ndisc.c +++ b/net/ipv6/ndisc.c @@ -74,8 +74,7 @@ #include <net/checksum.h> #include <linux/proc_fs.h> -static struct inode ndisc_inode; -static struct socket *ndisc_socket=&ndisc_inode.u.socket_i; +static struct socket *ndisc_socket; static int ndisc_constructor(struct neighbour *neigh); static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb); @@ -1134,23 +1133,29 @@ struct proc_dir_entry ndisc_proc_entry = -__initfunc(void ndisc_init(struct net_proto_family *ops)) +__initfunc(int ndisc_init(struct net_proto_family *ops)) { struct sock *sk; int err; - ndisc_inode.i_mode = S_IFSOCK; - ndisc_inode.i_sock = 1; - ndisc_inode.i_uid = 0; - ndisc_inode.i_gid = 0; - - ndisc_socket->inode = &ndisc_inode; - ndisc_socket->state = SS_UNCONNECTED; - ndisc_socket->type = SOCK_RAW; + ndisc_socket = sock_alloc(); + if (ndisc_socket == NULL) { + printk(KERN_ERR + "Failed to create the NDISC control socket.\n"); + return -1; + } + ndisc_socket->inode->i_uid = 0; + ndisc_socket->inode->i_gid = 0; + ndisc_socket->type = SOCK_RAW; - if((err=ops->create(ndisc_socket, IPPROTO_ICMPV6))<0) + if((err = ops->create(ndisc_socket, IPPROTO_ICMPV6)) < 0) { printk(KERN_DEBUG - "Failed to create the NDISC control socket.\n"); + "Failed to initializee the NDISC control socket (err %d).\n", + err); + sock_release(ndisc_socket); + ndisc_socket = NULL; /* For safety. */ + return err; + } sk = ndisc_socket->sk; sk->allocation = GFP_ATOMIC; @@ -1174,9 +1179,10 @@ __initfunc(void ndisc_init(struct net_proto_family *ops)) #ifdef CONFIG_SYSCTL neigh_sysctl_register(NULL, &nd_tbl.parms, NET_IPV6, NET_IPV6_NEIGH, "ipv6"); #endif + + return 0; } -#ifdef MODULE void ndisc_cleanup(void) { #ifdef CONFIG_PROC_FS @@ -1185,5 +1191,6 @@ void ndisc_cleanup(void) #endif #endif neigh_table_clear(&nd_tbl); + sock_release(ndisc_socket); + ndisc_socket = NULL; /* For safety. */ } -#endif diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c index 3ec242adb..8a5ae0654 100644 --- a/net/ipv6/protocol.c +++ b/net/ipv6/protocol.c @@ -3,9 +3,9 @@ * operating system. INET is implemented using the BSD Socket * interface as the means of communication with the user level. * - * AF_INET6 protocol dispatch tables. + * PF_INET6 protocol dispatch tables. * - * Version: $Id: protocol.c,v 1.5 1997/03/18 18:24:44 davem Exp $ + * Version: $Id: protocol.c,v 1.6 1998/05/03 14:31:09 alan Exp $ * * Authors: Pedro Roque <roque@di.fc.ul.pt> * diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 7429a9210..659ec59cc 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -7,7 +7,7 @@ * * Adapted from linux/net/ipv4/raw.c * - * $Id: raw.c,v 1.19 1998/03/20 09:12:20 davem Exp $ + * $Id: raw.c,v 1.20 1998/07/15 05:05:41 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -596,6 +596,8 @@ static void rawv6_close(struct sock *sk, unsigned long timeout) { sk->state = TCP_CLOSE; ipv6_sock_mc_close(sk); + if (sk->num == IPPROTO_RAW) + ip6_ra_control(sk, -1, NULL); sk->dead = 1; destroy_sock(sk); } diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 3baa41007..9d159fe36 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: route.c,v 1.28 1998/04/28 06:22:04 davem Exp $ + * $Id: route.c,v 1.32 1998/07/25 23:28:52 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -1722,7 +1722,6 @@ int inet6_rtm_newroute(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) return err; } - struct rt6_rtnl_dump_arg { struct sk_buff *skb; @@ -1733,6 +1732,9 @@ struct rt6_rtnl_dump_arg }; static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, + struct in6_addr *dst, + struct in6_addr *src, + int iif, int type, pid_t pid, u32 seq) { struct rtmsg *rtm; @@ -1777,10 +1779,23 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, #ifdef CONFIG_RTNL_OLD_IFINFO o = skb->tail; #endif - if (rtm->rtm_dst_len) + if (dst) { + RTA_PUT(skb, RTA_DST, 16, dst); + rtm->rtm_dst_len = 128; + } else if (rtm->rtm_dst_len) RTA_PUT(skb, RTA_DST, 16, &rt->rt6i_dst.addr); - if (rtm->rtm_src_len) + if (src) { + RTA_PUT(skb, RTA_SRC, 16, src); + rtm->rtm_src_len = 128; + } else if (rtm->rtm_src_len) RTA_PUT(skb, RTA_SRC, 16, &rt->rt6i_src.addr); + if (iif) + RTA_PUT(skb, RTA_IIF, 4, &iif); + else if (dst) { + struct inet6_ifaddr *ifp = ipv6_get_saddr(&rt->u.dst, dst); + if (ifp) + RTA_PUT(skb, RTA_PREFSRC, 16, &ifp->addr); + } #ifdef CONFIG_RTNL_OLD_IFINFO if (rt->u.dst.pmtu) RTA_PUT(skb, RTA_MTU, sizeof(unsigned), &rt->u.dst.pmtu); @@ -1842,7 +1857,7 @@ static void rt6_dump_node(struct fib6_node *fn, void *p_arg) arg->count++; continue; } - if (rt6_fill_node(arg->skb, rt, RTM_NEWROUTE, + if (rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE, NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq) <= 0) { arg->stop = 1; break; @@ -1870,6 +1885,68 @@ int inet6_dump_fib(struct sk_buff *skb, struct netlink_callback *cb) return skb->len; } +int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg) +{ + struct rtattr **rta = arg; + int iif = 0; + int err; + struct sk_buff *skb; + struct flowi fl; + struct rt6_info *rt; + + skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL); + if (skb == NULL) + return -ENOBUFS; + + /* Reserve room for dummy headers, this skb can pass + through good chunk of routing engine. + */ + skb->mac.raw = skb->data; + skb_reserve(skb, MAX_HEADER + sizeof(struct ipv6hdr)); + + fl.proto = 0; + fl.nl_u.ip6_u.daddr = NULL; + fl.nl_u.ip6_u.saddr = NULL; + fl.uli_u.icmpt.type = 0; + fl.uli_u.icmpt.code = 0; + if (rta[RTA_SRC-1]) + fl.nl_u.ip6_u.saddr = (struct in6_addr*)RTA_DATA(rta[RTA_SRC-1]); + if (rta[RTA_DST-1]) + fl.nl_u.ip6_u.daddr = (struct in6_addr*)RTA_DATA(rta[RTA_DST-1]); + + if (rta[RTA_IIF-1]) + memcpy(&iif, RTA_DATA(rta[RTA_IIF-1]), sizeof(int)); + + if (iif) { + struct device *dev; + dev = dev_get_by_index(iif); + if (!dev) + return -ENODEV; + } + + fl.oif = 0; + if (rta[RTA_OIF-1]) + memcpy(&fl.oif, RTA_DATA(rta[RTA_OIF-1]), sizeof(int)); + + rt = (struct rt6_info*)ip6_route_output(NULL, &fl); + + skb->dst = &rt->u.dst; + + NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid; + err = rt6_fill_node(skb, rt, + fl.nl_u.ip6_u.daddr, + fl.nl_u.ip6_u.saddr, + iif, + RTM_NEWROUTE, NETLINK_CB(in_skb).pid, nlh->nlmsg_seq); + if (err < 0) + return -EMSGSIZE; + + err = netlink_unicast(rtnl, skb, NETLINK_CB(in_skb).pid, MSG_DONTWAIT); + if (err < 0) + return err; + return 0; +} + void inet6_rt_notify(int event, struct rt6_info *rt) { struct sk_buff *skb; @@ -1880,7 +1957,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt) netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS); return; } - if (rt6_fill_node(skb, rt, event, 0, 0) < 0) { + if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0) < 0) { kfree_skb(skb); netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL); return; @@ -2173,5 +2250,6 @@ void ip6_route_cleanup(void) netlink_detach(NETLINK_ROUTE6); #endif rt6_ifdown(NULL); + fib6_gc_cleanup(); } #endif /* MODULE */ diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 0a4a95c7c..5fa45dce5 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -5,7 +5,7 @@ * Authors: * Pedro Roque <roque@di.fc.ul.pt> * - * $Id: tcp_ipv6.c,v 1.80 1998/05/02 12:47:15 davem Exp $ + * $Id: tcp_ipv6.c,v 1.82 1998/06/11 03:15:52 davem Exp $ * * Based on: * linux/net/ipv4/tcp.c @@ -64,9 +64,7 @@ static __inline__ int tcp_v6_hashfn(struct in6_addr *laddr, u16 lport, { int hashent = (lport ^ fport); - hashent ^= (laddr->s6_addr32[0] ^ laddr->s6_addr32[1]); - hashent ^= (faddr->s6_addr32[0] ^ faddr->s6_addr32[1]); - hashent ^= (faddr->s6_addr32[2] ^ faddr->s6_addr32[3]); + hashent ^= (laddr->s6_addr32[3] ^ faddr->s6_addr32[3]); return (hashent & ((TCP_HTABLE_SIZE/2) - 1)); } @@ -145,6 +143,13 @@ go_like_smoke: static void tcp_v6_hash(struct sock *sk) { + /* Well, I know that it is ugly... + All this ->prot, ->af_specific etc. need LARGE cleanup --ANK + */ + if (sk->tp_pinfo.af_tcp.af_specific == &ipv6_mapped) { + tcp_prot.hash(sk); + return; + } if(sk->state != TCP_CLOSE) { struct sock **skp; @@ -213,7 +218,7 @@ static struct sock *tcp_v6_lookup_listener(struct in6_addr *daddr, unsigned shor hiscore=0; sk = tcp_listening_hash[tcp_lhashfn(hnum)]; for(; sk; sk = sk->next) { - if((sk->num == hnum) && (sk->family == AF_INET6)) { + if((sk->num == hnum) && (sk->family == PF_INET6)) { struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; score = 1; @@ -272,7 +277,7 @@ static inline struct sock *__tcp_v6_lookup(struct tcphdr *th, /* Must check for a TIME_WAIT'er before going to listener hash. */ for(sk = tcp_established_hash[hash+(TCP_HTABLE_SIZE/2)]; sk; sk = sk->next) { if(*((__u32 *)&(sk->dport)) == ports && - sk->family == AF_INET6) { + sk->family == PF_INET6) { struct tcp_tw_bucket *tw = (struct tcp_tw_bucket *)sk; if(!ipv6_addr_cmp(&tw->v6_daddr, saddr) && !ipv6_addr_cmp(&tw->v6_rcv_saddr, daddr) && @@ -415,8 +420,14 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, if (err) { sk->tp_pinfo.af_tcp.af_specific = &ipv6_specific; sk->backlog_rcv = tcp_v6_do_rcv; + } else { + /* Yuup... And it is not the only place... --ANK */ + ipv6_addr_set(&np->saddr, 0, 0, __constant_htonl(0x0000FFFF), + sk->saddr); + ipv6_addr_set(&np->rcv_saddr, 0, 0, __constant_htonl(0x0000FFFF), + sk->rcv_saddr); } - + return err; } diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index 6078ab679..2dac0570f 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -7,7 +7,7 @@ * * Based on linux/ipv4/udp.c * - * $Id: udp.c,v 1.27 1998/03/21 07:28:06 davem Exp $ + * $Id: udp.c,v 1.31 1998/07/15 05:05:45 davem Exp $ * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -147,7 +147,7 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, for(sk = udp_hash[hnum & (UDP_HTABLE_SIZE - 1)]; sk != NULL; sk = sk->next) { if((sk->num == hnum) && - (sk->family == AF_INET6) && + (sk->family == PF_INET6) && !(sk->dead && (sk->state == TCP_CLOSE))) { struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; int score = 0; @@ -185,12 +185,18 @@ static struct sock *udp_v6_lookup(struct in6_addr *saddr, u16 sport, int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct sockaddr_in6 *usin = (struct sockaddr_in6 *) uaddr; + struct ipv6_pinfo *np = &sk->net_pinfo.af_inet6; struct in6_addr *daddr; struct dst_entry *dst; - struct ipv6_pinfo *np; struct inet6_ifaddr *ifa; struct flowi fl; int addr_type; + int err; + + if (usin->sin6_family == AF_INET) { + err = udp_connect(sk, uaddr, addr_len); + goto ipv4_connected; + } if (addr_len < sizeof(*usin)) return(-EINVAL); @@ -199,7 +205,6 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) return(-EAFNOSUPPORT); addr_type = ipv6_addr_type(&usin->sin6_addr); - np = &sk->net_pinfo.af_inet6; if (addr_type == IPV6_ADDR_ANY) { /* @@ -212,18 +217,21 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (addr_type == IPV6_ADDR_MAPPED) { struct sockaddr_in sin; - int err; sin.sin_family = AF_INET; sin.sin_addr.s_addr = daddr->s6_addr32[3]; + sin.sin_port = usin->sin6_port; err = udp_connect(sk, (struct sockaddr*) &sin, sizeof(sin)); - + +ipv4_connected: if (err < 0) return err; - ipv6_addr_copy(&np->daddr, daddr); - + ipv6_addr_set(&np->daddr, 0, 0, + __constant_htonl(0x0000ffff), + sk->daddr); + if(ipv6_addr_any(&np->saddr)) { ipv6_addr_set(&np->saddr, 0, 0, __constant_htonl(0x0000ffff), @@ -236,7 +244,7 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) __constant_htonl(0x0000ffff), sk->rcv_saddr); } - + return 0; } ipv6_addr_copy(&np->daddr, daddr); @@ -347,6 +355,8 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len, if (skb->protocol == __constant_htons(ETH_P_IP)) { ipv6_addr_set(&sin6->sin6_addr, 0, 0, __constant_htonl(0xffff), skb->nh.iph->saddr); + if (sk->ip_cmsg_flags) + ip_cmsg_recv(msg, skb); } else { memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr, sizeof(struct in6_addr)); @@ -668,6 +678,9 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen) return(-EINVAL); if (sin6) { + if (sin6->sin6_family == AF_INET) + return udp_sendmsg(sk, msg, ulen); + if (addr_len < sizeof(*sin6)) return(-EINVAL); @@ -689,7 +702,7 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen) } } else { if (sk->state != TCP_ESTABLISHED) - return(-EINVAL); + return(-ENOTCONN); udh.uh.dest = sk->dport; daddr = &sk->net_pinfo.af_inet6.daddr; @@ -702,8 +715,10 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen) sin.sin_family = AF_INET; sin.sin_addr.s_addr = daddr->s6_addr32[3]; + sin.sin_port = udh.uh.dest; + msg->msg_name = (struct sockaddr *)(&sin); - return udp_sendmsg(sk, msg, len); + return udp_sendmsg(sk, msg, ulen); } udh.daddr = NULL; |