summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexey Kuznetsov <kuznet@ms2.inr.ac.ru>2002-11-04 15:18:11 -0800
committerDavid S. Miller <davem@nuts.ninka.net>2002-11-04 15:18:11 -0800
commitfefd92463dfde738bce403acf35ff05cac4dc6a0 (patch)
treee46506bd7109d08aff73b401528566af3ea7b973
parentb9346730a75d99030d15d041c2c4719780361f9f (diff)
[IPSEC]: Bug fixes and updates.
- Implement IP_IPSEC_POLICY setsockopt - Rework input policy checks to use it - dst->child destruction is repaired - Fix tunnel mode IP header building.
-rw-r--r--include/linux/in.h1
-rw-r--r--include/linux/ipsec.h11
-rw-r--r--include/net/dst.h10
-rw-r--r--include/net/protocol.h1
-rw-r--r--include/net/route.h1
-rw-r--r--include/net/sock.h1
-rw-r--r--include/net/xfrm.h15
-rw-r--r--net/core/dst.c55
-rw-r--r--net/ipv4/Kconfig4
-rw-r--r--net/ipv4/af_inet.c2
-rw-r--r--net/ipv4/ah.c8
-rw-r--r--net/ipv4/esp.c36
-rw-r--r--net/ipv4/ip_forward.c2
-rw-r--r--net/ipv4/ip_input.c26
-rw-r--r--net/ipv4/ip_output.c6
-rw-r--r--net/ipv4/ip_sockglue.c5
-rw-r--r--net/ipv4/raw.c8
-rw-r--r--net/ipv4/route.c9
-rw-r--r--net/ipv4/tcp_ipv4.c18
-rw-r--r--net/ipv4/udp.c11
-rw-r--r--net/ipv4/xfrm_input.c6
-rw-r--r--net/ipv4/xfrm_policy.c102
-rw-r--r--net/ipv4/xfrm_state.c37
-rw-r--r--net/ipv6/route.c6
-rw-r--r--net/ipv6/tcp_ipv6.c2
-rw-r--r--net/key/af_key.c103
-rw-r--r--net/netsyms.c1
27 files changed, 331 insertions, 156 deletions
diff --git a/include/linux/in.h b/include/linux/in.h
index eebfb0306d1b..edea83ecf432 100644
--- a/include/linux/in.h
+++ b/include/linux/in.h
@@ -69,6 +69,7 @@ struct in_addr {
#define IP_RECVTOS 13
#define IP_MTU 14
#define IP_FREEBIND 15
+#define IP_IPSEC_POLICY 16
/* BSD compatibility */
#define IP_RECVRETOPTS IP_RETOPTS
diff --git a/include/linux/ipsec.h b/include/linux/ipsec.h
index ae132602002a..d3c527616b5e 100644
--- a/include/linux/ipsec.h
+++ b/include/linux/ipsec.h
@@ -43,15 +43,4 @@ enum {
#define IPSEC_REPLAYWSIZE 32
-#ifdef __KERNEL__
-struct sock;
-struct sk_buff;
-
-static __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
-{
- return 1;
-}
-#endif
-
-
#endif /* _LINUX_IPSEC_H */
diff --git a/include/net/dst.h b/include/net/dst.h
index 935fba293f31..c25cdac635ed 100644
--- a/include/net/dst.h
+++ b/include/net/dst.h
@@ -44,6 +44,7 @@ struct dst_entry
#define DST_HOST 1
#define DST_NOXFRM 2
#define DST_NOPOLICY 4
+#define DST_NOHASH 8
unsigned long lastuse;
unsigned long expires;
@@ -138,8 +139,15 @@ struct dst_entry * dst_clone(struct dst_entry * dst)
static inline
void dst_release(struct dst_entry * dst)
{
- if (dst)
+ if (dst) {
+ if (atomic_read(&dst->__refcnt) < 1) {
+ __label__ __lbl;
+ printk("BUG: dst underflow %d: %p\n",
+ atomic_read(&dst->__refcnt), &&__lbl);
+__lbl:
+ }
atomic_dec(&dst->__refcnt);
+ }
}
/* Children define the path of the packet through the
diff --git a/include/net/protocol.h b/include/net/protocol.h
index 9ba874a3d18f..2063dfd55690 100644
--- a/include/net/protocol.h
+++ b/include/net/protocol.h
@@ -38,6 +38,7 @@ struct inet_protocol
{
int (*handler)(struct sk_buff *skb);
void (*err_handler)(struct sk_buff *skb, u32 info);
+ int no_policy;
};
#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
diff --git a/include/net/route.h b/include/net/route.h
index 6987a321075d..ad37024a0154 100644
--- a/include/net/route.h
+++ b/include/net/route.h
@@ -114,6 +114,7 @@ extern void ip_rt_advice(struct rtable **rp, int advice);
extern void rt_cache_flush(int how);
extern int __ip_route_output_key(struct rtable **, const struct flowi *flp);
extern int ip_route_output_key(struct rtable **, struct flowi *flp);
+extern int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags);
extern int ip_route_input(struct sk_buff*, u32 dst, u32 src, u8 tos, struct net_device *devin);
extern unsigned short ip_rt_frag_needed(struct iphdr *iph, unsigned short new_mtu);
extern void ip_rt_send_redirect(struct sk_buff *skb);
diff --git a/include/net/sock.h b/include/net/sock.h
index 4a4094b93d07..da4e817da7a7 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -110,6 +110,7 @@ struct sock {
wait_queue_head_t *sleep; /* Sock wait queue */
struct dst_entry *dst_cache; /* Destination cache */
rwlock_t dst_lock;
+ struct xfrm_policy *policy[2];
atomic_t rmem_alloc; /* Receive queue bytes committed */
struct sk_buff_head receive_queue; /* Incoming packets */
atomic_t wmem_alloc; /* Transmit queue bytes committed */
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 1d663c6839a6..2961e6616b7f 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -312,6 +312,7 @@ struct xfrm_mgr
char *id;
int (*notify)(struct xfrm_state *x, int event);
int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir);
+ struct xfrm_policy *(*compile_policy)(int opt, u8 *data, int len, int *dir);
};
extern int xfrm_register_km(struct xfrm_mgr *km);
@@ -397,13 +398,16 @@ secpath_put(struct sec_path *sp)
__secpath_destroy(sp);
}
-extern int __xfrm_policy_check(int dir, struct sk_buff *skb);
+extern int __xfrm_policy_check(struct sock *, int dir, struct sk_buff *skb);
-static inline int xfrm_policy_check(int dir, struct sk_buff *skb)
+static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb)
{
+ if (sk && sk->policy[XFRM_POLICY_IN])
+ return __xfrm_policy_check(sk, dir, skb);
+
return !xfrm_policy_list[dir] ||
(skb->dst->flags & DST_NOPOLICY) ||
- __xfrm_policy_check(dir, skb);
+ __xfrm_policy_check(sk, dir, skb);
}
extern int __xfrm_route_forward(struct sk_buff *skb);
@@ -431,6 +435,7 @@ extern int xfrm_replay_check(struct xfrm_state *x, u32 seq);
extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq);
extern int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl);
extern int xfrm4_rcv(struct sk_buff *skb);
+extern int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen);
struct xfrm_policy *xfrm_policy_alloc(void);
extern int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), void *);
@@ -439,12 +444,12 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
struct xfrm_policy *xfrm_policy_delete(int dir, struct xfrm_selector *sel);
struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete);
void xfrm_policy_flush(void);
-int xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm,
- struct flowi *fl, struct dst_entry **dst_p);
void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
struct xfrm_state * xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr);
extern void xfrm_policy_flush(void);
extern void xfrm_policy_kill(struct xfrm_policy *);
+extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
+extern struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl);
extern wait_queue_head_t *km_waitq;
extern void km_warn_expired(struct xfrm_state *x);
diff --git a/net/core/dst.c b/net/core/dst.c
index 398463b6b6bb..a566cbe03eeb 100644
--- a/net/core/dst.c
+++ b/net/core/dst.c
@@ -36,6 +36,7 @@ static spinlock_t dst_lock = SPIN_LOCK_UNLOCKED;
static unsigned long dst_gc_timer_expires;
static unsigned long dst_gc_timer_inc = DST_GC_MAX;
static void dst_run_gc(unsigned long);
+static void ___dst_free(struct dst_entry * dst);
static struct timer_list dst_gc_timer =
{ data: DST_GC_MIN, function: dst_run_gc };
@@ -59,12 +60,26 @@ static void dst_run_gc(unsigned long dummy)
delayed++;
continue;
}
- if (dst->child) {
- dst->child->next = dst->next;
- *dstp = dst->child;
- } else
- *dstp = dst->next;
- dst_destroy(dst);
+ *dstp = dst->next;
+
+ dst = dst_destroy(dst);
+ if (dst) {
+ /* NOHASH and still referenced. Unless it is already
+ * on gc list, invalidate it and add to gc list.
+ *
+ * Note: this is temporary. Actually, NOHASH dst's
+ * must be obsoleted when parent is obsoleted.
+ * But we do not have state "obsoleted, but
+ * referenced by parent", so it is right.
+ */
+ if (dst->obsolete > 1)
+ continue;
+
+ ___dst_free(dst);
+ dst->next = *dstp;
+ *dstp = dst;
+ dstp = &dst->next;
+ }
}
if (!dst_garbage_list) {
dst_gc_timer_inc = DST_GC_MAX;
@@ -120,10 +135,8 @@ void * dst_alloc(struct dst_ops * ops)
return dst;
}
-void __dst_free(struct dst_entry * dst)
+static void ___dst_free(struct dst_entry * dst)
{
- spin_lock_bh(&dst_lock);
-
/* The first case (dev==NULL) is required, when
protocol module is unloaded.
*/
@@ -132,6 +145,12 @@ void __dst_free(struct dst_entry * dst)
dst->output = dst_blackhole;
}
dst->obsolete = 2;
+}
+
+void __dst_free(struct dst_entry * dst)
+{
+ spin_lock_bh(&dst_lock);
+ ___dst_free(dst);
dst->next = dst_garbage_list;
dst_garbage_list = dst;
if (dst_gc_timer_inc > DST_GC_INC) {
@@ -141,7 +160,6 @@ void __dst_free(struct dst_entry * dst)
dst_gc_timer.expires = jiffies + dst_gc_timer_expires;
add_timer(&dst_gc_timer);
}
-
spin_unlock_bh(&dst_lock);
}
@@ -177,10 +195,19 @@ again:
kmem_cache_free(dst->ops->kmem_cachep, dst);
dst = child;
- if (dst && !atomic_read(&dst->__refcnt))
- goto again;
-
- return dst;
+ if (dst) {
+ if (atomic_dec_and_test(&dst->__refcnt)) {
+ /* We were real parent of this dst, so kill child. */
+ if (dst->flags&DST_NOHASH)
+ goto again;
+ } else {
+ /* Child is still referenced, return it for freeing. */
+ if (dst->flags&DST_NOHASH)
+ return dst;
+ /* Child is still in his hash table */
+ }
+ }
+ return NULL;
}
static int dst_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 4d5c8464b120..e8f334059cdd 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -349,14 +349,14 @@ config SYN_COOKIES
If unsure, say N.
config INET_AH
- bool "IP: AH transformation"
+ tristate "IP: AH transformation"
---help---
Support for IPsec AH.
If unsure, say Y.
config INET_ESP
- bool "IP: ESP transformation"
+ tristate "IP: ESP transformation"
---help---
Support for IPsec ESP.
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index 41909c8b507f..bdce83a90c6e 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1038,11 +1038,13 @@ static struct inet_protocol igmp_protocol = {
static struct inet_protocol tcp_protocol = {
.handler = tcp_v4_rcv,
.err_handler = tcp_v4_err,
+ .no_policy = 1,
};
static struct inet_protocol udp_protocol = {
.handler = udp_rcv,
.err_handler = udp_err,
+ .no_policy = 1,
};
static struct inet_protocol icmp_protocol = {
diff --git a/net/ipv4/ah.c b/net/ipv4/ah.c
index 57fe5d443ee9..178baf73bac2 100644
--- a/net/ipv4/ah.c
+++ b/net/ipv4/ah.c
@@ -176,12 +176,13 @@ int ah_output(struct sk_buff *skb)
iph = skb->nh.iph;
if (x->props.mode) {
top_iph = (struct iphdr*)skb_push(skb, x->props.header_len);
- top_iph->ihl = 4;
- top_iph->version = 5;
+ top_iph->ihl = 5;
+ top_iph->version = 4;
top_iph->tos = 0;
top_iph->tot_len = htons(skb->len);
- top_iph->id = inet_getid(((struct rtable*)dst)->peer, 0);
top_iph->frag_off = 0;
+ if (!(iph->frag_off&htons(IP_DF)))
+ __ip_select_ident(top_iph, dst, 0);
top_iph->ttl = 0;
top_iph->protocol = IPPROTO_AH;
top_iph->check = 0;
@@ -379,6 +380,7 @@ static struct xfrm_type ah_type =
static struct inet_protocol ah4_protocol = {
.handler = xfrm4_rcv,
.err_handler = ah4_err,
+ .no_policy = 1,
};
int __init ah4_init(void)
diff --git a/net/ipv4/esp.c b/net/ipv4/esp.c
index cbaf651e8b51..509e88df29cc 100644
--- a/net/ipv4/esp.c
+++ b/net/ipv4/esp.c
@@ -187,33 +187,13 @@ esp_hmac_digest(struct esp_data *esp, struct sk_buff *skb, int offset,
int len, u8 *auth_data)
{
struct crypto_tfm *tfm = esp->auth.tfm;
- int i;
- char tmp_digest[crypto_tfm_alg_digestsize(tfm)];
- char pad[crypto_tfm_alg_blocksize(tfm)];
+ char digest[crypto_tfm_alg_digestsize(tfm)];
memset(auth_data, 0, esp->auth.authlen);
-
- memset(pad, 0, sizeof(pad));
- memcpy(pad, esp->auth.key, esp->auth.key_len);
- for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
- pad[i] ^= 0x36;
-
- crypto_digest_init(tfm);
- tfm->__crt_alg->cra_digest.dia_update(tfm->crt_ctx, pad, sizeof(pad));
+ crypto_hmac_init(tfm, esp->auth.key, &esp->auth.key_len);
skb_digest_walk(skb, tfm, offset, len);
- tfm->__crt_alg->cra_digest.dia_update(tfm->crt_ctx, skb->data+offset, len);
- crypto_digest_final(tfm, tmp_digest);
-
- memset(pad, 0, sizeof(pad));
- memcpy(pad, esp->auth.key, esp->auth.key_len);
-
- for (i = 0; i < crypto_tfm_alg_blocksize(tfm); i++)
- pad[i] ^= 0x5c;
-
- crypto_digest_init(tfm);
- tfm->__crt_alg->cra_digest.dia_update(tfm->crt_ctx, pad, sizeof(pad));
- tfm->__crt_alg->cra_digest.dia_update(tfm->crt_ctx, tmp_digest, crypto_tfm_alg_digestsize(tfm));
- crypto_digest_final(tfm, auth_data);
+ crypto_hmac_final(tfm, esp->auth.key, &esp->auth.key_len, digest);
+ memcpy(auth_data, digest, crypto_tfm_alg_digestsize(tfm));
}
/* Check that skb data bits are writable. If they are not, copy data
@@ -390,12 +370,13 @@ int esp_output(struct sk_buff *skb)
top_iph = (struct iphdr*)skb_push(skb, x->props.header_len);
esph = (struct ip_esp_hdr*)(top_iph+1);
*(u8*)(trailer->tail - 1) = IPPROTO_IP;
- top_iph->ihl = 4;
- top_iph->version = 5;
+ top_iph->ihl = 5;
+ top_iph->version = 4;
top_iph->tos = iph->tos; /* DS disclosed */
top_iph->tot_len = htons(skb->len + esp->auth.authlen);
- top_iph->id = inet_getid(((struct rtable*)dst)->peer, 0);
top_iph->frag_off = iph->frag_off&htons(IP_DF);
+ if (!(top_iph->frag_off))
+ ip_select_ident(top_iph, dst, 0);
top_iph->ttl = iph->ttl; /* TTL disclosed */
top_iph->protocol = IPPROTO_ESP;
top_iph->check = 0;
@@ -668,6 +649,7 @@ static struct xfrm_type esp_type =
static struct inet_protocol esp4_protocol = {
.handler = xfrm4_rcv,
.err_handler = esp4_err,
+ .no_policy = 1,
};
int __init esp4_init(void)
diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c
index 1b1ce0a33507..f9fa6a1cefcc 100644
--- a/net/ipv4/ip_forward.c
+++ b/net/ipv4/ip_forward.c
@@ -60,7 +60,7 @@ int ip_forward(struct sk_buff *skb)
struct rtable *rt; /* Route we use */
struct ip_options * opt = &(IPCB(skb)->opt);
- if (!xfrm_policy_check(XFRM_POLICY_FWD, skb))
+ if (!xfrm_policy_check(NULL, XFRM_POLICY_FWD, skb))
goto drop;
if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 4d63141e8edb..6c67950d4b4b 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -223,15 +223,6 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
struct inet_protocol *ipprot;
resubmit:
-
- /* Fuck... This IS ugly. */
- if (protocol != IPPROTO_AH &&
- protocol != IPPROTO_ESP &&
- !xfrm_policy_check(XFRM_POLICY_IN, skb)) {
- kfree_skb(skb);
- return 0;
- }
-
hash = protocol & (MAX_INET_PROTOS - 1);
raw_sk = raw_v4_htable[hash];
@@ -242,7 +233,14 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
raw_v4_input(skb, skb->nh.iph, hash);
if ((ipprot = inet_protos[hash]) != NULL) {
- int ret = ipprot->handler(skb);
+ int ret;
+
+ if (!ipprot->no_policy &&
+ !xfrm_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+ kfree_skb(skb);
+ return 0;
+ }
+ ret = ipprot->handler(skb);
if (ret < 0) {
protocol = -ret;
goto resubmit;
@@ -250,9 +248,11 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
IP_INC_STATS_BH(IpInDelivers);
} else {
if (!raw_sk) {
- IP_INC_STATS_BH(IpInUnknownProtos);
- icmp_send(skb, ICMP_DEST_UNREACH,
- ICMP_PROT_UNREACH, 0);
+ if (xfrm_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+ IP_INC_STATS_BH(IpInUnknownProtos);
+ icmp_send(skb, ICMP_DEST_UNREACH,
+ ICMP_PROT_UNREACH, 0);
+ }
} else
IP_INC_STATS_BH(IpInDelivers);
kfree_skb(skb);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index 6f979dbe7f36..2ea609f62fdb 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -321,7 +321,7 @@ int ip_queue_xmit(struct sk_buff *skb)
* keep trying until route appears or the connection times
* itself out.
*/
- if (ip_route_output_key(&rt, &fl))
+ if (ip_route_output_flow(&rt, &fl, sk, 0))
goto no_route;
}
__sk_dst_set(sk, &rt->u.dst);
@@ -1220,6 +1220,10 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
{ .daddr = daddr,
.saddr = rt->rt_spec_dst,
.tos = RT_TOS(skb->nh.iph->tos) } },
+ /* Not quite clean, but right. */
+ .uli_u = { .ports =
+ { .sport = skb->h.th->dest,
+ .dport = skb->h.th->source } },
.proto = sk->protocol };
if (ip_route_output_key(&rt, &fl))
return;
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index cab255f23f1f..252acda965e8 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -36,6 +36,7 @@
#include <linux/route.h>
#include <linux/mroute.h>
#include <net/route.h>
+#include <net/xfrm.h>
#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
#include <net/transp_v6.h>
#endif
@@ -624,6 +625,10 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
inet->freebind = !!val;
break;
+ case IP_IPSEC_POLICY:
+ err = xfrm_user_policy(sk, optname, optval, optlen);
+ break;
+
default:
#ifdef CONFIG_NETFILTER
err = nf_setsockopt(sk, PF_INET, optname, optval,
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index f4bbe20272fa..263d39500558 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -64,6 +64,7 @@
#include <net/raw.h>
#include <net/inet_common.h>
#include <net/checksum.h>
+#include <net/xfrm.h>
#include <linux/netfilter_ipv4.h>
struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE];
@@ -237,6 +238,11 @@ static int raw_rcv_skb(struct sock * sk, struct sk_buff * skb)
int raw_rcv(struct sock *sk, struct sk_buff *skb)
{
+ if (xfrm_policy_check(sk, XFRM_POLICY_IN, skb)) {
+ kfree_skb(skb);
+ return NET_RX_DROP;
+ }
+
skb_push(skb, skb->data - skb->nh.raw);
raw_rcv_skb(sk, skb);
@@ -425,7 +431,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
.saddr = saddr,
.tos = tos } },
.proto = IPPROTO_RAW };
- err = ip_route_output_key(&rt, &fl);
+ err = ip_route_output_flow(&rt, &fl, sk, msg->msg_flags&MSG_DONTWAIT);
}
if (err)
goto done;
diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 7b103c6e9d97..4f10bf4c4f68 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -2034,6 +2034,15 @@ int ip_route_output_key(struct rtable **rp, struct flowi *flp)
return flp->proto ? xfrm_lookup((struct dst_entry**)rp, flp, NULL, 0) : 0;
}
+int ip_route_output_flow(struct rtable **rp, struct flowi *flp, struct sock *sk, int flags)
+{
+ int err;
+
+ if ((err = __ip_route_output_key(rp, flp)) != 0)
+ return err;
+ return flp->proto ? xfrm_lookup((struct dst_entry**)rp, flp, sk, flags) : 0;
+}
+
static int rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq, int event,
int nowait)
{
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index fbd5ea082bea..5fae95496824 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -64,11 +64,11 @@
#include <net/tcp.h>
#include <net/ipv6.h>
#include <net/inet_common.h>
+#include <net/xfrm.h>
#include <linux/inet.h>
#include <linux/ipv6.h>
#include <linux/stddef.h>
-#include <linux/ipsec.h>
extern int sysctl_ip_dynaddr;
extern int sysctl_ip_default_ttl;
@@ -1299,7 +1299,7 @@ static struct dst_entry* tcp_v4_route_req(struct sock *sk,
{ .sport = inet_sk(sk)->sport,
.dport = req->rmt_port } } };
- if (ip_route_output_key(&rt, &fl)) {
+ if (ip_route_output_flow(&rt, &fl, sk, 0)) {
IP_INC_STATS_BH(IpOutNoRoutes);
return NULL;
}
@@ -1796,12 +1796,12 @@ int tcp_v4_rcv(struct sk_buff *skb)
goto no_tcp_socket;
process:
- if (!ipsec_sk_policy(sk, skb))
- goto discard_and_relse;
-
if (sk->state == TCP_TIME_WAIT)
goto do_time_wait;
+ if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb))
+ goto discard_and_relse;
+
skb->dev = NULL;
bh_lock_sock(sk);
@@ -1818,6 +1818,9 @@ process:
return ret;
no_tcp_socket:
+ if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb))
+ goto discard_it;
+
if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
bad_packet:
TCP_INC_STATS_BH(TcpInErrs);
@@ -1835,6 +1838,9 @@ discard_and_relse:
goto discard_it;
do_time_wait:
+ if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb))
+ goto discard_and_relse;
+
if (skb->len < (th->doff << 2) || tcp_checksum_complete(skb)) {
TCP_INC_STATS_BH(TcpInErrs);
goto discard_and_relse;
@@ -1950,7 +1956,7 @@ int tcp_v4_rebuild_header(struct sock *sk)
{ .sport = inet->sport,
.dport = inet->dport } } };
- err = ip_route_output_key(&rt, &fl);
+ err = ip_route_output_flow(&rt, &fl, sk, 0);
}
if (!err) {
__sk_dst_set(sk, &rt->u.dst);
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index c8bb729ab8ba..9eb378821111 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -104,6 +104,7 @@
#include <net/route.h>
#include <net/inet_common.h>
#include <net/checksum.h>
+#include <net/xfrm.h>
/*
* Snmp MIB for the UDP layer
@@ -600,7 +601,7 @@ int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
.uli_u = { .ports =
{ .sport = inet->sport,
.dport = dport } } };
- err = ip_route_output_key(&rt, &fl);
+ err = ip_route_output_flow(&rt, &fl, sk, msg->msg_flags&MSG_DONTWAIT);
if (err)
goto out;
@@ -943,6 +944,10 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
/*
* Charge it to the socket, dropping if the queue is full.
*/
+ if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb)) {
+ kfree_skb(skb);
+ return -1;
+ }
#if defined(CONFIG_FILTER)
if (sk->filter && skb->ip_summed != CHECKSUM_UNNECESSARY) {
@@ -1070,6 +1075,9 @@ int udp_rcv(struct sk_buff *skb)
return 0;
}
+ if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb))
+ goto drop;
+
/* No socket. Drop packet silently, if checksum is wrong */
if (udp_checksum_complete(skb))
goto csum_error;
@@ -1110,6 +1118,7 @@ csum_error:
NIPQUAD(daddr),
ntohs(uh->dest),
ulen));
+drop:
UDP_INC_STATS_BH(UdpInErrors);
kfree_skb(skb);
return(0);
diff --git a/net/ipv4/xfrm_input.c b/net/ipv4/xfrm_input.c
index 846c8278e8e6..e94f6759d0ff 100644
--- a/net/ipv4/xfrm_input.c
+++ b/net/ipv4/xfrm_input.c
@@ -123,8 +123,10 @@ int xfrm4_rcv(struct sk_buff *skb)
skb->sp->len += xfrm_nr;
if (decaps) {
- dst_release(skb->dst);
- skb->dst = NULL;
+ if (!(skb->dev->flags&IFF_LOOPBACK)) {
+ dst_release(skb->dst);
+ skb->dst = NULL;
+ }
netif_rx(skb);
return 0;
} else {
diff --git a/net/ipv4/xfrm_policy.c b/net/ipv4/xfrm_policy.c
index 9d76f495f608..3d27f9ede817 100644
--- a/net/ipv4/xfrm_policy.c
+++ b/net/ipv4/xfrm_policy.c
@@ -397,7 +397,7 @@ out:
struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl)
{
struct xfrm_policy *pol;
- // Not now :-) u64 now = (unsigned long)xtime.tv_sec;
+ /* Not now :-) u64 now = (unsigned long)xtime.tv_sec; */
read_lock(&xfrm_policy_lock);
for (pol = xfrm_policy_list[dir]; pol; pol = pol->next) {
@@ -412,6 +412,40 @@ struct xfrm_policy *xfrm_policy_lookup(int dir, struct flowi *fl)
return pol;
}
+struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl)
+{
+ struct xfrm_policy *pol;
+ /* Not now :-) u64 now = (unsigned long)xtime.tv_sec; */
+
+ read_lock(&xfrm_policy_lock);
+ for (pol = sk->policy[dir]; pol; pol = pol->next) {
+ struct xfrm_selector *sel = &pol->selector;
+
+ if (xfrm4_selector_match(sel, fl) /* XXX && XXX now < pol->validtime */) {
+ atomic_inc(&pol->refcnt);
+ break;
+ }
+ }
+ read_unlock(&xfrm_policy_lock);
+ return pol;
+}
+
+int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol)
+{
+ struct xfrm_policy *old_pol;
+
+ write_lock_bh(&xfrm_policy_lock);
+ old_pol = sk->policy[dir];
+ sk->policy[dir] = pol;
+ write_unlock_bh(&xfrm_policy_lock);
+
+ if (old_pol) {
+ xfrm_policy_kill(old_pol);
+ xfrm_pol_put(old_pol);
+ }
+ return 0;
+}
+
/* Resolve list of templates for the flow, given policy. */
static int
@@ -482,12 +516,13 @@ static int xfrm_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl)
* all the metrics... Shortly, bundle a bundle.
*/
-int
+static int
xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm,
struct flowi *fl, struct dst_entry **dst_p)
{
struct dst_entry *dst, *dst_prev;
- struct rtable *rt = (struct rtable*)(*dst_p);
+ struct rtable *rt0 = (struct rtable*)(*dst_p);
+ struct rtable *rt = rt0;
u32 remote = fl->fl4_dst;
u32 local = fl->fl4_src;
int i;
@@ -507,8 +542,11 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm,
dst1->xfrm = xfrm[i];
if (!dst)
dst = dst1;
- else
+ else {
dst_prev->child = dst1;
+ dst1->flags |= DST_NOHASH;
+ dst_clone(dst1);
+ }
dst_prev = dst1;
if (xfrm[i]->props.mode) {
remote = xfrm[i]->id.daddr.xfrm4_addr;
@@ -523,11 +561,11 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm,
.saddr = local }
}
};
- err = ip_route_output_key(&rt, &fl_tunnel);
+ err = __ip_route_output_key(&rt, &fl_tunnel);
if (err)
goto error;
- dst_release(*dst_p);
- *dst_p = &rt->u.dst;
+ } else {
+ dst_clone(&rt->u.dst);
}
dst_prev->child = &rt->u.dst;
for (dst_prev = dst; dst_prev != &rt->u.dst; dst_prev = dst_prev->child) {
@@ -537,7 +575,7 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm,
dst_prev->dev = rt->u.dst.dev;
if (rt->u.dst.dev)
dev_hold(rt->u.dst.dev);
- dst_prev->flags = DST_HOST;
+ dst_prev->flags |= DST_HOST;
dst_prev->lastuse = jiffies;
dst_prev->header_len = header_len;
memcpy(&dst_prev->metrics, &rt->u.dst.metrics, sizeof(dst_prev->metrics));
@@ -550,13 +588,14 @@ xfrm_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm,
if (rt->peer)
atomic_inc(&rt->peer->refcnt);
x->u.rt.peer = rt->peer;
+ /* Sheit... I remember I did this right. Apparently,
+ * it was magically lost, so this code needs audit */
x->u.rt.rt_flags = rt->rt_flags;
x->u.rt.rt_type = rt->rt_type;
- x->u.rt.rt_src = rt->rt_src;
- x->u.rt.rt_src = rt->rt_src;
- x->u.rt.rt_dst = rt->rt_dst;
+ x->u.rt.rt_src = rt0->rt_src;
+ x->u.rt.rt_dst = rt0->rt_dst;
x->u.rt.rt_gateway = rt->rt_gateway;
- x->u.rt.rt_spec_dst = rt->rt_spec_dst;
+ x->u.rt.rt_spec_dst = rt0->rt_spec_dst;
header_len -= x->u.dst.xfrm->props.header_len;
}
*dst_p = dst;
@@ -583,18 +622,24 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
int err;
u32 genid;
- /* To accelerate a bit... */
- if ((rt->u.dst.flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT])
- return 0;
-
fl->oif = rt->u.dst.dev->ifindex;
fl->fl4_src = rt->rt_src;
restart:
genid = xfrm_policy_genid;
- policy = flow_lookup(XFRM_POLICY_OUT, fl);
- if (!policy)
- return 0;
+ policy = NULL;
+ if (sk && sk->policy[1])
+ policy = xfrm_sk_policy_lookup(sk, XFRM_POLICY_OUT, fl);
+
+ if (!policy) {
+ /* To accelerate a bit... */
+ if ((rt->u.dst.flags & DST_NOXFRM) || !xfrm_policy_list[XFRM_POLICY_OUT])
+ return 0;
+
+ policy = flow_lookup(XFRM_POLICY_OUT, fl);
+ if (!policy)
+ return 0;
+ }
switch (policy->action) {
case XFRM_POLICY_BLOCK:
@@ -677,14 +722,13 @@ restart:
write_unlock_bh(&policy->lock);
xfrm_pol_put(policy);
- if (dst) {
- dst_release(dst);
+ if (dst)
dst_free(dst);
- }
goto restart;
}
dst->next = policy->bundles;
policy->bundles = dst;
+ dst_clone(dst);
write_unlock_bh(&policy->lock);
}
*dst_p = dst;
@@ -773,7 +817,7 @@ _decode_session(struct sk_buff *skb, struct flowi *fl)
fl->fl4_src = iph->saddr;
}
-int __xfrm_policy_check(int dir, struct sk_buff *skb)
+int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb)
{
struct xfrm_policy *pol;
struct flowi fl;
@@ -789,7 +833,12 @@ int __xfrm_policy_check(int dir, struct sk_buff *skb)
}
}
- pol = flow_lookup(dir, &fl);
+ pol = NULL;
+ if (sk && sk->policy[dir])
+ pol =xfrm_sk_policy_lookup(sk, dir, &fl);
+
+ if (!pol)
+ pol = flow_lookup(dir, &fl);
if (!pol)
return 1;
@@ -925,10 +974,13 @@ static int xfrm4_get_mss(struct dst_entry *dst, u32 mtu)
do {
struct xfrm_state *x = d->xfrm;
if (x) {
- if (x->type->get_max_size)
+ spin_lock_bh(&x->lock);
+ if (x->km.state == XFRM_STATE_VALID &&
+ x->type && x->type->get_max_size)
m = x->type->get_max_size(d->xfrm, m);
else
m += x->props.header_len;
+ spin_unlock_bh(&x->lock);
}
} while ((d = d->child) != NULL);
diff --git a/net/ipv4/xfrm_state.c b/net/ipv4/xfrm_state.c
index 9adb4dc5a27d..c672c9bea6b8 100644
--- a/net/ipv4/xfrm_state.c
+++ b/net/ipv4/xfrm_state.c
@@ -508,6 +508,43 @@ int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol)
return err;
}
+int xfrm_user_policy(struct sock *sk, int optname, u8 *optval, int optlen)
+{
+ int err;
+ u8 *data;
+ struct xfrm_mgr *km;
+ struct xfrm_policy *pol = NULL;
+
+ if (optlen <= 0 || optlen > PAGE_SIZE)
+ return -EMSGSIZE;
+
+ data = kmalloc(optlen, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ err = -EFAULT;
+ if (copy_from_user(data, optval, optlen))
+ goto out;
+
+ err = -EINVAL;
+ read_lock(&xfrm_km_lock);
+ list_for_each_entry(km, &xfrm_km_list, list) {
+ pol = km->compile_policy(optname, data, optlen, &err);
+ if (err >= 0)
+ break;
+ }
+ read_unlock(&xfrm_km_lock);
+
+ if (err >= 0) {
+ xfrm_sk_policy_insert(sk, err, pol);
+ err = 0;
+ }
+
+out:
+ kfree(data);
+ return err;
+}
+
int xfrm_register_km(struct xfrm_mgr *km)
{
write_lock_bh(&xfrm_km_lock);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 6051c0677f49..1ff9ddc6ccdd 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -107,7 +107,8 @@ struct rt6_info ip6_null_entry = {
.error = -ENETUNREACH,
.input = ip6_pkt_discard,
.output = ip6_pkt_discard,
- .ops = &ip6_dst_ops
+ .ops = &ip6_dst_ops,
+ .path = (struct dst_entry*)&ip6_null_entry,
}
},
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
@@ -1252,6 +1253,9 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
*/
idev = __in6_dev_get(arg->dev);
+ if (idev == NULL)
+ return 0;
+
/* For administrative MTU increase, there is no way to discover
IPv6 PMTU increase, so PMTU increase should be updated here.
Since RFC 1981 doesn't include administrative MTU increase
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index ecc85a8df356..e041453d1d84 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1638,8 +1638,6 @@ static int tcp_v6_rcv(struct sk_buff *skb)
goto no_tcp_socket;
process:
- if(!ipsec_sk_policy(sk,skb))
- goto discard_and_relse;
if(sk->state == TCP_TIME_WAIT)
goto do_time_wait;
diff --git a/net/key/af_key.c b/net/key/af_key.c
index 4eee93ea6e91..0a953121af2a 100644
--- a/net/key/af_key.c
+++ b/net/key/af_key.c
@@ -1080,38 +1080,6 @@ static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg *
}
-static int pfkey_update(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
-{
- struct sk_buff *resp_skb;
- int err;
-
- if (!ext_hdrs[SADB_EXT_SA-1] ||
- !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1],
- ext_hdrs[SADB_EXT_ADDRESS_DST-1]))
- return -EINVAL;
-
- if (hdr->sadb_msg_satype == SADB_SATYPE_ESP &&
- !ext_hdrs[SADB_EXT_KEY_ENCRYPT-1])
- return -EINVAL;
-
- if (hdr->sadb_msg_satype == SADB_SATYPE_AH &&
- !ext_hdrs[SADB_EXT_KEY_AUTH-1])
- return -EINVAL;
-
- if (!!ext_hdrs[SADB_EXT_LIFETIME_HARD-1] !=
- !!ext_hdrs[SADB_EXT_LIFETIME_SOFT-1])
- return -EINVAL;
-
- /* XXX Implement XXX */
- resp_skb = NULL;
- err = -EOPNOTSUPP;
-
- if (!err)
- pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk);
-
- return err;
-}
-
static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs)
{
struct sk_buff *out_skb;
@@ -1125,7 +1093,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr,
/* XXX there is race condition */
x1 = pfkey_xfrm_state_lookup(hdr, ext_hdrs);
- if (x1 != NULL) {
+ if (x1 && hdr->sadb_msg_type == SADB_ADD) {
x->km.state = XFRM_STATE_DEAD;
xfrm_state_put(x);
xfrm_state_put(x1);
@@ -1134,6 +1102,11 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr,
xfrm_state_insert(x);
+ if (x1 && hdr->sadb_msg_type != SADB_ADD) {
+ xfrm_state_delete(x1);
+ xfrm_state_put(x1);
+ }
+
out_skb = pfkey_xfrm_state2msg(x, 0, 3);
if (IS_ERR(out_skb))
return PTR_ERR(out_skb); /* XXX Should we return 0 here ? */
@@ -1166,7 +1139,6 @@ static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
return -ESRCH;
xfrm_state_delete(x);
-
xfrm_state_put(x);
pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL,
@@ -1382,7 +1354,7 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq)
struct sockaddr_in *addr;
if (xp->xfrm_nr >= XFRM_MAX_DEPTH)
- return -EINVAL;
+ return -ELOOP;
if (rq->sadb_x_ipsecrequest_mode == 0)
return -EINVAL;
@@ -1408,7 +1380,7 @@ parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol)
int len = pol->sadb_x_policy_len*8 - sizeof(struct sadb_x_policy);
struct sadb_x_ipsecrequest *rq = (void*)(pol+1);
- while (len > sizeof(struct sadb_x_ipsecrequest)) {
+ while (len >= sizeof(struct sadb_x_ipsecrequest)) {
if ((err = parse_ipsecrequest(xp, rq)) < 0)
return err;
len -= rq->sadb_x_ipsecrequest_len;
@@ -1647,7 +1619,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, sk);
return 0;
- out:
+out:
kfree(xp);
return err;
}
@@ -1823,7 +1795,7 @@ typedef int (*pfkey_handler)(struct sock *sk, struct sk_buff *skb,
static pfkey_handler pfkey_funcs[SADB_MAX + 1] = {
[SADB_RESERVED] = pfkey_reserved,
[SADB_GETSPI] = pfkey_getspi,
- [SADB_UPDATE] = pfkey_update,
+ [SADB_UPDATE] = pfkey_add,
[SADB_ADD] = pfkey_add,
[SADB_DELETE] = pfkey_delete,
[SADB_GET] = pfkey_get,
@@ -2084,6 +2056,58 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct
return 0;
}
+static struct xfrm_policy *pfkey_compile_policy(int opt, u8 *data, int len, int *dir)
+{
+ struct xfrm_policy *xp;
+ struct sadb_x_policy *pol = (struct sadb_x_policy*)data;
+
+ if (opt != IP_IPSEC_POLICY) {
+ *dir = -EOPNOTSUPP;
+ return NULL;
+ }
+
+ *dir = -EINVAL;
+
+ if (len < sizeof(struct sadb_x_policy) ||
+ pol->sadb_x_policy_len*8 > len ||
+ pol->sadb_x_policy_type > IPSEC_POLICY_BYPASS ||
+ (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir > IPSEC_DIR_OUTBOUND))
+ return NULL;
+
+ xp = xfrm_policy_alloc();
+ if (xp == NULL) {
+ *dir = -ENOBUFS;
+ return NULL;
+ }
+
+ xp->index = pol->sadb_x_policy_id;
+ xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ?
+ XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW);
+
+ xp->curlft.add_time = (unsigned long)xtime.tv_sec;
+ xp->curlft.use_time = (unsigned long)xtime.tv_sec;
+ xp->lft.soft_byte_limit = -1;
+ xp->lft.hard_byte_limit = -1;
+ xp->lft.soft_packet_limit = -1;
+ xp->lft.hard_packet_limit = -1;
+ xp->lft.soft_add_expires_seconds = -1;
+ xp->lft.hard_add_expires_seconds = -1;
+ xp->lft.soft_use_expires_seconds = -1;
+ xp->lft.hard_use_expires_seconds = -1;
+
+ xp->xfrm_nr = 0;
+ if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC &&
+ (*dir = parse_ipsecrequests(xp, pol)) < 0)
+ goto out;
+
+ *dir = pol->sadb_x_policy_dir-1;
+ return xp;
+
+out:
+ kfree(xp);
+ return NULL;
+}
+
static int pfkey_sendmsg(struct kiocb *kiocb,
struct socket *sock, struct msghdr *msg, int len,
struct scm_cookie *scm)
@@ -2246,7 +2270,8 @@ static struct xfrm_mgr pfkeyv2_mgr =
{
.id = "pfkeyv2",
.notify = pfkey_send_notify,
- .acquire = pfkey_send_acquire
+ .acquire = pfkey_send_acquire,
+ .compile_policy = pfkey_compile_policy,
};
static void __exit ipsec_pfkey_exit(void)
diff --git a/net/netsyms.c b/net/netsyms.c
index 11f5d2ea2886..7a95b134aa7b 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -286,7 +286,6 @@ EXPORT_SYMBOL(dlci_ioctl_hook);
EXPORT_SYMBOL(xfrm_policy_alloc);
EXPORT_SYMBOL(__xfrm_policy_destroy);
EXPORT_SYMBOL(xfrm_policy_lookup);
-EXPORT_SYMBOL(xfrm_bundle_create);
EXPORT_SYMBOL(xfrm_lookup);
EXPORT_SYMBOL(__xfrm_policy_check);
EXPORT_SYMBOL(__xfrm_route_forward);