diff options
| author | Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> | 2002-11-10 09:04:35 -0800 |
|---|---|---|
| committer | David S. Miller <davem@nuts.ninka.net> | 2002-11-10 09:04:35 -0800 |
| commit | b85b57e3e2cf033fd0a0a377d9d3c3d141d4eb8a (patch) | |
| tree | 7ffc487b70cbde7ee61e362a46bfb50ceff88140 | |
| parent | 2b25a88957143e4dff7b80fc083c44322a37c5f0 (diff) | |
[IPSEC]: More fixes and corrections.
- Make connect() policy selection actually happen
- return len instead of 0 on successful pfkey sendmsg
- make prefixlen checks in a way more compatible with isakmpd
- key manager wait queues are totally wrong
| -rw-r--r-- | include/net/route.h | 11 | ||||
| -rw-r--r-- | include/net/xfrm.h | 13 | ||||
| -rw-r--r-- | net/ipv4/ip_output.c | 10 | ||||
| -rw-r--r-- | net/ipv4/raw.c | 2 | ||||
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 6 | ||||
| -rw-r--r-- | net/ipv4/udp.c | 4 | ||||
| -rw-r--r-- | net/ipv4/xfrm_policy.c | 84 | ||||
| -rw-r--r-- | net/ipv4/xfrm_state.c | 16 | ||||
| -rw-r--r-- | net/key/af_key.c | 70 | ||||
| -rw-r--r-- | net/netsyms.c | 1 |
10 files changed, 156 insertions, 61 deletions
diff --git a/include/net/route.h b/include/net/route.h index ad37024a0154..afab97d19a81 100644 --- a/include/net/route.h +++ b/include/net/route.h @@ -140,7 +140,9 @@ static inline char rt_tos2priority(u8 tos) return ip_tos2prio[IPTOS_TOS(tos)>>1]; } -static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos, int oif, u8 protocol, u16 sport, u16 dport) +static inline int ip_route_connect(struct rtable **rp, u32 dst, + u32 src, u32 tos, int oif, u8 protocol, + u16 sport, u16 dport, struct sock *sk) { struct flowi fl = { .oif = oif, .nl_u = { .ip4_u = { .daddr = dst, @@ -161,10 +163,11 @@ static inline int ip_route_connect(struct rtable **rp, u32 dst, u32 src, u32 tos ip_rt_put(*rp); *rp = NULL; } - return ip_route_output_key(rp, &fl); + return ip_route_output_flow(rp, &fl, sk, 0); } -static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dport) +static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dport, + struct sock *sk) { if (sport != (*rp)->fl.uli_u.ports.sport || dport != (*rp)->fl.uli_u.ports.dport) { @@ -175,7 +178,7 @@ static inline int ip_route_newports(struct rtable **rp, u16 sport, u16 dport) fl.uli_u.ports.dport = dport; ip_rt_put(*rp); *rp = NULL; - return ip_route_output_key(rp, &fl); + return ip_route_output_flow(rp, &fl, sk, 0); } return 0; } diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 7bef54d4532b..e82a59c8c24c 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -8,6 +8,9 @@ #include <net/dst.h> #include <net/route.h> +extern struct semaphore xfrm_cfg_sem; + + /* Organization of SPD aka "XFRM rules" ------------------------------------ @@ -320,7 +323,7 @@ extern int xfrm_register_km(struct xfrm_mgr *km); extern int xfrm_unregister_km(struct xfrm_mgr *km); -extern struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX]; +extern struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; static inline void xfrm_pol_hold(struct xfrm_policy *policy) { @@ -429,16 +432,16 @@ static inline int xfrm_sk_clone_policy(struct sock *sk) return 0; } -extern void __xfrm_sk_free_policy(struct xfrm_policy *); +extern void __xfrm_sk_free_policy(struct xfrm_policy *, int dir); static inline void xfrm_sk_free_policy(struct sock *sk) { if (unlikely(sk->policy[0] != NULL)) { - __xfrm_sk_free_policy(sk->policy[0]); + __xfrm_sk_free_policy(sk->policy[0], 0); sk->policy[0] = NULL; } if (unlikely(sk->policy[1] != NULL)) { - __xfrm_sk_free_policy(sk->policy[1]); + __xfrm_sk_free_policy(sk->policy[1], 1); sk->policy[1] = NULL; } } @@ -477,7 +480,7 @@ extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *p extern struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl); extern int xfrm_flush_bundles(struct xfrm_state *x); -extern wait_queue_head_t *km_waitq; +extern wait_queue_head_t km_waitq; extern void km_warn_expired(struct xfrm_state *x); extern void km_expired(struct xfrm_state *x); extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *pol); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index 2ea609f62fdb..c62ef5eed340 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -815,14 +815,16 @@ alloc_new_skb: alloclen = maxfraglen; else alloclen = datalen + fragheaderlen; - if (!(flags & MSG_DONTWAIT) || transhdrlen) { + if (transhdrlen) { skb = sock_alloc_send_skb(sk, alloclen + hh_len + 15, (flags & MSG_DONTWAIT), &err); } else { - skb = sock_wmalloc(sk, - alloclen + hh_len + 15, 1, - sk->allocation); + skb = NULL; + if (atomic_read(&sk->wmem_alloc) <= 2*sk->sndbuf) + skb = sock_wmalloc(sk, + alloclen + hh_len + 15, 1, + sk->allocation); if (unlikely(skb == NULL)) err = -ENOBUFS; } diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c index 1612e2df2b91..cfb5457377ca 100644 --- a/net/ipv4/raw.c +++ b/net/ipv4/raw.c @@ -431,7 +431,7 @@ static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, .saddr = saddr, .tos = tos } }, .proto = inet->hdrincl ? IPPROTO_RAW : sk->protocol }; - err = ip_route_output_flow(&rt, &fl, sk, msg->msg_flags&MSG_DONTWAIT); + err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); } if (err) goto done; diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 5fae95496824..c7f7223fa7d1 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -780,7 +780,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) tmp = ip_route_connect(&rt, nexthop, inet->saddr, RT_CONN_FLAGS(sk), sk->bound_dev_if, IPPROTO_TCP, - inet->sport, usin->sin_port); + inet->sport, usin->sin_port, sk); if (tmp < 0) return tmp; @@ -837,7 +837,7 @@ int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) if (err) goto failure; - err = ip_route_newports(&rt, inet->sport, inet->dport); + err = ip_route_newports(&rt, inet->sport, inet->dport, sk); if (err) goto failure; @@ -1896,7 +1896,7 @@ static int tcp_v4_reselect_saddr(struct sock *sk) RT_TOS(inet->tos) | sk->localroute, sk->bound_dev_if, IPPROTO_TCP, - inet->sport, inet->dport); + inet->sport, inet->dport, sk); if (err) return err; diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 9eb378821111..b816d2f362e2 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -601,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_flow(&rt, &fl, sk, msg->msg_flags&MSG_DONTWAIT); + err = ip_route_output_flow(&rt, &fl, sk, !(msg->msg_flags&MSG_DONTWAIT)); if (err) goto out; @@ -884,7 +884,7 @@ int udp_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) err = ip_route_connect(&rt, usin->sin_addr.s_addr, saddr, RT_CONN_FLAGS(sk), oif, IPPROTO_UDP, - inet->sport, usin->sin_port); + inet->sport, usin->sin_port, sk); if (err) return err; if ((rt->rt_flags&RTCF_BROADCAST) && !sk->broadcast) { diff --git a/net/ipv4/xfrm_policy.c b/net/ipv4/xfrm_policy.c index 93c5b14b00fd..6d23f57172c3 100644 --- a/net/ipv4/xfrm_policy.c +++ b/net/ipv4/xfrm_policy.c @@ -1,10 +1,12 @@ #include <net/xfrm.h> #include <net/ip.h> +DECLARE_MUTEX(xfrm_cfg_sem); + static u32 xfrm_policy_genid; static rwlock_t xfrm_policy_lock = RW_LOCK_UNLOCKED; -struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX]; +struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; extern struct dst_ops xfrm4_dst_ops; @@ -263,10 +265,13 @@ static u32 xfrm_gen_index(int dir) { u32 idx; struct xfrm_policy *p; - static u32 pol_id; + static u32 idx_generator; for (;;) { - idx = (++pol_id ? : ++pol_id); + idx = (idx_generator | dir); + idx_generator += 8; + if (idx == 0) + idx = 8; for (p = xfrm_policy_list[dir]; p; p = p->next) { if (p->index == idx) break; @@ -300,6 +305,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl) write_unlock_bh(&xfrm_policy_lock); if (pol) { + atomic_dec(&pol->refcnt); xfrm_policy_kill(pol); xfrm_pol_put(pol); } @@ -328,7 +334,7 @@ struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete) struct xfrm_policy *pol, **p; write_lock_bh(&xfrm_policy_lock); - for (p = &xfrm_policy_list[dir]; (pol=*p)!=NULL; p = &pol->next) { + for (p = &xfrm_policy_list[id & 7]; (pol=*p)!=NULL; p = &pol->next) { if (pol->index == id) { if (delete) *p = pol->next; @@ -375,7 +381,7 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), int error = 0; read_lock(&xfrm_policy_lock); - for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { + for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) count++; } @@ -385,9 +391,9 @@ int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), goto out; } - for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { + for (dir = 0; dir < 2*XFRM_POLICY_MAX; dir++) { for (xp = xfrm_policy_list[dir]; xp; xp = xp->next) { - error = func(xp, dir, --count, data); + error = func(xp, dir%XFRM_POLICY_MAX, --count, data); if (error) goto out; } @@ -423,18 +429,37 @@ struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi struct xfrm_policy *pol; 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)) { + if ((pol = sk->policy[dir]) != NULL) { + if (xfrm4_selector_match(&pol->selector, fl)) atomic_inc(&pol->refcnt); - break; - } + else + pol = NULL; } read_unlock(&xfrm_policy_lock); return pol; } +void xfrm_sk_policy_link(struct xfrm_policy *pol, int dir) +{ + pol->next = xfrm_policy_list[XFRM_POLICY_MAX+dir]; + xfrm_policy_list[XFRM_POLICY_MAX+dir] = pol; + atomic_inc(&pol->refcnt); +} + +void xfrm_sk_policy_unlink(struct xfrm_policy *pol, int dir) +{ + struct xfrm_policy **polp; + + for (polp = &xfrm_policy_list[XFRM_POLICY_MAX+dir]; + *polp != NULL; polp = &(*polp)->next) { + if (*polp == pol) { + *polp = pol->next; + atomic_dec(&pol->refcnt); + return; + } + } +} + int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) { struct xfrm_policy *old_pol; @@ -442,6 +467,13 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) write_lock_bh(&xfrm_policy_lock); old_pol = sk->policy[dir]; sk->policy[dir] = pol; + if (pol) { + pol->curlft.add_time = (unsigned long)xtime.tv_sec; + pol->index = xfrm_gen_index(XFRM_POLICY_MAX+dir); + xfrm_sk_policy_link(pol, dir); + } + if (old_pol) + xfrm_sk_policy_unlink(old_pol, dir); write_unlock_bh(&xfrm_policy_lock); if (old_pol) { @@ -451,7 +483,7 @@ int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol) return 0; } -static struct xfrm_policy *clone_policy(struct xfrm_policy *old) +static struct xfrm_policy *clone_policy(struct xfrm_policy *old, int dir) { struct xfrm_policy *newp = xfrm_policy_alloc(GFP_ATOMIC); @@ -462,8 +494,12 @@ static struct xfrm_policy *clone_policy(struct xfrm_policy *old) newp->action = old->action; newp->flags = old->flags; newp->xfrm_nr = old->xfrm_nr; + newp->index = old->index; memcpy(newp->xfrm_vec, old->xfrm_vec, newp->xfrm_nr*sizeof(struct xfrm_tmpl)); + write_lock_bh(&xfrm_policy_lock); + xfrm_sk_policy_link(newp, dir); + write_unlock_bh(&xfrm_policy_lock); } return newp; } @@ -475,15 +511,19 @@ int __xfrm_sk_clone_policy(struct sock *sk) p1 = sk->policy[1]; sk->policy[0] = NULL; sk->policy[1] = NULL; - if (p0 && (sk->policy[0] = clone_policy(p0)) == NULL) + if (p0 && (sk->policy[0] = clone_policy(p0, 0)) == NULL) return -ENOMEM; - if (p1 && (sk->policy[1] = clone_policy(p1)) == NULL) + if (p1 && (sk->policy[1] = clone_policy(p1, 1)) == NULL) return -ENOMEM; return 0; } -void __xfrm_sk_free_policy(struct xfrm_policy *pol) +void __xfrm_sk_free_policy(struct xfrm_policy *pol, int dir) { + write_lock_bh(&xfrm_policy_lock); + xfrm_sk_policy_unlink(pol, dir); + write_unlock_bh(&xfrm_policy_lock); + xfrm_policy_kill(pol); xfrm_pol_put(pol); } @@ -734,12 +774,12 @@ restart: goto error; __set_task_state(tsk, TASK_INTERRUPTIBLE); - add_wait_queue(km_waitq, &wait); + add_wait_queue(&km_waitq, &wait); err = xfrm_tmpl_resolve(policy, fl, xfrm); if (err == -EAGAIN) schedule(); __set_task_state(tsk, TASK_RUNNING); - remove_wait_queue(km_waitq, &wait); + remove_wait_queue(&km_waitq, &wait); if (err == -EAGAIN && signal_pending(current)) { err = -ERESTART; @@ -888,7 +928,7 @@ int __xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *skb) pol = NULL; if (sk && sk->policy[dir]) - pol =xfrm_sk_policy_lookup(sk, dir, &fl); + pol = xfrm_sk_policy_lookup(sk, dir, &fl); if (!pol) pol = flow_lookup(dir, &fl); @@ -985,7 +1025,7 @@ static int xfrm4_garbage_collect(void) struct dst_entry *dst, **dstp, *gc_list = NULL; read_lock_bh(&xfrm_policy_lock); - for (i=0; i<XFRM_POLICY_MAX; i++) { + for (i=0; i<2*XFRM_POLICY_MAX; i++) { for (pol = xfrm_policy_list[i]; pol; pol = pol->next) { write_lock(&pol->lock); dstp = &pol->bundles; @@ -1028,7 +1068,7 @@ int xfrm_flush_bundles(struct xfrm_state *x) struct dst_entry *dst, **dstp, *gc_list = NULL; read_lock_bh(&xfrm_policy_lock); - for (i=0; i<XFRM_POLICY_MAX; i++) { + for (i=0; i<2*XFRM_POLICY_MAX; i++) { for (pol = xfrm_policy_list[i]; pol; pol = pol->next) { write_lock(&pol->lock); dstp = &pol->bundles; diff --git a/net/ipv4/xfrm_state.c b/net/ipv4/xfrm_state.c index 6605a8c8fa1c..75ef5a816ff5 100644 --- a/net/ipv4/xfrm_state.c +++ b/net/ipv4/xfrm_state.c @@ -22,7 +22,7 @@ static spinlock_t xfrm_state_lock = SPIN_LOCK_UNLOCKED; static struct list_head xfrm_state_bydst[XFRM_DST_HSIZE]; static struct list_head xfrm_state_byspi[XFRM_DST_HSIZE]; -wait_queue_head_t *km_waitq; +DECLARE_WAIT_QUEUE_HEAD(km_waitq); #define ACQ_EXPIRES 30 @@ -163,7 +163,7 @@ static void __xfrm_state_delete(struct xfrm_state *x) if (kill && x->type) x->type->destructor(x); - wake_up(km_waitq); + wake_up(&km_waitq); } void xfrm_state_delete(struct xfrm_state *x) @@ -195,7 +195,7 @@ restart: } } spin_unlock_bh(&xfrm_state_lock); - wake_up(km_waitq); + wake_up(&km_waitq); } struct xfrm_state * @@ -213,6 +213,7 @@ xfrm_state_find(u32 daddr, u32 saddr, struct flowi *fl, struct xfrm_tmpl *tmpl, spin_lock_bh(&xfrm_state_lock); list_for_each_entry(x, xfrm_state_bydst+h, bydst) { if (daddr == x->id.daddr.xfrm4_addr && + x->props.reqid == tmpl->reqid && (saddr == x->props.saddr.xfrm4_addr || !saddr || !x->props.saddr.xfrm4_addr) && tmpl->mode == x->props.mode && tmpl->id.proto == x->id.proto) { @@ -278,6 +279,7 @@ xfrm_state_find(u32 daddr, u32 saddr, struct flowi *fl, struct xfrm_tmpl *tmpl, if (x->props.saddr.xfrm4_addr == 0) x->props.saddr.xfrm4_addr = saddr; x->props.mode = tmpl->mode; + x->props.reqid = tmpl->reqid; if (km_query(x, tmpl, pol) == 0) { x->km.state = XFRM_STATE_ACQ; @@ -323,7 +325,7 @@ void xfrm_state_insert(struct xfrm_state *x) atomic_inc(&x->refcnt); spin_unlock_bh(&xfrm_state_lock); - wake_up(km_waitq); + wake_up(&km_waitq); } int xfrm_state_check_expire(struct xfrm_state *x) @@ -398,7 +400,7 @@ xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr) mode == x->props.mode && proto == x->id.proto && saddr == x->props.saddr.xfrm4_addr && - (!reqid || reqid == x->props.reqid)) { + reqid == x->props.reqid) { if (!x0) x0 = x; if (x->km.state != XFRM_STATE_ACQ) @@ -427,7 +429,7 @@ xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr) mod_timer(&x0->timer, jiffies + ACQ_EXPIRES*HZ); atomic_inc(&x0->refcnt); list_add_tail(&x0->bydst, xfrm_state_bydst+h); - wake_up(km_waitq); + wake_up(&km_waitq); } spin_unlock_bh(&xfrm_state_lock); return x0; @@ -491,7 +493,7 @@ xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi) list_add(&x->byspi, xfrm_state_byspi+h); atomic_inc(&x->refcnt); spin_unlock_bh(&xfrm_state_lock); - wake_up(km_waitq); + wake_up(&km_waitq); } } diff --git a/net/key/af_key.c b/net/key/af_key.c index 5c7517cada36..bcabdcabdc6c 100644 --- a/net/key/af_key.c +++ b/net/key/af_key.c @@ -30,6 +30,7 @@ #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x)) #define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x)) + /* List of all pfkey sockets. */ static struct sock * pfkey_table; static DECLARE_WAIT_QUEUE_HEAD(pfkey_table_wait); @@ -871,10 +872,6 @@ static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, !!ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]) return ERR_PTR(-EINVAL); - /* XXX Do we need this check ? */ - if (((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_SRC-1])->sadb_address_prefixlen != 32 || - ((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1])->sadb_address_prefixlen != 32) - return ERR_PTR(-EINVAL); proto = pfkey_satype2proto(hdr->sadb_msg_satype); if (proto == 0) return ERR_PTR(-EINVAL); @@ -1379,6 +1376,34 @@ static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg * return 0; } +static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr) +{ + int i; + u16 reqid = *(u16*)ptr; + + for (i=0; i<xp->xfrm_nr; i++) { + if (xp->xfrm_vec[i].reqid == reqid) + return -EEXIST; + } + return 0; +} + +static u16 gen_reqid(void) +{ + u16 start; + static u16 reqid = IPSEC_MANUAL_REQID_MAX; + + start = reqid; + do { + ++reqid; + if (reqid == 0) + reqid = IPSEC_MANUAL_REQID_MAX+1; + if (xfrm_policy_walk(check_reqid, (void*)&reqid) != -EEXIST) + return reqid; + } while (reqid != start); + return 0; +} + static int parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) { @@ -1395,7 +1420,14 @@ parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) t->mode = rq->sadb_x_ipsecrequest_mode-1; if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE) t->optional = 1; - t->reqid = rq->sadb_x_ipsecrequest_reqid; + else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) { + t->reqid = rq->sadb_x_ipsecrequest_reqid; + if (t->reqid > IPSEC_MANUAL_REQID_MAX) + t->reqid = 0; + if (!t->reqid && !(t->reqid = gen_reqid())) + return -ENOBUFS; + } + /* addresses present only in tunnel mode */ if (t->mode) { addr = (void*)(rq+1); @@ -1544,6 +1576,8 @@ static struct sk_buff * pfkey_xfrm_policy2msg(struct xfrm_policy *xp, int dir) rq->sadb_x_ipsecrequest_proto = t->id.proto; rq->sadb_x_ipsecrequest_mode = t->mode+1; rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE; + if (t->reqid) + rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE; if (t->optional) rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE; rq->sadb_x_ipsecrequest_reqid = t->reqid; @@ -1590,7 +1624,6 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h if (xp == NULL) return -ENOBUFS; - xp->index = pol->sadb_x_policy_id; xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ? XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW); @@ -2013,6 +2046,18 @@ static int pfkey_send_notify(struct xfrm_state *x, int hard) return 0; } +static u32 get_acqseq(void) +{ + u32 res; + static u32 acqseq; + static spinlock_t acqseq_lock = SPIN_LOCK_UNLOCKED; + + spin_lock_bh(&acqseq_lock); + res = (++acqseq ? : ++acqseq); + spin_unlock_bh(&acqseq_lock); + return res; +} + static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp, int dir) { struct sk_buff *skb; @@ -2020,7 +2065,6 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct struct sadb_address *addr; struct sadb_x_policy *pol; int size; - static u32 acqseq; size = sizeof(struct sadb_msg) + sizeof(struct sadb_address)*2 + @@ -2043,10 +2087,9 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct hdr->sadb_msg_len = size / sizeof(uint64_t); hdr->sadb_msg_errno = 0; hdr->sadb_msg_reserved = 0; - hdr->sadb_msg_seq = (++acqseq ? : ++acqseq); - x->km.seq = acqseq; + hdr->sadb_msg_seq = x->km.seq = get_acqseq(); hdr->sadb_msg_pid = 0; - + /* src address */ addr = (struct sadb_address*) skb_put(skb, sizeof(struct sadb_address)+sizeof(struct sockaddr_in)); @@ -2076,7 +2119,7 @@ static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct ((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr = x->id.daddr.xfrm4_addr; ((struct sockaddr_in*)(addr + 1))->sin_port = 0; - + pol = (struct sadb_x_policy *) skb_put(skb, sizeof(struct sadb_x_policy)); pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t); pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; @@ -2119,7 +2162,6 @@ static struct xfrm_policy *pfkey_compile_policy(int opt, u8 *data, int len, int 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); @@ -2171,7 +2213,9 @@ static int pfkey_sendmsg(struct kiocb *kiocb, if (!hdr) goto out; + down(&xfrm_cfg_sem); err = pfkey_process(sk, skb, hdr); + up(&xfrm_cfg_sem); out: if (err && hdr && pfkey_error(hdr, err, sk) == 0) @@ -2179,7 +2223,7 @@ out: if (skb) kfree_skb(skb); - return err; + return err ? : len; } static int pfkey_recvmsg(struct kiocb *kiocb, diff --git a/net/netsyms.c b/net/netsyms.c index 7a6797a03236..de2ba57226f6 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -283,6 +283,7 @@ extern int (*dlci_ioctl_hook)(unsigned int, void *); EXPORT_SYMBOL(dlci_ioctl_hook); #endif +EXPORT_SYMBOL(xfrm_cfg_sem); EXPORT_SYMBOL(xfrm_policy_alloc); EXPORT_SYMBOL(__xfrm_policy_destroy); EXPORT_SYMBOL(xfrm_policy_lookup); |
