Commit 8c22b71f authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/home/davem/BK/net-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents cd8963f8 9ce7e537
......@@ -1528,7 +1528,7 @@ struct tg3_internal_buffer_desc {
u32 __cookie3;
};
#define TG3_HW_STATUS_SIZE 0x80
#define TG3_HW_STATUS_SIZE 0x50
struct tg3_hw_status {
u32 status;
#define SD_STATUS_UPDATED 0x00000001
......
......@@ -7,6 +7,7 @@
#define NETLINK_FIREWALL 3 /* Firewalling hook */
#define NETLINK_TCPDIAG 4 /* TCP socket monitoring */
#define NETLINK_NFLOG 5 /* netfilter/iptables ULOG */
#define NETLINK_XFRM 6 /* ipsec */
#define NETLINK_ARPD 8
#define NETLINK_ROUTE6 11 /* af_inet6 route comm channel */
#define NETLINK_IP6_FW 13
......@@ -86,6 +87,8 @@ struct nlmsgerr
#ifdef __KERNEL__
#include <linux/capability.h>
struct netlink_skb_parms
{
struct ucred creds; /* Skb credentials */
......
#ifndef _LINUX_XFRM_H
#define _LINUX_XFRM_H
#include <linux/types.h>
/* All of the structures in this file may not change size as they are
* passed into the kernel from userspace via netlink sockets.
*/
/* Structure to encapsulate addresses. I do not want to use
* "standard" structure. My apologies.
*/
typedef union
{
struct {
__u32 addr;
__u32 mask; /* Use unused bits to cache mask. */
} a4;
#define xfrm4_addr a4.addr
#define xfrm4_mask a4.mask
__u32 a6[4];
} xfrm_address_t;
/* Ident of a specific xfrm_state. It is used on input to lookup
* the state by (spi,daddr,ah/esp) or to store information about
* spi, protocol and tunnel address on output.
*/
struct xfrm_id
{
xfrm_address_t daddr;
__u32 spi;
__u8 proto;
};
/* Selector, used as selector both on policy rules (SPD) and SAs. */
struct xfrm_selector
{
xfrm_address_t daddr;
xfrm_address_t saddr;
__u16 dport;
__u16 dport_mask;
__u16 sport;
__u16 sport_mask;
__u8 prefixlen_d;
__u8 prefixlen_s;
__u8 proto;
int ifindex;
uid_t user;
void *owner;
};
#define XFRM_INF (~(u64)0)
struct xfrm_lifetime_cfg
{
__u64 soft_byte_limit;
__u64 hard_byte_limit;
__u64 soft_packet_limit;
__u64 hard_packet_limit;
__u64 soft_add_expires_seconds;
__u64 hard_add_expires_seconds;
__u64 soft_use_expires_seconds;
__u64 hard_use_expires_seconds;
};
struct xfrm_lifetime_cur
{
__u64 bytes;
__u64 packets;
__u64 add_time;
__u64 use_time;
};
struct xfrm_replay_state
{
__u32 oseq;
__u32 seq;
__u32 bitmap;
};
struct xfrm_algo {
char alg_name[64];
int alg_key_len; /* in bits */
char alg_key[0];
};
struct xfrm_stats {
__u32 replay_window;
__u32 replay;
__u32 integrity_failed;
};
/* Netlink configuration messages. */
#define XFRM_MSG_BASE 0x10
#define XFRM_MSG_NEWSA (RTM_BASE + 0)
#define XFRM_MSG_DELSA (RTM_BASE + 1)
#define XFRM_MSG_GETSA (RTM_BASE + 2)
#define XFRM_MSG_NEWPOLICY (RTM_BASE + 3)
#define XFRM_MSG_DELPOLICY (RTM_BASE + 4)
#define XFRM_MSG_GETPOLICY (RTM_BASE + 5)
#define XFRM_MSG_ALLOCSPI (RTM_BASE + 6)
#define XFRM_MSG_ACQUIRE (RTM_BASE + 7)
#define XFRM_MSG_MAX (XFRM_MSG_ACQUIRE+1)
struct xfrm_user_tmpl {
struct xfrm_id id;
xfrm_address_t saddr;
__u16 reqid;
__u8 mode;
__u8 share;
__u32 aalgos;
__u32 ealgos;
__u32 calgos;
};
/* Netlink message attributes. */
enum xfrm_attr_type_t {
XFRMA_UNSPEC,
XFRMA_ALG_AUTH, /* struct xfrm_algo */
XFRMA_ALG_CRYPT, /* struct xfrm_algo */
XFRMA_ALG_COMP, /* struct xfrm_algo */
XFRMA_TMPL, /* 1 or more struct xfrm_user_tmpl */
#define XFRMA_MAX XFRMA_TMPL
};
struct xfrm_usersa_info {
struct xfrm_selector sel;
struct xfrm_id id;
struct xfrm_lifetime_cfg lft;
struct xfrm_lifetime_cur curlft;
struct xfrm_stats stats;
__u16 family;
__u16 reqid;
__u8 sa_type;
__u8 mode; /* 0=transport,1=tunnel */
__u8 replay_window;
};
struct xfrm_usersa_id {
xfrm_address_t saddr;
__u32 spi;
__u8 proto;
};
struct xfrm_userpolicy_info {
struct xfrm_selector sel;
struct xfrm_id id;
struct xfrm_lifetime_cfg lft;
struct xfrm_lifetime_cur curlft;
__u32 index;
__u16 family;
__u8 dir;
__u8 action;
};
struct xfrm_userpolicy_id {
struct xfrm_selector sel;
__u32 index;
__u8 dir;
};
#endif /* _LINUX_XFRM_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;
}
......
#include <linux/types.h>
#include <linux/xfrm.h>
#include <linux/spinlock.h>
#include <linux/list.h>
#include <linux/skbuff.h>
......@@ -8,6 +8,8 @@
#include <net/dst.h>
#include <net/route.h>
extern struct semaphore xfrm_cfg_sem;
/* Organization of SPD aka "XFRM rules"
------------------------------------
......@@ -69,84 +71,6 @@
metrics. Plus, it will be made via sk->dst_cache. Solved.
*/
/* Structure to encapsulate addresses. I do not want to use
* "standard" structure. My apologies. */
typedef union
{
struct {
u32 addr;
u32 mask; /* Use unused bits to cache mask. */
} a4;
#define xfrm4_addr a4.addr
#define xfrm4_mask a4.mask
u32 a6[4];
} xfrm_address_t;
/* Ident of a specific xfrm_state. It is used on input to lookup
* the state by (spi,daddr,ah/esp) or to store information about
* spi, protocol and tunnel address on output. */
struct xfrm_id
{
xfrm_address_t daddr;
__u32 spi;
__u8 proto;
};
/* Selector, used as selector both on policy rules (SPD) and SAs. */
struct xfrm_selector
{
xfrm_address_t daddr;
xfrm_address_t saddr;
__u16 dport;
__u16 dport_mask;
__u16 sport;
__u16 sport_mask;
__u8 prefixlen_d;
__u8 prefixlen_s;
__u8 proto;
int ifindex;
uid_t user;
void *owner;
};
#define XFRM_INF (~(u64)0)
struct xfrm_lifetime_cfg
{
u64 soft_byte_limit;
u64 hard_byte_limit;
u64 soft_packet_limit;
u64 hard_packet_limit;
u64 soft_add_expires_seconds;
u64 hard_add_expires_seconds;
u64 soft_use_expires_seconds;
u64 hard_use_expires_seconds;
};
struct xfrm_lifetime_cur
{
u64 bytes;
u64 packets;
u64 add_time;
u64 use_time;
};
struct xfrm_replay_state
{
u32 oseq;
u32 seq;
u32 bitmap;
};
struct xfrm_algo {
char alg_name[CRYPTO_MAX_ALG_NAME];
int alg_key_len; /* in bits */
char alg_key[0];
};
/* Full description of state of transformer. */
struct xfrm_state
{
......@@ -188,11 +112,7 @@ struct xfrm_state
struct xfrm_replay_state replay;
/* Statistics */
struct {
u32 replay_window;
u32 replay;
u32 integrity_failed;
} stats;
struct xfrm_stats stats;
struct xfrm_lifetime_cur curlft;
struct timer_list timer;
......@@ -320,7 +240,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 +349,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 +397,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);
......@@ -1142,65 +1142,115 @@ struct arp_iter_state {
int is_pneigh, bucket;
};
static __inline__ struct neighbour *neigh_get_bucket(struct seq_file *seq,
loff_t *pos)
static struct neighbour *neigh_get_first(struct seq_file *seq)
{
struct neighbour *n = NULL;
struct arp_iter_state* state = seq->private;
loff_t l = *pos;
int i;
for (; state->bucket <= NEIGH_HASHMASK; ++state->bucket)
for (i = 0, n = arp_tbl.hash_buckets[state->bucket]; n;
++i, n = n->next)
/* Do not confuse users "arp -a" with magic entries */
if ((n->nud_state & ~NUD_NOARP) && !l--) {
*pos = i;
goto out;
}
out:
struct neighbour *n = NULL;
state->is_pneigh = 0;
for (state->bucket = 0;
state->bucket <= NEIGH_HASHMASK;
++state->bucket) {
n = arp_tbl.hash_buckets[state->bucket];
while (n && !(n->nud_state & ~NUD_NOARP))
n = n->next;
if (n)
break;
}
return n;
}
static __inline__ struct pneigh_entry *pneigh_get_bucket(struct seq_file *seq,
loff_t *pos)
static struct neighbour *neigh_get_next(struct seq_file *seq,
struct neighbour *n)
{
struct pneigh_entry *n = NULL;
struct arp_iter_state* state = seq->private;
loff_t l = *pos;
int i;
for (; state->bucket <= PNEIGH_HASHMASK; ++state->bucket)
for (i = 0, n = arp_tbl.phash_buckets[state->bucket]; n;
++i, n = n->next)
if (!l--) {
*pos = i;
goto out;
}
do {
n = n->next;
/* Don't confuse "arp -a" w/ magic entries */
try_again:
} while (n && !(n->nud_state & ~NUD_NOARP));
if (n)
goto out;
if (++state->bucket > NEIGH_HASHMASK)
goto out;
n = arp_tbl.hash_buckets[state->bucket];
goto try_again;
out:
return n;
}
static __inline__ void *arp_get_bucket(struct seq_file *seq, loff_t *pos)
static struct neighbour *neigh_get_idx(struct seq_file *seq, loff_t *pos)
{
void *rc = neigh_get_bucket(seq, pos);
struct neighbour *n = neigh_get_first(seq);
if (!rc) {
struct arp_iter_state* state = seq->private;
if (n)
while (*pos && (n = neigh_get_next(seq, n)))
--*pos;
return *pos ? NULL : n;
}
static struct pneigh_entry *pneigh_get_first(struct seq_file *seq)
{
struct arp_iter_state* state = seq->private;
struct pneigh_entry *pn;
state->is_pneigh = 1;
for (state->bucket = 0;
state->bucket <= PNEIGH_HASHMASK;
++state->bucket) {
pn = arp_tbl.phash_buckets[state->bucket];
if (pn)
break;
}
return pn;
}
static struct pneigh_entry *pneigh_get_next(struct seq_file *seq,
struct pneigh_entry *pn)
{
struct arp_iter_state* state = seq->private;
pn = pn->next;
while (!pn) {
if (++state->bucket > PNEIGH_HASHMASK)
break;
pn = arp_tbl.phash_buckets[state->bucket];
}
return pn;
}
static struct pneigh_entry *pneigh_get_idx(struct seq_file *seq, loff_t pos)
{
struct pneigh_entry *pn = pneigh_get_first(seq);
if (pn)
while (pos && (pn = pneigh_get_next(seq, pn)))
--pos;
return pos ? NULL : pn;
}
static void *arp_get_idx(struct seq_file *seq, loff_t pos)
{
void *rc;
read_lock_bh(&arp_tbl.lock);
rc = neigh_get_idx(seq, &pos);
if (!rc) {
read_unlock_bh(&arp_tbl.lock);
state->is_pneigh = 1;
state->bucket = 0;
*pos = 0;
rc = pneigh_get_bucket(seq, pos);
rc = pneigh_get_idx(seq, pos);
}
return rc;
}
static void *arp_seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock_bh(&arp_tbl.lock);
return *pos ? arp_get_bucket(seq, pos) : (void *)1;
return *pos ? arp_get_idx(seq, *pos - 1) : (void *)1;
}
static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
......@@ -1209,38 +1259,19 @@ static void *arp_seq_next(struct seq_file *seq, void *v, loff_t *pos)
struct arp_iter_state* state;
if (v == (void *)1) {
rc = arp_get_bucket(seq, pos);
rc = arp_get_idx(seq, 0);
goto out;
}
state = seq->private;
if (!state->is_pneigh) {
struct neighbour *n = v;
rc = n = n->next;
if (n)
goto out;
*pos = 0;
++state->bucket;
rc = neigh_get_bucket(seq, pos);
rc = neigh_get_next(seq, v);
if (rc)
goto out;
read_unlock_bh(&arp_tbl.lock);
state->is_pneigh = 1;
state->bucket = 0;
*pos = 0;
rc = pneigh_get_bucket(seq, pos);
} else {
struct pneigh_entry *pn = v;
pn = pn->next;
if (!pn) {
++state->bucket;
*pos = 0;
pn = pneigh_get_bucket(seq, pos);
}
rc = pn;
}
rc = pneigh_get_first(seq);
} else
rc = pneigh_get_next(seq, v);
out:
++*pos;
return rc;
......@@ -1291,7 +1322,6 @@ static __inline__ void arp_format_neigh_entry(struct seq_file *seq,
static __inline__ void arp_format_pneigh_entry(struct seq_file *seq,
struct pneigh_entry *n)
{
struct net_device *dev = n->dev;
int hatype = dev ? dev->type : 0;
char tbuf[16];
......
......@@ -815,14 +815,16 @@ int ip_append_data(struct sock *sk,
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;
}
......
......@@ -164,13 +164,11 @@ int snmp_get_info(char *buffer, char **start, off_t offset, int length)
/*
* Output /proc/net/netstat
*/
int netstat_get_info(char *buffer, char **start, off_t offset, int length)
static int netstat_seq_show(struct seq_file *seq, void *v)
{
int len, i;
int i;
len = sprintf(buffer,
"TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
seq_puts(seq, "TcpExt: SyncookiesSent SyncookiesRecv SyncookiesFailed"
" EmbryonicRsts PruneCalled RcvPruned OfoPruned"
" OutOfWindowIcmps LockDroppedIcmps ArpFilter"
" TW TWRecycled TWKilled"
......@@ -196,31 +194,37 @@ int netstat_get_info(char *buffer, char **start, off_t offset, int length)
" TCPAbortOnMemory TCPAbortOnTimeout TCPAbortOnLinger"
" TCPAbortFailed TCPMemoryPressures\n"
"TcpExt:");
for (i=0; i<offsetof(struct linux_mib, __pad)/sizeof(unsigned long); i++)
len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)net_statistics, sizeof(struct linux_mib), i));
len += sprintf (buffer + len, "\n");
for (i = 0;
i < offsetof(struct linux_mib, __pad) / sizeof(unsigned long);
i++)
seq_printf(seq, " %lu",
fold_field((unsigned long *)net_statistics,
sizeof(struct linux_mib), i));
seq_putc(seq, '\n');
return 0;
}
if (offset >= len)
{
*start = buffer;
return 0;
}
*start = buffer + offset;
len -= offset;
if (len > length)
len = length;
if (len < 0)
len = 0;
return len;
static int netstat_seq_open(struct inode *inode, struct file *file)
{
return single_open(file, netstat_seq_show, NULL);
}
static struct file_operations netstat_seq_fops = {
.open = netstat_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
int __init ip_misc_proc_init(void)
{
int rc = 0;
struct proc_dir_entry *p = create_proc_entry("netstat", S_IRUGO, proc_net);
if (!proc_net_create("netstat", 0, netstat_get_info))
if (!p)
goto out_netstat;
p->proc_fops = &netstat_seq_fops;
if (!proc_net_create("snmp", 0, snmp_get_info))
goto out_snmp;
if (!proc_net_create("sockstat", 0, afinet_get_info))
......@@ -230,7 +234,7 @@ int __init ip_misc_proc_init(void)
out_sockstat:
proc_net_remove("snmp");
out_snmp:
proc_net_remove("netstat");
remove_proc_entry("netstat", proc_net);
out_netstat:
rc = -ENOMEM;
goto out;
......
......@@ -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;
......
......@@ -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;
......
......@@ -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) {
......
#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 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
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;
......
......@@ -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 @@ void xfrm_state_flush(u8 proto)
}
}
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);
}
}
......
......@@ -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 @@ static int pfkey_sendmsg(struct kiocb *kiocb,
if (skb)
kfree_skb(skb);
return err;
return err ? : len;
}
static int pfkey_recvmsg(struct kiocb *kiocb,
......
......@@ -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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment