From 5dee9e7c4c869fcffccc3d432b755793dfa71376 Mon Sep 17 00:00:00 2001 From: Marcel Holtmann Date: Thu, 24 May 2007 14:27:19 +0200 Subject: [Bluetooth] Fix L2CAP configuration parameter handling The L2CAP configuration parameter handling was missing the support for rejecting unknown options. The capability to reject unknown options is mandatory since the Bluetooth 1.2 specification. This patch implements its and also simplifies the parameter parsing. Signed-off-by: Marcel Holtmann --- include/net/bluetooth/l2cap.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) (limited to 'include') diff --git a/include/net/bluetooth/l2cap.h b/include/net/bluetooth/l2cap.h index 8242a0ee1f58..87df4e87622d 100644 --- a/include/net/bluetooth/l2cap.h +++ b/include/net/bluetooth/l2cap.h @@ -129,8 +129,10 @@ struct l2cap_conf_rsp { __u8 data[0]; } __attribute__ ((packed)); -#define L2CAP_CONF_SUCCESS 0x00 -#define L2CAP_CONF_UNACCEPT 0x01 +#define L2CAP_CONF_SUCCESS 0x0000 +#define L2CAP_CONF_UNACCEPT 0x0001 +#define L2CAP_CONF_REJECT 0x0002 +#define L2CAP_CONF_UNKNOWN 0x0003 struct l2cap_conf_opt { __u8 type; @@ -215,6 +217,8 @@ struct l2cap_pinfo { __u32 link_mode; + __u8 conf_req[64]; + __u8 conf_len; __u8 conf_state; __u8 conf_retry; __u16 conf_mtu; -- cgit v1.2.3-55-g7522 From 25b86e05467a2bf936b78695ef49039e3bbd1e0c Mon Sep 17 00:00:00 2001 From: Patrick McHardy Date: Thu, 24 May 2007 16:41:50 -0700 Subject: [NETFILTER]: nf_conntrack_ftp: fix newline sequence number calculation When the packet size is changed by the FTP NAT helper, the connection tracking helper adjusts the sequence number of the newline character by the size difference. This is wrong because NAT sequence number adjustment happens after helpers are called, so the unadjusted number is compared to the already adjusted one. Based on report by YU, Haitao Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_ftp.h | 3 +-- net/ipv4/netfilter/nf_nat_ftp.c | 20 ++++++-------------- net/netfilter/nf_conntrack_ftp.c | 5 ++--- 3 files changed, 9 insertions(+), 19 deletions(-) (limited to 'include') diff --git a/include/linux/netfilter/nf_conntrack_ftp.h b/include/linux/netfilter/nf_conntrack_ftp.h index 81453ea7e4c2..b7c360ffd0d0 100644 --- a/include/linux/netfilter/nf_conntrack_ftp.h +++ b/include/linux/netfilter/nf_conntrack_ftp.h @@ -37,8 +37,7 @@ extern unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb, enum nf_ct_ftp_type type, unsigned int matchoff, unsigned int matchlen, - struct nf_conntrack_expect *exp, - u32 *seq); + struct nf_conntrack_expect *exp); #endif /* __KERNEL__ */ #endif /* _NF_CONNTRACK_FTP_H */ diff --git a/net/ipv4/netfilter/nf_nat_ftp.c b/net/ipv4/netfilter/nf_nat_ftp.c index 751b59801755..e6bc8e5a72f1 100644 --- a/net/ipv4/netfilter/nf_nat_ftp.c +++ b/net/ipv4/netfilter/nf_nat_ftp.c @@ -40,8 +40,7 @@ mangle_rfc959_packet(struct sk_buff **pskb, unsigned int matchoff, unsigned int matchlen, struct nf_conn *ct, - enum ip_conntrack_info ctinfo, - u32 *seq) + enum ip_conntrack_info ctinfo) { char buffer[sizeof("nnn,nnn,nnn,nnn,nnn,nnn")]; @@ -50,7 +49,6 @@ mangle_rfc959_packet(struct sk_buff **pskb, DEBUGP("calling nf_nat_mangle_tcp_packet\n"); - *seq += strlen(buffer) - matchlen; return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, matchlen, buffer, strlen(buffer)); } @@ -63,8 +61,7 @@ mangle_eprt_packet(struct sk_buff **pskb, unsigned int matchoff, unsigned int matchlen, struct nf_conn *ct, - enum ip_conntrack_info ctinfo, - u32 *seq) + enum ip_conntrack_info ctinfo) { char buffer[sizeof("|1|255.255.255.255|65535|")]; @@ -72,7 +69,6 @@ mangle_eprt_packet(struct sk_buff **pskb, DEBUGP("calling nf_nat_mangle_tcp_packet\n"); - *seq += strlen(buffer) - matchlen; return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, matchlen, buffer, strlen(buffer)); } @@ -85,8 +81,7 @@ mangle_epsv_packet(struct sk_buff **pskb, unsigned int matchoff, unsigned int matchlen, struct nf_conn *ct, - enum ip_conntrack_info ctinfo, - u32 *seq) + enum ip_conntrack_info ctinfo) { char buffer[sizeof("|||65535|")]; @@ -94,14 +89,13 @@ mangle_epsv_packet(struct sk_buff **pskb, DEBUGP("calling nf_nat_mangle_tcp_packet\n"); - *seq += strlen(buffer) - matchlen; return nf_nat_mangle_tcp_packet(pskb, ct, ctinfo, matchoff, matchlen, buffer, strlen(buffer)); } static int (*mangle[])(struct sk_buff **, __be32, u_int16_t, unsigned int, unsigned int, struct nf_conn *, - enum ip_conntrack_info, u32 *seq) + enum ip_conntrack_info) = { [NF_CT_FTP_PORT] = mangle_rfc959_packet, [NF_CT_FTP_PASV] = mangle_rfc959_packet, @@ -116,8 +110,7 @@ static unsigned int nf_nat_ftp(struct sk_buff **pskb, enum nf_ct_ftp_type type, unsigned int matchoff, unsigned int matchlen, - struct nf_conntrack_expect *exp, - u32 *seq) + struct nf_conntrack_expect *exp) { __be32 newip; u_int16_t port; @@ -145,8 +138,7 @@ static unsigned int nf_nat_ftp(struct sk_buff **pskb, if (port == 0) return NF_DROP; - if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo, - seq)) { + if (!mangle[type](pskb, newip, port, matchoff, matchlen, ct, ctinfo)) { nf_conntrack_unexpect_related(exp); return NF_DROP; } diff --git a/net/netfilter/nf_conntrack_ftp.c b/net/netfilter/nf_conntrack_ftp.c index 4bb669c7780f..82db2aa53bfc 100644 --- a/net/netfilter/nf_conntrack_ftp.c +++ b/net/netfilter/nf_conntrack_ftp.c @@ -48,8 +48,7 @@ unsigned int (*nf_nat_ftp_hook)(struct sk_buff **pskb, enum nf_ct_ftp_type type, unsigned int matchoff, unsigned int matchlen, - struct nf_conntrack_expect *exp, - u32 *seq); + struct nf_conntrack_expect *exp); EXPORT_SYMBOL_GPL(nf_nat_ftp_hook); #if 0 @@ -521,7 +520,7 @@ static int help(struct sk_buff **pskb, nf_nat_ftp = rcu_dereference(nf_nat_ftp_hook); if (nf_nat_ftp && ct->status & IPS_NAT_MASK) ret = nf_nat_ftp(pskb, ctinfo, search[dir][i].ftptype, - matchoff, matchlen, exp, &seq); + matchoff, matchlen, exp); else { /* Can't expect this? Best to drop packet now. */ if (nf_conntrack_expect_related(exp) != 0) -- cgit v1.2.3-55-g7522 From d052918688bdd7a1218aa5ae182013bf45a4881a Mon Sep 17 00:00:00 2001 From: Jing Min Zhao Date: Thu, 24 May 2007 16:42:26 -0700 Subject: [NETFILTER]: nf_conntrack_h323: fix ASN.1 types 1. Add support for decoding IPv6 address. I know it was manually added in the header file, but not in the template file. That wouldn't work. 2. Add missing support for decoding T.120 address in OLCA. 3. Remove unnecessary decoding of Information signal. Signed-off-by: Jing Min Zhao Signed-off-by: Patrick McHardy Signed-off-by: David S. Miller --- include/linux/netfilter/nf_conntrack_h323_types.h | 23 +++-------------- net/netfilter/nf_conntrack_h323_types.c | 31 ++++++++++------------- 2 files changed, 16 insertions(+), 38 deletions(-) (limited to 'include') diff --git a/include/linux/netfilter/nf_conntrack_h323_types.h b/include/linux/netfilter/nf_conntrack_h323_types.h index 38d74d5c9700..f35b6b4801e7 100644 --- a/include/linux/netfilter/nf_conntrack_h323_types.h +++ b/include/linux/netfilter/nf_conntrack_h323_types.h @@ -1,4 +1,4 @@ -/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 +/* Generated by Jing Min Zhao's ASN.1 parser, May 16 2007 * * Copyright (c) 2006 Jing Min Zhao * @@ -12,7 +12,7 @@ typedef struct TransportAddress_ipAddress { /* SEQUENCE */ typedef struct TransportAddress_ip6Address { /* SEQUENCE */ int options; /* No use */ - unsigned ip6; + unsigned ip; } TransportAddress_ip6Address; typedef struct TransportAddress { /* CHOICE */ @@ -364,23 +364,6 @@ typedef struct Alerting_UUIE { /* SEQUENCE */ Alerting_UUIE_fastStart fastStart; } Alerting_UUIE; -typedef struct Information_UUIE_fastStart { /* SEQUENCE OF */ - int count; - OpenLogicalChannel item[30]; -} Information_UUIE_fastStart; - -typedef struct Information_UUIE { /* SEQUENCE */ - enum { - eInformation_UUIE_callIdentifier = (1 << 31), - eInformation_UUIE_tokens = (1 << 30), - eInformation_UUIE_cryptoTokens = (1 << 29), - eInformation_UUIE_fastStart = (1 << 28), - eInformation_UUIE_fastConnectRefused = (1 << 27), - eInformation_UUIE_circuitInfo = (1 << 26), - } options; - Information_UUIE_fastStart fastStart; -} Information_UUIE; - typedef struct FacilityReason { /* CHOICE */ enum { eFacilityReason_routeCallToGatekeeper, @@ -471,7 +454,6 @@ typedef struct H323_UU_PDU_h323_message_body { /* CHOICE */ CallProceeding_UUIE callProceeding; Connect_UUIE connect; Alerting_UUIE alerting; - Information_UUIE information; Facility_UUIE facility; Progress_UUIE progress; }; @@ -561,6 +543,7 @@ typedef struct OpenLogicalChannelAck { /* SEQUENCE */ } options; OpenLogicalChannelAck_reverseLogicalChannelParameters reverseLogicalChannelParameters; + NetworkAccessParameters separateStack; OpenLogicalChannelAck_forwardMultiplexAckParameters forwardMultiplexAckParameters; } OpenLogicalChannelAck; diff --git a/net/netfilter/nf_conntrack_h323_types.c b/net/netfilter/nf_conntrack_h323_types.c index 4c6f8b3b1208..3a21fdf1a265 100644 --- a/net/netfilter/nf_conntrack_h323_types.c +++ b/net/netfilter/nf_conntrack_h323_types.c @@ -1,4 +1,4 @@ -/* Generated by Jing Min Zhao's ASN.1 parser, Apr 20 2006 +/* Generated by Jing Min Zhao's ASN.1 parser, May 16 2007 * * Copyright (c) 2006 Jing Min Zhao * @@ -37,7 +37,7 @@ static field_t _TransportAddress_ipxAddress[] = { /* SEQUENCE */ static field_t _TransportAddress_ip6Address[] = { /* SEQUENCE */ {FNAME("ip") OCTSTR, FIXD, 16, 0, DECODE, - offsetof(TransportAddress_ip6Address, ip6), NULL}, + offsetof(TransportAddress_ip6Address, ip), NULL}, {FNAME("port") INT, WORD, 0, 0, SKIP, 0, NULL}, }; @@ -67,7 +67,8 @@ static field_t _TransportAddress[] = { /* CHOICE */ {FNAME("ipxAddress") SEQ, 0, 3, 3, SKIP, 0, _TransportAddress_ipxAddress}, {FNAME("ip6Address") SEQ, 0, 2, 2, DECODE | EXT, - offsetof(TransportAddress, ip6Address), _TransportAddress_ip6Address}, + offsetof(TransportAddress, ip6Address), + _TransportAddress_ip6Address}, {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, {FNAME("nsap") OCTSTR, 5, 1, 0, SKIP, 0, NULL}, {FNAME("nonStandardAddress") SEQ, 0, 2, 2, SKIP, 0, @@ -638,7 +639,8 @@ static field_t _UnicastAddress_iPXAddress[] = { /* SEQUENCE */ }; static field_t _UnicastAddress_iP6Address[] = { /* SEQUENCE */ - {FNAME("network") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, + {FNAME("network") OCTSTR, FIXD, 16, 0, DECODE, + offsetof(UnicastAddress_iP6Address, network), NULL}, {FNAME("tsapIdentifier") INT, WORD, 0, 0, SKIP, 0, NULL}, }; @@ -665,8 +667,8 @@ static field_t _UnicastAddress[] = { /* CHOICE */ offsetof(UnicastAddress, iPAddress), _UnicastAddress_iPAddress}, {FNAME("iPXAddress") SEQ, 0, 3, 3, SKIP | EXT, 0, _UnicastAddress_iPXAddress}, - {FNAME("iP6Address") SEQ, 0, 2, 2, SKIP | EXT, 0, - _UnicastAddress_iP6Address}, + {FNAME("iP6Address") SEQ, 0, 2, 2, DECODE | EXT, + offsetof(UnicastAddress, iP6Address), _UnicastAddress_iP6Address}, {FNAME("netBios") OCTSTR, FIXD, 16, 0, SKIP, 0, NULL}, {FNAME("iPSourceRouteAddress") SEQ, 0, 4, 4, SKIP | EXT, 0, _UnicastAddress_iPSourceRouteAddress}, @@ -984,19 +986,12 @@ static field_t _Alerting_UUIE[] = { /* SEQUENCE */ {FNAME("featureSet") SEQ, 3, 4, 4, SKIP | EXT | OPT, 0, NULL}, }; -static field_t _Information_UUIE_fastStart[] = { /* SEQUENCE OF */ - {FNAME("item") SEQ, 1, 3, 5, DECODE | OPEN | EXT, - sizeof(OpenLogicalChannel), _OpenLogicalChannel} - , -}; - static field_t _Information_UUIE[] = { /* SEQUENCE */ {FNAME("protocolIdentifier") OID, BYTE, 0, 0, SKIP, 0, NULL}, {FNAME("callIdentifier") SEQ, 0, 1, 1, SKIP | EXT, 0, NULL}, {FNAME("tokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, {FNAME("cryptoTokens") SEQOF, SEMI, 0, 0, SKIP | OPT, 0, NULL}, - {FNAME("fastStart") SEQOF, SEMI, 0, 30, DECODE | OPT, - offsetof(Information_UUIE, fastStart), _Information_UUIE_fastStart}, + {FNAME("fastStart") SEQOF, SEMI, 0, 30, SKIP | OPT, 0, NULL}, {FNAME("fastConnectRefused") NUL, FIXD, 0, 0, SKIP | OPT, 0, NULL}, {FNAME("circuitInfo") SEQ, 3, 3, 3, SKIP | EXT | OPT, 0, NULL}, }; @@ -1343,9 +1338,7 @@ static field_t _H323_UU_PDU_h323_message_body[] = { /* CHOICE */ offsetof(H323_UU_PDU_h323_message_body, connect), _Connect_UUIE}, {FNAME("alerting") SEQ, 1, 3, 17, DECODE | EXT, offsetof(H323_UU_PDU_h323_message_body, alerting), _Alerting_UUIE}, - {FNAME("information") SEQ, 0, 1, 7, DECODE | EXT, - offsetof(H323_UU_PDU_h323_message_body, information), - _Information_UUIE}, + {FNAME("information") SEQ, 0, 1, 7, SKIP | EXT, 0, _Information_UUIE}, {FNAME("releaseComplete") SEQ, 1, 2, 11, SKIP | EXT, 0, _ReleaseComplete_UUIE}, {FNAME("facility") SEQ, 3, 5, 21, DECODE | EXT, @@ -1430,7 +1423,9 @@ static field_t _OpenLogicalChannelAck[] = { /* SEQUENCE */ DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, reverseLogicalChannelParameters), _OpenLogicalChannelAck_reverseLogicalChannelParameters}, - {FNAME("separateStack") SEQ, 2, 4, 5, SKIP | EXT | OPT, 0, NULL}, + {FNAME("separateStack") SEQ, 2, 4, 5, DECODE | EXT | OPT, + offsetof(OpenLogicalChannelAck, separateStack), + _NetworkAccessParameters}, {FNAME("forwardMultiplexAckParameters") CHOICE, 0, 1, 1, DECODE | EXT | OPT, offsetof(OpenLogicalChannelAck, forwardMultiplexAckParameters), -- cgit v1.2.3-55-g7522 From 14e50e57aedb2a89cf79b77782879769794cab7b Mon Sep 17 00:00:00 2001 From: David S. Miller Date: Thu, 24 May 2007 18:17:54 -0700 Subject: [XFRM]: Allow packet drops during larval state resolution. The current IPSEC rule resolution behavior we have does not work for a lot of people, even though technically it's an improvement from the -EAGAIN buisness we had before. Right now we'll block until the key manager resolves the route. That works for simple cases, but many folks would rather packets get silently dropped until the key manager resolves the IPSEC rules. We can't tell these folks to "set the socket non-blocking" because they don't have control over the non-block setting of things like the sockets used to resolve DNS deep inside of the resolver libraries in libc. With that in mind I coded up the patch below with some help from Herbert Xu which provides packet-drop behavior during larval state resolution, controllable via sysctl and off by default. This lays the framework to either: 1) Make this default at some point or... 2) Move this logic into xfrm{4,6}_policy.c and implement the ARP-like resolution queue we've all been dreaming of. The idea would be to queue packets to the policy, then once the larval state is resolved by the key manager we re-resolve the route and push the packets out. The packets would timeout if the rule didn't get resolved in a certain amount of time. Signed-off-by: David S. Miller --- include/net/dst.h | 7 +++++ include/net/ipv6.h | 3 ++ net/core/sysctl_net_core.c | 9 ++++++ net/dccp/ipv6.c | 10 +++++-- net/ipv4/route.c | 71 +++++++++++++++++++++++++++++++++++++++++++++- net/ipv6/datagram.c | 8 ++++-- net/ipv6/raw.c | 8 ++++-- net/ipv6/route.c | 63 ++++++++++++++++++++++++++++++++++++++++ net/ipv6/tcp_ipv6.c | 8 ++++-- net/ipv6/udp.c | 8 ++++-- net/xfrm/xfrm_policy.c | 28 ++++++++++++++++-- 11 files changed, 209 insertions(+), 14 deletions(-) (limited to 'include') diff --git a/include/net/dst.h b/include/net/dst.h index e12a8ce0b9b3..82270f9332db 100644 --- a/include/net/dst.h +++ b/include/net/dst.h @@ -265,9 +265,16 @@ static inline int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, { return 0; } +static inline int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, + struct sock *sk, int flags) +{ + return 0; +} #else extern int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, struct sock *sk, int flags); +extern int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, + struct sock *sk, int flags); #endif #endif diff --git a/include/net/ipv6.h b/include/net/ipv6.h index 4fa5dfe886c4..78a0d06d98d5 100644 --- a/include/net/ipv6.h +++ b/include/net/ipv6.h @@ -469,6 +469,9 @@ extern void ip6_flush_pending_frames(struct sock *sk); extern int ip6_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl); +extern int ip6_dst_blackhole(struct sock *sk, + struct dst_entry **dst, + struct flowi *fl); extern int ip6_sk_dst_lookup(struct sock *sk, struct dst_entry **dst, struct flowi *fl); diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c index b29712033dd4..f34aca041a25 100644 --- a/net/core/sysctl_net_core.c +++ b/net/core/sysctl_net_core.c @@ -24,6 +24,7 @@ extern int sysctl_core_destroy_delay; #ifdef CONFIG_XFRM extern u32 sysctl_xfrm_aevent_etime; extern u32 sysctl_xfrm_aevent_rseqth; +extern int sysctl_xfrm_larval_drop; #endif ctl_table core_table[] = { @@ -118,6 +119,14 @@ ctl_table core_table[] = { .mode = 0644, .proc_handler = &proc_dointvec }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "xfrm_larval_drop", + .data = &sysctl_xfrm_larval_drop, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec + }, #endif /* CONFIG_XFRM */ #endif /* CONFIG_NET */ { diff --git a/net/dccp/ipv6.c b/net/dccp/ipv6.c index 64eac2515aa2..31737cdf156a 100644 --- a/net/dccp/ipv6.c +++ b/net/dccp/ipv6.c @@ -1043,9 +1043,13 @@ static int dccp_v6_connect(struct sock *sk, struct sockaddr *uaddr, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - err = xfrm_lookup(&dst, &fl, sk, 1); - if (err < 0) - goto failure; + err = __xfrm_lookup(&dst, &fl, sk, 1); + if (err < 0) { + if (err == -EREMOTE) + err = ip6_dst_blackhole(sk, &dst, &fl); + if (err < 0) + goto failure; + } if (saddr == NULL) { saddr = &fl.fl6_src; diff --git a/net/ipv4/route.c b/net/ipv4/route.c index df9fe4f2e8cc..8603cfb271f2 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c @@ -2598,6 +2598,69 @@ int __ip_route_output_key(struct rtable **rp, const struct flowi *flp) EXPORT_SYMBOL_GPL(__ip_route_output_key); +static void ipv4_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) +{ +} + +static struct dst_ops ipv4_dst_blackhole_ops = { + .family = AF_INET, + .protocol = __constant_htons(ETH_P_IP), + .destroy = ipv4_dst_destroy, + .check = ipv4_dst_check, + .update_pmtu = ipv4_rt_blackhole_update_pmtu, + .entry_size = sizeof(struct rtable), +}; + + +static int ipv4_blackhole_output(struct sk_buff *skb) +{ + kfree_skb(skb); + return 0; +} + +static int ipv4_dst_blackhole(struct rtable **rp, struct flowi *flp, struct sock *sk) +{ + struct rtable *ort = *rp; + struct rtable *rt = (struct rtable *) + dst_alloc(&ipv4_dst_blackhole_ops); + + if (rt) { + struct dst_entry *new = &rt->u.dst; + + atomic_set(&new->__refcnt, 1); + new->__use = 1; + new->input = ipv4_blackhole_output; + new->output = ipv4_blackhole_output; + memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32)); + + new->dev = ort->u.dst.dev; + if (new->dev) + dev_hold(new->dev); + + rt->fl = ort->fl; + + rt->idev = ort->idev; + if (rt->idev) + in_dev_hold(rt->idev); + rt->rt_flags = ort->rt_flags; + rt->rt_type = ort->rt_type; + rt->rt_dst = ort->rt_dst; + rt->rt_src = ort->rt_src; + rt->rt_iif = ort->rt_iif; + rt->rt_gateway = ort->rt_gateway; + rt->rt_spec_dst = ort->rt_spec_dst; + rt->peer = ort->peer; + if (rt->peer) + atomic_inc(&rt->peer->refcnt); + + dst_free(new); + } + + dst_release(&(*rp)->u.dst); + *rp = rt; + return (rt ? 0 : -ENOMEM); +} + int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags) { int err; @@ -2610,7 +2673,11 @@ int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, flp->fl4_src = (*rp)->rt_src; if (!flp->fl4_dst) flp->fl4_dst = (*rp)->rt_dst; - return xfrm_lookup((struct dst_entry **)rp, flp, sk, flags); + err = __xfrm_lookup((struct dst_entry **)rp, flp, sk, flags); + if (err == -EREMOTE) + err = ipv4_dst_blackhole(rp, flp, sk); + + return err; } return 0; @@ -3139,6 +3206,8 @@ int __init ip_rt_init(void) kmem_cache_create("ip_dst_cache", sizeof(struct rtable), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + ipv4_dst_blackhole_ops.kmem_cachep = ipv4_dst_ops.kmem_cachep; + rt_hash_table = (struct rt_hash_bucket *) alloc_large_system_hash("IP route cache", sizeof(struct rt_hash_bucket), diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c index 403eee66b9c5..b1fe7ac5dc90 100644 --- a/net/ipv6/datagram.c +++ b/net/ipv6/datagram.c @@ -177,8 +177,12 @@ ipv4_connected: if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) - goto out; + if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { + if (err == -EREMOTE) + err = ip6_dst_blackhole(sk, &dst, &fl); + if (err < 0) + goto out; + } /* source address lookup done in ip6_dst_lookup */ diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c index 009a1047fc3f..a58459a76684 100644 --- a/net/ipv6/raw.c +++ b/net/ipv6/raw.c @@ -818,8 +818,12 @@ static int rawv6_sendmsg(struct kiocb *iocb, struct sock *sk, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) - goto out; + if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { + if (err == -EREMOTE) + err = ip6_dst_blackhole(sk, &dst, &fl); + if (err < 0) + goto out; + } if (hlimit < 0) { if (ipv6_addr_is_multicast(&fl.fl6_dst)) diff --git a/net/ipv6/route.c b/net/ipv6/route.c index b46ad53044ba..1324b06796c0 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c @@ -119,6 +119,19 @@ static struct dst_ops ip6_dst_ops = { .entry_size = sizeof(struct rt6_info), }; +static void ip6_rt_blackhole_update_pmtu(struct dst_entry *dst, u32 mtu) +{ +} + +static struct dst_ops ip6_dst_blackhole_ops = { + .family = AF_INET6, + .protocol = __constant_htons(ETH_P_IPV6), + .destroy = ip6_dst_destroy, + .check = ip6_dst_check, + .update_pmtu = ip6_rt_blackhole_update_pmtu, + .entry_size = sizeof(struct rt6_info), +}; + struct rt6_info ip6_null_entry = { .u = { .dst = { @@ -833,6 +846,54 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl) EXPORT_SYMBOL(ip6_route_output); +static int ip6_blackhole_output(struct sk_buff *skb) +{ + kfree_skb(skb); + return 0; +} + +int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl) +{ + struct rt6_info *ort = (struct rt6_info *) *dstp; + struct rt6_info *rt = (struct rt6_info *) + dst_alloc(&ip6_dst_blackhole_ops); + struct dst_entry *new = NULL; + + if (rt) { + new = &rt->u.dst; + + atomic_set(&new->__refcnt, 1); + new->__use = 1; + new->input = ip6_blackhole_output; + new->output = ip6_blackhole_output; + + memcpy(new->metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32)); + new->dev = ort->u.dst.dev; + if (new->dev) + dev_hold(new->dev); + rt->rt6i_idev = ort->rt6i_idev; + if (rt->rt6i_idev) + in6_dev_hold(rt->rt6i_idev); + rt->rt6i_expires = 0; + + ipv6_addr_copy(&rt->rt6i_gateway, &ort->rt6i_gateway); + rt->rt6i_flags = ort->rt6i_flags & ~RTF_EXPIRES; + rt->rt6i_metric = 0; + + memcpy(&rt->rt6i_dst, &ort->rt6i_dst, sizeof(struct rt6key)); +#ifdef CONFIG_IPV6_SUBTREES + memcpy(&rt->rt6i_src, &ort->rt6i_src, sizeof(struct rt6key)); +#endif + + dst_free(new); + } + + dst_release(*dstp); + *dstp = new; + return (new ? 0 : -ENOMEM); +} +EXPORT_SYMBOL_GPL(ip6_dst_blackhole); + /* * Destination cache support functions */ @@ -2495,6 +2556,8 @@ void __init ip6_route_init(void) ip6_dst_ops.kmem_cachep = kmem_cache_create("ip6_dst_cache", sizeof(struct rt6_info), 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL, NULL); + ip6_dst_blackhole_ops.kmem_cachep = ip6_dst_ops.kmem_cachep; + fib6_init(); #ifdef CONFIG_PROC_FS p = proc_net_create("ipv6_route", 0, rt6_proc_info); diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index e2f25ea43b68..4f06a51ad4fd 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -265,8 +265,12 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr, if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) - goto failure; + if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { + if (err == -EREMOTE) + err = ip6_dst_blackhole(sk, &dst, &fl); + if (err < 0) + goto failure; + } if (saddr == NULL) { saddr = &fl.fl6_src; diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index a7ae59c954d5..d1fbddd172e7 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -767,8 +767,12 @@ do_udp_sendmsg: if (final_p) ipv6_addr_copy(&fl.fl6_dst, final_p); - if ((err = xfrm_lookup(&dst, &fl, sk, 1)) < 0) - goto out; + if ((err = __xfrm_lookup(&dst, &fl, sk, 1)) < 0) { + if (err == -EREMOTE) + err = ip6_dst_blackhole(sk, &dst, &fl); + if (err < 0) + goto out; + } if (hlimit < 0) { if (ipv6_addr_is_multicast(&fl.fl6_dst)) diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index d0882e53b6fc..b8bab89616a0 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c @@ -29,6 +29,8 @@ #include "xfrm_hash.h" +int sysctl_xfrm_larval_drop; + DEFINE_MUTEX(xfrm_cfg_mutex); EXPORT_SYMBOL(xfrm_cfg_mutex); @@ -1390,8 +1392,8 @@ static int stale_bundle(struct dst_entry *dst); * At the moment we eat a raw IP route. Mostly to speed up lookups * on interfaces with disabled IPsec. */ -int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, - struct sock *sk, int flags) +int __xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, + struct sock *sk, int flags) { struct xfrm_policy *policy; struct xfrm_policy *pols[XFRM_POLICY_TYPE_MAX]; @@ -1509,6 +1511,13 @@ restart: if (unlikely(nx<0)) { err = nx; + if (err == -EAGAIN && sysctl_xfrm_larval_drop) { + /* EREMOTE tells the caller to generate + * a one-shot blackhole route. + */ + xfrm_pol_put(policy); + return -EREMOTE; + } if (err == -EAGAIN && flags) { DECLARE_WAITQUEUE(wait, current); @@ -1598,6 +1607,21 @@ error: *dst_p = NULL; return err; } +EXPORT_SYMBOL(__xfrm_lookup); + +int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, + struct sock *sk, int flags) +{ + int err = __xfrm_lookup(dst_p, fl, sk, flags); + + if (err == -EREMOTE) { + dst_release(*dst_p); + *dst_p = NULL; + err = -EAGAIN; + } + + return err; +} EXPORT_SYMBOL(xfrm_lookup); static inline int -- cgit v1.2.3-55-g7522