From 6e1d9d04c4004361fb327abcbde74a20e8dca2ff Mon Sep 17 00:00:00 2001 From: YOSHIFUJI Hideaki Date: Mon, 12 Feb 2007 20:26:39 -0800 Subject: [IPV6] HASHTABLES: Use appropriate seed for caluculating ehash index. Tetsuo Handa told me that connect(2) with TCPv6 socket almost always took a few minutes to return when we did not have any ports available in the range of net.ipv4.ip_local_port_range. The reason was that we used incorrect seed for calculating index of hash when we check established sockets in __inet6_check_established(). Signed-off-by: YOSHIFUJI Hideaki Signed-off-by: David S. Miller --- net/ipv6/inet6_hashtables.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/ipv6/inet6_hashtables.c b/net/ipv6/inet6_hashtables.c index 30b16da739c2..ae6b0e7eb488 100644 --- a/net/ipv6/inet6_hashtables.c +++ b/net/ipv6/inet6_hashtables.c @@ -172,7 +172,7 @@ static int __inet6_check_established(struct inet_timewait_death_row *death_row, const struct in6_addr *saddr = &np->daddr; const int dif = sk->sk_bound_dev_if; const __portpair ports = INET_COMBINED_PORTS(inet->dport, lport); - const unsigned int hash = inet6_ehashfn(daddr, inet->num, saddr, + const unsigned int hash = inet6_ehashfn(daddr, lport, saddr, inet->dport); struct inet_ehash_bucket *head = inet_ehash_bucket(hinfo, hash); struct sock *sk2; -- cgit v1.2.3-59-g8ed1b From e2e01bfef8399c8f39c9fdf4a5576039069e760c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Mon, 12 Feb 2007 20:27:10 -0800 Subject: [XFRM]: Fix IPv4 tunnel mode decapsulation with IPV6=n Add missing break when CONFIG_IPV6=n. Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/ipv4/xfrm4_mode_tunnel.c | 1 + 1 file changed, 1 insertion(+) (limited to 'net') diff --git a/net/ipv4/xfrm4_mode_tunnel.c b/net/ipv4/xfrm4_mode_tunnel.c index e54c5494c88f..e1cab33fdad1 100644 --- a/net/ipv4/xfrm4_mode_tunnel.c +++ b/net/ipv4/xfrm4_mode_tunnel.c @@ -95,6 +95,7 @@ static int xfrm4_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) switch(iph->protocol){ case IPPROTO_IPIP: + break; #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) case IPPROTO_IPV6: break; -- cgit v1.2.3-59-g8ed1b From bbf4a6bc8c4d59a0a9033fc2cb96ec03430c96e4 Mon Sep 17 00:00:00 2001 From: Herbert Xu Date: Tue, 13 Feb 2007 12:32:58 -0800 Subject: [NETFILTER]: Clear GSO bits for TCP reset packet The TCP reset packet is copied from the original. This includes all the GSO bits which do not apply to the new packet. So we should clear those bits. Spotted by Patrick McHardy. Signed-off-by: Herbert Xu Signed-off-by: David S. Miller --- net/ipv4/netfilter/ipt_REJECT.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'net') diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c index a9eb3635fff2..80f739e21824 100644 --- a/net/ipv4/netfilter/ipt_REJECT.c +++ b/net/ipv4/netfilter/ipt_REJECT.c @@ -80,6 +80,10 @@ static void send_reset(struct sk_buff *oldskb, int hook) nskb->mark = 0; skb_init_secmark(nskb); + skb_shinfo(nskb)->gso_size = 0; + skb_shinfo(nskb)->gso_segs = 0; + skb_shinfo(nskb)->gso_type = 0; + tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); /* Swap source and dest */ -- cgit v1.2.3-59-g8ed1b From a10d567c89dfba90dde2e0515e25760fd74cde06 Mon Sep 17 00:00:00 2001 From: Jarek Poplawski Date: Tue, 13 Feb 2007 12:35:26 -0800 Subject: [BRIDGE] br_if: Fix oops in port_carrier_check Signed-off-by: Jarek Poplawski Acked-by: Stephen Hemminger Signed-off-by: David S. Miller --- net/bridge/br_if.c | 8 ++++++-- net/bridge/br_notify.c | 4 +++- 2 files changed, 9 insertions(+), 3 deletions(-) (limited to 'net') diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c index f35c1a378d0f..aff6a779c9c8 100644 --- a/net/bridge/br_if.c +++ b/net/bridge/br_if.c @@ -108,6 +108,7 @@ static void port_carrier_check(struct work_struct *work) spin_unlock_bh(&br->lock); } done: + dev_put(dev); rtnl_unlock(); } @@ -161,7 +162,8 @@ static void del_nbp(struct net_bridge_port *p) dev_set_promiscuity(dev, -1); - cancel_delayed_work(&p->carrier_check); + if (cancel_delayed_work(&p->carrier_check)) + dev_put(dev); spin_lock_bh(&br->lock); br_stp_disable_port(p); @@ -444,7 +446,9 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) spin_lock_bh(&br->lock); br_stp_recalculate_bridge_id(br); br_features_recompute(br); - schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE); + if (schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE)) + dev_hold(dev); + spin_unlock_bh(&br->lock); dev_set_mtu(br->dev, br_min_mtu(br)); diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c index 8cd3e4229070..3311c4e30829 100644 --- a/net/bridge/br_notify.c +++ b/net/bridge/br_notify.c @@ -56,7 +56,9 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v case NETDEV_CHANGE: if (br->dev->flags & IFF_UP) - schedule_delayed_work(&p->carrier_check, BR_PORT_DEBOUNCE); + if (schedule_delayed_work(&p->carrier_check, + BR_PORT_DEBOUNCE)) + dev_hold(dev); break; case NETDEV_FEAT_CHANGE: -- cgit v1.2.3-59-g8ed1b From 3d50f23108ff01457d1ca6fb2b5f2da8214e83e4 Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Tue, 13 Feb 2007 12:36:57 -0800 Subject: [NET_SCHED]: sch_hfsc: replace ASSERT macro by WARN_ON Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- net/sched/sch_hfsc.c | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) (limited to 'net') diff --git a/net/sched/sch_hfsc.c b/net/sched/sch_hfsc.c index 135087d4213a..396deb71480f 100644 --- a/net/sched/sch_hfsc.c +++ b/net/sched/sch_hfsc.c @@ -71,8 +71,6 @@ #include #include -#define HFSC_DEBUG 1 - /* * kernel internal service curve representation: * coordinates are given by 64 bit unsigned integers. @@ -211,17 +209,6 @@ do { \ } while (0) #endif -#if HFSC_DEBUG -#define ASSERT(cond) \ -do { \ - if (unlikely(!(cond))) \ - printk("assertion %s failed at %s:%i (%s)\n", \ - #cond, __FILE__, __LINE__, __FUNCTION__); \ -} while (0) -#else -#define ASSERT(cond) -#endif /* HFSC_DEBUG */ - #define HT_INFINITY 0xffffffffffffffffULL /* infinite time value */ @@ -1492,7 +1479,7 @@ hfsc_schedule_watchdog(struct Qdisc *sch, u64 cur_time) if (next_time == 0 || next_time > q->root.cl_cfmin) next_time = q->root.cl_cfmin; } - ASSERT(next_time != 0); + WARN_ON(next_time == 0); delay = next_time - cur_time; delay = PSCHED_US2JIFFIE(delay); -- cgit v1.2.3-59-g8ed1b From 600ff0c24bb71482e7f0da948a931d5c5d72838a Mon Sep 17 00:00:00 2001 From: Ilpo Järvinen Date: Tue, 13 Feb 2007 12:42:11 -0800 Subject: [TCP]: Prevent pseudo garbage in SYN's advertized window MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit TCP may advertize up to 16-bits window in SYN packets (no window scaling allowed). At the same time, TCP may have rcv_wnd (32-bits) that does not fit to 16-bits without window scaling resulting in pseudo garbage into advertized window from the low-order bits of rcv_wnd. This can happen at least when mss <= (1< Signed-off-by: David S. Miller --- net/ipv4/tcp_output.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'net') diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index cebe9aa918a3..dc151139b5af 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -481,7 +481,7 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, /* RFC1323: The window in SYN & SYN/ACK segments * is never scaled. */ - th->window = htons(tp->rcv_wnd); + th->window = htons(min(tp->rcv_wnd, 65535U)); } else { th->window = htons(tcp_select_window(sk)); } @@ -2160,7 +2160,7 @@ struct sk_buff * tcp_make_synack(struct sock *sk, struct dst_entry *dst, } /* RFC1323: The window in SYN & SYN/ACK segments is never scaled. */ - th->window = htons(req->rcv_wnd); + th->window = htons(min(req->rcv_wnd, 65535U)); TCP_SKB_CB(skb)->when = tcp_time_stamp; tcp_syn_build_options((__be32 *)(th + 1), dst_metric(dst, RTAX_ADVMSS), ireq->tstamp_ok, -- cgit v1.2.3-59-g8ed1b From c0d56408e3ff52d635441e0f08d12164a63728cf Mon Sep 17 00:00:00 2001 From: Kazunori MIYAZAWA Date: Tue, 13 Feb 2007 12:54:47 -0800 Subject: [IPSEC]: Changing API of xfrm4_tunnel_register. This patch changes xfrm4_tunnel register and deregister interface to prepare for solving the conflict of device tunnels with inter address family IPsec tunnel. Signed-off-by: Kazunori MIYAZAWA Signed-off-by: David S. Miller --- include/net/xfrm.h | 4 ++-- net/ipv4/ipip.c | 6 +++--- net/ipv4/tunnel4.c | 50 +++++++++++++++++++++++++++++++++++++++++++++---- net/ipv4/xfrm4_input.c | 4 +++- net/ipv4/xfrm4_tunnel.c | 29 ++++++++++++++++++++++++---- 5 files changed, 79 insertions(+), 14 deletions(-) (limited to 'net') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 16924cb772c9..20be8beb9a11 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -946,8 +946,8 @@ extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); extern int xfrm_init_state(struct xfrm_state *x); extern int xfrm4_rcv(struct sk_buff *skb); extern int xfrm4_output(struct sk_buff *skb); -extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); -extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); +extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family); +extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family); extern int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi); extern int xfrm6_rcv(struct sk_buff **pskb); extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c index 475bcd1e4181..9b561e633b00 100644 --- a/net/ipv4/ipip.c +++ b/net/ipv4/ipip.c @@ -871,7 +871,7 @@ static int __init ipip_init(void) printk(banner); - if (xfrm4_tunnel_register(&ipip_handler)) { + if (xfrm4_tunnel_register(&ipip_handler, AF_INET)) { printk(KERN_INFO "ipip init: can't register tunnel\n"); return -EAGAIN; } @@ -893,7 +893,7 @@ static int __init ipip_init(void) err2: free_netdev(ipip_fb_tunnel_dev); err1: - xfrm4_tunnel_deregister(&ipip_handler); + xfrm4_tunnel_deregister(&ipip_handler, AF_INET); goto out; } @@ -913,7 +913,7 @@ static void __exit ipip_destroy_tunnels(void) static void __exit ipip_fini(void) { - if (xfrm4_tunnel_deregister(&ipip_handler)) + if (xfrm4_tunnel_deregister(&ipip_handler, AF_INET)) printk(KERN_INFO "ipip close: can't deregister tunnel\n"); rtnl_lock(); diff --git a/net/ipv4/tunnel4.c b/net/ipv4/tunnel4.c index 8d30c48f090e..a794a8ca8b4f 100644 --- a/net/ipv4/tunnel4.c +++ b/net/ipv4/tunnel4.c @@ -14,9 +14,10 @@ #include static struct xfrm_tunnel *tunnel4_handlers; +static struct xfrm_tunnel *tunnel64_handlers; static DEFINE_MUTEX(tunnel4_mutex); -int xfrm4_tunnel_register(struct xfrm_tunnel *handler) +int xfrm4_tunnel_register(struct xfrm_tunnel *handler, unsigned short family) { struct xfrm_tunnel **pprev; int ret = -EEXIST; @@ -24,7 +25,8 @@ int xfrm4_tunnel_register(struct xfrm_tunnel *handler) mutex_lock(&tunnel4_mutex); - for (pprev = &tunnel4_handlers; *pprev; pprev = &(*pprev)->next) { + for (pprev = (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; + *pprev; pprev = &(*pprev)->next) { if ((*pprev)->priority > priority) break; if ((*pprev)->priority == priority) @@ -44,14 +46,15 @@ err: EXPORT_SYMBOL(xfrm4_tunnel_register); -int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler) +int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler, unsigned short family) { struct xfrm_tunnel **pprev; int ret = -ENOENT; mutex_lock(&tunnel4_mutex); - for (pprev = &tunnel4_handlers; *pprev; pprev = &(*pprev)->next) { + for (pprev = (family == AF_INET) ? &tunnel4_handlers : &tunnel64_handlers; + *pprev; pprev = &(*pprev)->next) { if (*pprev == handler) { *pprev = handler->next; ret = 0; @@ -86,6 +89,26 @@ drop: return 0; } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +static int tunnel64_rcv(struct sk_buff *skb) +{ + struct xfrm_tunnel *handler; + + if (!pskb_may_pull(skb, sizeof(struct iphdr))) + goto drop; + + for (handler = tunnel64_handlers; handler; handler = handler->next) + if (!handler->handler(skb)) + return 0; + + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0); + +drop: + kfree_skb(skb); + return 0; +} +#endif + static void tunnel4_err(struct sk_buff *skb, u32 info) { struct xfrm_tunnel *handler; @@ -101,17 +124,36 @@ static struct net_protocol tunnel4_protocol = { .no_policy = 1, }; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +static struct net_protocol tunnel64_protocol = { + .handler = tunnel64_rcv, + .err_handler = tunnel4_err, + .no_policy = 1, +}; +#endif + static int __init tunnel4_init(void) { if (inet_add_protocol(&tunnel4_protocol, IPPROTO_IPIP)) { printk(KERN_ERR "tunnel4 init: can't add protocol\n"); return -EAGAIN; } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (inet_add_protocol(&tunnel64_protocol, IPPROTO_IPV6)) { + printk(KERN_ERR "tunnel64 init: can't add protocol\n"); + inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP); + return -EAGAIN; + } +#endif return 0; } static void __exit tunnel4_fini(void) { +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (inet_del_protocol(&tunnel64_protocol, IPPROTO_IPV6)) + printk(KERN_ERR "tunnel64 close: can't remove protocol\n"); +#endif if (inet_del_protocol(&tunnel4_protocol, IPPROTO_IPIP)) printk(KERN_ERR "tunnel4 close: can't remove protocol\n"); } diff --git a/net/ipv4/xfrm4_input.c b/net/ipv4/xfrm4_input.c index 289146bdb8b0..78e80deb7e89 100644 --- a/net/ipv4/xfrm4_input.c +++ b/net/ipv4/xfrm4_input.c @@ -27,6 +27,7 @@ static int xfrm4_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 { switch (nexthdr) { case IPPROTO_IPIP: + case IPPROTO_IPV6: *spi = skb->nh.iph->saddr; *seq = 0; return 0; @@ -70,7 +71,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type) if (xfrm_nr == XFRM_MAX_DEPTH) goto drop; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, iph->protocol, AF_INET); + x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, + iph->protocol != IPPROTO_IPV6 ? iph->protocol : IPPROTO_IPIP, AF_INET); if (x == NULL) goto drop; diff --git a/net/ipv4/xfrm4_tunnel.c b/net/ipv4/xfrm4_tunnel.c index 1be6762b2d47..3eef06454da9 100644 --- a/net/ipv4/xfrm4_tunnel.c +++ b/net/ipv4/xfrm4_tunnel.c @@ -64,24 +64,45 @@ static struct xfrm_tunnel xfrm_tunnel_handler = { .priority = 2, }; +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) +static struct xfrm_tunnel xfrm64_tunnel_handler = { + .handler = xfrm4_rcv, + .err_handler = xfrm_tunnel_err, + .priority = 2, +}; +#endif + static int __init ipip_init(void) { if (xfrm_register_type(&ipip_type, AF_INET) < 0) { printk(KERN_INFO "ipip init: can't add xfrm type\n"); return -EAGAIN; } - if (xfrm4_tunnel_register(&xfrm_tunnel_handler)) { - printk(KERN_INFO "ipip init: can't add xfrm handler\n"); + + if (xfrm4_tunnel_register(&xfrm_tunnel_handler, AF_INET)) { + printk(KERN_INFO "ipip init: can't add xfrm handler for AF_INET\n"); + xfrm_unregister_type(&ipip_type, AF_INET); + return -EAGAIN; + } +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (xfrm4_tunnel_register(&xfrm64_tunnel_handler, AF_INET6)) { + printk(KERN_INFO "ipip init: can't add xfrm handler for AF_INET6\n"); + xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET); xfrm_unregister_type(&ipip_type, AF_INET); return -EAGAIN; } +#endif return 0; } static void __exit ipip_fini(void) { - if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler)) - printk(KERN_INFO "ipip close: can't remove xfrm handler\n"); +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + if (xfrm4_tunnel_deregister(&xfrm64_tunnel_handler, AF_INET6)) + printk(KERN_INFO "ipip close: can't remove xfrm handler for AF_INET6\n"); +#endif + if (xfrm4_tunnel_deregister(&xfrm_tunnel_handler, AF_INET)) + printk(KERN_INFO "ipip close: can't remove xfrm handler for AF_INET\n"); if (xfrm_unregister_type(&ipip_type, AF_INET) < 0) printk(KERN_INFO "ipip close: can't remove xfrm type\n"); } -- cgit v1.2.3-59-g8ed1b From c73cb5a2d607b5b95a06a54d8291ddb659b348b6 Mon Sep 17 00:00:00 2001 From: Kazunori MIYAZAWA Date: Tue, 13 Feb 2007 12:55:25 -0800 Subject: [IPSEC]: make sit use the xfrm4_tunnel_register This patch makes sit use xfrm4_tunnel_register instead of inet_add_protocol. It solves conflict of sit device with inter address family IPsec tunnel. Signed-off-by: Kazunori MIYAZAWA Signed-off-by: David S. Miller --- net/ipv6/Kconfig | 1 + net/ipv6/sit.c | 30 ++++++++++++++++++------------ 2 files changed, 19 insertions(+), 12 deletions(-) (limited to 'net') diff --git a/net/ipv6/Kconfig b/net/ipv6/Kconfig index deb4101a2a81..79682efb14be 100644 --- a/net/ipv6/Kconfig +++ b/net/ipv6/Kconfig @@ -156,6 +156,7 @@ config INET6_XFRM_MODE_ROUTEOPTIMIZATION config IPV6_SIT tristate "IPv6: IPv6-in-IPv4 tunnel (SIT driver)" depends on IPV6 + select INET_TUNNEL default y ---help--- Tunneling means encapsulating data of one protocol type within diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c index 4d3cf301e1fc..862ed7c52c38 100644 --- a/net/ipv6/sit.c +++ b/net/ipv6/sit.c @@ -216,7 +216,7 @@ static void ipip6_tunnel_uninit(struct net_device *dev) } -static void ipip6_err(struct sk_buff *skb, u32 info) +static int ipip6_err(struct sk_buff *skb, u32 info) { #ifndef I_WISH_WORLD_WERE_PERFECT @@ -228,21 +228,22 @@ static void ipip6_err(struct sk_buff *skb, u32 info) int type = skb->h.icmph->type; int code = skb->h.icmph->code; struct ip_tunnel *t; + int err; switch (type) { default: case ICMP_PARAMETERPROB: - return; + return 0; case ICMP_DEST_UNREACH: switch (code) { case ICMP_SR_FAILED: case ICMP_PORT_UNREACH: /* Impossible event. */ - return; + return 0; case ICMP_FRAG_NEEDED: /* Soft state for pmtu is maintained by IP core. */ - return; + return 0; default: /* All others are translated to HOST_UNREACH. rfc2003 contains "deep thoughts" about NET_UNREACH, @@ -253,14 +254,18 @@ static void ipip6_err(struct sk_buff *skb, u32 info) break; case ICMP_TIME_EXCEEDED: if (code != ICMP_EXC_TTL) - return; + return 0; break; } + err = -ENOENT; + read_lock(&ipip6_lock); t = ipip6_tunnel_lookup(iph->daddr, iph->saddr); if (t == NULL || t->parms.iph.daddr == 0) goto out; + + err = 0; if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED) goto out; @@ -271,7 +276,7 @@ static void ipip6_err(struct sk_buff *skb, u32 info) t->err_time = jiffies; out: read_unlock(&ipip6_lock); - return; + return err; #else struct iphdr *iph = (struct iphdr*)dp; int hlen = iph->ihl<<2; @@ -332,7 +337,7 @@ out: /* Prepare fake skb to feed it to icmpv6_send */ skb2 = skb_clone(skb, GFP_ATOMIC); if (skb2 == NULL) - return; + return 0; dst_release(skb2->dst); skb2->dst = NULL; skb_pull(skb2, skb->data - (u8*)iph6); @@ -355,7 +360,7 @@ out: } } kfree_skb(skb2); - return; + return 0; #endif } @@ -791,9 +796,10 @@ static int __init ipip6_fb_tunnel_init(struct net_device *dev) return 0; } -static struct net_protocol sit_protocol = { +static struct xfrm_tunnel sit_handler = { .handler = ipip6_rcv, .err_handler = ipip6_err, + .priority = 1, }; static void __exit sit_destroy_tunnels(void) @@ -812,7 +818,7 @@ static void __exit sit_destroy_tunnels(void) static void __exit sit_cleanup(void) { - inet_del_protocol(&sit_protocol, IPPROTO_IPV6); + xfrm4_tunnel_deregister(&sit_handler, AF_INET6); rtnl_lock(); sit_destroy_tunnels(); @@ -826,7 +832,7 @@ static int __init sit_init(void) printk(KERN_INFO "IPv6 over IPv4 tunneling driver\n"); - if (inet_add_protocol(&sit_protocol, IPPROTO_IPV6) < 0) { + if (xfrm4_tunnel_register(&sit_handler, AF_INET6) < 0) { printk(KERN_INFO "sit init: Can't add protocol\n"); return -EAGAIN; } @@ -848,7 +854,7 @@ static int __init sit_init(void) err2: free_netdev(ipip6_fb_tunnel_dev); err1: - inet_del_protocol(&sit_protocol, IPPROTO_IPV6); + xfrm4_tunnel_deregister(&sit_handler, AF_INET6); goto out; } -- cgit v1.2.3-59-g8ed1b From 73d605d1abbd70ef67b7660cf2ff177259960756 Mon Sep 17 00:00:00 2001 From: Kazunori MIYAZAWA Date: Tue, 13 Feb 2007 12:55:55 -0800 Subject: [IPSEC]: changing API of xfrm6_tunnel_register This patch changes xfrm6_tunnel register and deregister interface to prepare for solving the conflict of device tunnels with inter address family IPsec tunnel. There is no device which conflicts with IPv4 over IPv6 IPsec tunnel. Signed-off-by: Kazunori MIYAZAWA Signed-off-by: David S. Miller --- include/net/xfrm.h | 4 ++-- net/ipv6/ip6_tunnel.c | 6 +++--- net/ipv6/tunnel6.c | 43 +++++++++++++++++++++++++++++++++++++++---- net/ipv6/xfrm6_input.c | 3 ++- net/ipv6/xfrm6_tunnel.c | 19 ++++++++++++++++--- 5 files changed, 62 insertions(+), 13 deletions(-) (limited to 'net') diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 20be8beb9a11..92a1fc46ea59 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -952,8 +952,8 @@ extern int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi); extern int xfrm6_rcv(struct sk_buff **pskb); extern int xfrm6_input_addr(struct sk_buff *skb, xfrm_address_t *daddr, xfrm_address_t *saddr, u8 proto); -extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler); -extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler); +extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family); +extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family); extern __be32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr); extern __be32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr); diff --git a/net/ipv6/ip6_tunnel.c b/net/ipv6/ip6_tunnel.c index 367b74832986..662edb826899 100644 --- a/net/ipv6/ip6_tunnel.c +++ b/net/ipv6/ip6_tunnel.c @@ -1128,7 +1128,7 @@ static int __init ip6_tunnel_init(void) { int err; - if (xfrm6_tunnel_register(&ip6ip6_handler)) { + if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) { printk(KERN_ERR "ip6ip6 init: can't register tunnel\n"); return -EAGAIN; } @@ -1147,7 +1147,7 @@ static int __init ip6_tunnel_init(void) } return 0; fail: - xfrm6_tunnel_deregister(&ip6ip6_handler); + xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6); return err; } @@ -1171,7 +1171,7 @@ static void __exit ip6ip6_destroy_tunnels(void) static void __exit ip6_tunnel_cleanup(void) { - if (xfrm6_tunnel_deregister(&ip6ip6_handler)) + if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6)) printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n"); rtnl_lock(); diff --git a/net/ipv6/tunnel6.c b/net/ipv6/tunnel6.c index 918d07dd1219..23e2809878ae 100644 --- a/net/ipv6/tunnel6.c +++ b/net/ipv6/tunnel6.c @@ -30,9 +30,10 @@ #include static struct xfrm6_tunnel *tunnel6_handlers; +static struct xfrm6_tunnel *tunnel46_handlers; static DEFINE_MUTEX(tunnel6_mutex); -int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) +int xfrm6_tunnel_register(struct xfrm6_tunnel *handler, unsigned short family) { struct xfrm6_tunnel **pprev; int ret = -EEXIST; @@ -40,7 +41,8 @@ int xfrm6_tunnel_register(struct xfrm6_tunnel *handler) mutex_lock(&tunnel6_mutex); - for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) { + for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; + *pprev; pprev = &(*pprev)->next) { if ((*pprev)->priority > priority) break; if ((*pprev)->priority == priority) @@ -60,14 +62,15 @@ err: EXPORT_SYMBOL(xfrm6_tunnel_register); -int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler) +int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler, unsigned short family) { struct xfrm6_tunnel **pprev; int ret = -ENOENT; mutex_lock(&tunnel6_mutex); - for (pprev = &tunnel6_handlers; *pprev; pprev = &(*pprev)->next) { + for (pprev = (family == AF_INET6) ? &tunnel6_handlers : &tunnel46_handlers; + *pprev; pprev = &(*pprev)->next) { if (*pprev == handler) { *pprev = handler->next; ret = 0; @@ -103,6 +106,25 @@ drop: return 0; } +static int tunnel46_rcv(struct sk_buff **pskb) +{ + struct sk_buff *skb = *pskb; + struct xfrm6_tunnel *handler; + + if (!pskb_may_pull(skb, sizeof(struct ipv6hdr))) + goto drop; + + for (handler = tunnel46_handlers; handler; handler = handler->next) + if (!handler->handler(skb)) + return 0; + + icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_PORT_UNREACH, 0, skb->dev); + +drop: + kfree_skb(skb); + return 0; +} + static void tunnel6_err(struct sk_buff *skb, struct inet6_skb_parm *opt, int type, int code, int offset, __be32 info) { @@ -119,17 +141,30 @@ static struct inet6_protocol tunnel6_protocol = { .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, }; +static struct inet6_protocol tunnel46_protocol = { + .handler = tunnel46_rcv, + .err_handler = tunnel6_err, + .flags = INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL, +}; + static int __init tunnel6_init(void) { if (inet6_add_protocol(&tunnel6_protocol, IPPROTO_IPV6)) { printk(KERN_ERR "tunnel6 init(): can't add protocol\n"); return -EAGAIN; } + if (inet6_add_protocol(&tunnel46_protocol, IPPROTO_IPIP)) { + printk(KERN_ERR "tunnel6 init(): can't add protocol\n"); + inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6); + return -EAGAIN; + } return 0; } static void __exit tunnel6_fini(void) { + if (inet6_del_protocol(&tunnel46_protocol, IPPROTO_IPIP)) + printk(KERN_ERR "tunnel6 close: can't remove protocol\n"); if (inet6_del_protocol(&tunnel6_protocol, IPPROTO_IPV6)) printk(KERN_ERR "tunnel6 close: can't remove protocol\n"); } diff --git a/net/ipv6/xfrm6_input.c b/net/ipv6/xfrm6_input.c index 25250147bdc3..31f651f95096 100644 --- a/net/ipv6/xfrm6_input.c +++ b/net/ipv6/xfrm6_input.c @@ -40,7 +40,8 @@ int xfrm6_rcv_spi(struct sk_buff *skb, __be32 spi) if (xfrm_nr == XFRM_MAX_DEPTH) goto drop; - x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, nexthdr, AF_INET6); + x = xfrm_state_lookup((xfrm_address_t *)&iph->daddr, spi, + nexthdr != IPPROTO_IPIP ? nexthdr : IPPROTO_IPV6, AF_INET6); if (x == NULL) goto drop; spin_lock(&x->lock); diff --git a/net/ipv6/xfrm6_tunnel.c b/net/ipv6/xfrm6_tunnel.c index fb0228772f01..ee4b84a33ff4 100644 --- a/net/ipv6/xfrm6_tunnel.c +++ b/net/ipv6/xfrm6_tunnel.c @@ -339,17 +339,29 @@ static struct xfrm6_tunnel xfrm6_tunnel_handler = { .priority = 2, }; +static struct xfrm6_tunnel xfrm46_tunnel_handler = { + .handler = xfrm6_tunnel_rcv, + .err_handler = xfrm6_tunnel_err, + .priority = 2, +}; + static int __init xfrm6_tunnel_init(void) { if (xfrm_register_type(&xfrm6_tunnel_type, AF_INET6) < 0) return -EAGAIN; - if (xfrm6_tunnel_register(&xfrm6_tunnel_handler)) { + if (xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6)) { + xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); + return -EAGAIN; + } + if (xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET)) { + xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); return -EAGAIN; } if (xfrm6_tunnel_spi_init() < 0) { - xfrm6_tunnel_deregister(&xfrm6_tunnel_handler); + xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); + xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); return -EAGAIN; } @@ -359,7 +371,8 @@ static int __init xfrm6_tunnel_init(void) static void __exit xfrm6_tunnel_fini(void) { xfrm6_tunnel_spi_fini(); - xfrm6_tunnel_deregister(&xfrm6_tunnel_handler); + xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); + xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); } -- cgit v1.2.3-59-g8ed1b From 928ba4169dc1d82c83105831f5ddb5472379b440 Mon Sep 17 00:00:00 2001 From: Kazunori MIYAZAWA Date: Tue, 13 Feb 2007 12:57:16 -0800 Subject: [IPSEC]: Fix the address family to refer encap_family Fix the address family to refer encap_family when comparing with a kernel generated xfrm_state Signed-off-by: Kazunori MIYAZAWA Signed-off-by: David S. Miller --- net/xfrm/xfrm_policy.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'net') diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index c394b413f651..946b715db5ec 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -1550,7 +1550,7 @@ xfrm_state_ok(struct xfrm_tmpl *tmpl, struct xfrm_state *x, unsigned short family) { if (xfrm_state_kern(x)) - return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, family); + return tmpl->optional && !xfrm_state_addr_cmp(tmpl, x, tmpl->encap_family); return x->id.proto == tmpl->id.proto && (x->id.spi == tmpl->id.spi || !tmpl->id.spi) && (x->props.reqid == tmpl->reqid || !tmpl->reqid) && -- cgit v1.2.3-59-g8ed1b