Commit e6e30add authored by David S. Miller's avatar David S. Miller

Merge branch 'net-next-2.6-misc-20080612a' of...

Merge branch 'net-next-2.6-misc-20080612a' of git://git.linux-ipv6.org/gitroot/yoshfuji/linux-2.6-next
parents d4c3c075 9501f972
...@@ -121,7 +121,8 @@ static inline int addrconf_finite_timeout(unsigned long timeout) ...@@ -121,7 +121,8 @@ static inline int addrconf_finite_timeout(unsigned long timeout)
*/ */
extern int ipv6_addr_label_init(void); extern int ipv6_addr_label_init(void);
extern void ipv6_addr_label_rtnl_register(void); extern void ipv6_addr_label_rtnl_register(void);
extern u32 ipv6_addr_label(const struct in6_addr *addr, extern u32 ipv6_addr_label(struct net *net,
const struct in6_addr *addr,
int type, int ifindex); int type, int ifindex);
/* /*
......
...@@ -148,7 +148,6 @@ struct ifacaddr6 ...@@ -148,7 +148,6 @@ struct ifacaddr6
#define IFA_HOST IPV6_ADDR_LOOPBACK #define IFA_HOST IPV6_ADDR_LOOPBACK
#define IFA_LINK IPV6_ADDR_LINKLOCAL #define IFA_LINK IPV6_ADDR_LINKLOCAL
#define IFA_SITE IPV6_ADDR_SITELOCAL #define IFA_SITE IPV6_ADDR_SITELOCAL
#define IFA_GLOBAL 0x0000U
struct ipv6_devstat { struct ipv6_devstat {
struct proc_dir_entry *proc_dir_entry; struct proc_dir_entry *proc_dir_entry;
......
...@@ -399,6 +399,8 @@ extern void tcp_parse_options(struct sk_buff *skb, ...@@ -399,6 +399,8 @@ extern void tcp_parse_options(struct sk_buff *skb,
struct tcp_options_received *opt_rx, struct tcp_options_received *opt_rx,
int estab); int estab);
extern u8 *tcp_parse_md5sig_option(struct tcphdr *th);
/* /*
* TCP v4 functions exported for the inet6 API * TCP v4 functions exported for the inet6 API
*/ */
...@@ -1115,13 +1117,19 @@ struct tcp_md5sig_pool { ...@@ -1115,13 +1117,19 @@ struct tcp_md5sig_pool {
#define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */ #define TCP_MD5SIG_MAXKEYS (~(u32)0) /* really?! */
/* - functions */ /* - functions */
extern int tcp_calc_md5_hash(char *md5_hash,
struct tcp_md5sig_key *key,
int bplen,
struct tcphdr *th,
unsigned int tcplen,
struct tcp_md5sig_pool *hp);
extern int tcp_v4_calc_md5_hash(char *md5_hash, extern int tcp_v4_calc_md5_hash(char *md5_hash,
struct tcp_md5sig_key *key, struct tcp_md5sig_key *key,
struct sock *sk, struct sock *sk,
struct dst_entry *dst, struct dst_entry *dst,
struct request_sock *req, struct request_sock *req,
struct tcphdr *th, struct tcphdr *th,
int protocol,
unsigned int tcplen); unsigned int tcplen);
extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk, extern struct tcp_md5sig_key *tcp_v4_md5_lookup(struct sock *sk,
struct sock *addr_sk); struct sock *addr_sk);
...@@ -1134,6 +1142,16 @@ extern int tcp_v4_md5_do_add(struct sock *sk, ...@@ -1134,6 +1142,16 @@ extern int tcp_v4_md5_do_add(struct sock *sk,
extern int tcp_v4_md5_do_del(struct sock *sk, extern int tcp_v4_md5_do_del(struct sock *sk,
__be32 addr); __be32 addr);
#ifdef CONFIG_TCP_MD5SIG
#define tcp_twsk_md5_key(twsk) ((twsk)->tw_md5_keylen ? \
&(struct tcp_md5sig_key) { \
.key = (twsk)->tw_md5_key, \
.keylen = (twsk)->tw_md5_keylen, \
} : NULL)
#else
#define tcp_twsk_md5_key(twsk) NULL
#endif
extern struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void); extern struct tcp_md5sig_pool **tcp_alloc_md5sig_pool(void);
extern void tcp_free_md5sig_pool(void); extern void tcp_free_md5sig_pool(void);
...@@ -1371,7 +1389,6 @@ struct tcp_sock_af_ops { ...@@ -1371,7 +1389,6 @@ struct tcp_sock_af_ops {
struct dst_entry *dst, struct dst_entry *dst,
struct request_sock *req, struct request_sock *req,
struct tcphdr *th, struct tcphdr *th,
int protocol,
unsigned int len); unsigned int len);
int (*md5_add) (struct sock *sk, int (*md5_add) (struct sock *sk,
struct sock *addr_sk, struct sock *addr_sk,
......
...@@ -2457,6 +2457,76 @@ static unsigned long tcp_md5sig_users; ...@@ -2457,6 +2457,76 @@ static unsigned long tcp_md5sig_users;
static struct tcp_md5sig_pool **tcp_md5sig_pool; static struct tcp_md5sig_pool **tcp_md5sig_pool;
static DEFINE_SPINLOCK(tcp_md5sig_pool_lock); static DEFINE_SPINLOCK(tcp_md5sig_pool_lock);
int tcp_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
int bplen,
struct tcphdr *th, unsigned int tcplen,
struct tcp_md5sig_pool *hp)
{
struct scatterlist sg[4];
__u16 data_len;
int block = 0;
__sum16 cksum;
struct hash_desc *desc = &hp->md5_desc;
int err;
unsigned int nbytes = 0;
sg_init_table(sg, 4);
/* 1. The TCP pseudo-header */
sg_set_buf(&sg[block++], &hp->md5_blk, bplen);
nbytes += bplen;
/* 2. The TCP header, excluding options, and assuming a
* checksum of zero
*/
cksum = th->check;
th->check = 0;
sg_set_buf(&sg[block++], th, sizeof(*th));
nbytes += sizeof(*th);
/* 3. The TCP segment data (if any) */
data_len = tcplen - (th->doff << 2);
if (data_len > 0) {
u8 *data = (u8 *)th + (th->doff << 2);
sg_set_buf(&sg[block++], data, data_len);
nbytes += data_len;
}
/* 4. an independently-specified key or password, known to both
* TCPs and presumably connection-specific
*/
sg_set_buf(&sg[block++], key->key, key->keylen);
nbytes += key->keylen;
sg_mark_end(&sg[block - 1]);
/* Now store the hash into the packet */
err = crypto_hash_init(desc);
if (err) {
if (net_ratelimit())
printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
return -1;
}
err = crypto_hash_update(desc, sg, nbytes);
if (err) {
if (net_ratelimit())
printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
return -1;
}
err = crypto_hash_final(desc, md5_hash);
if (err) {
if (net_ratelimit())
printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
return -1;
}
/* Reset header */
th->check = cksum;
return 0;
}
EXPORT_SYMBOL(tcp_calc_md5_hash);
static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool) static void __tcp_free_md5sig_pool(struct tcp_md5sig_pool **pool)
{ {
int cpu; int cpu;
......
...@@ -3448,6 +3448,43 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th, ...@@ -3448,6 +3448,43 @@ static int tcp_fast_parse_options(struct sk_buff *skb, struct tcphdr *th,
return 1; return 1;
} }
#ifdef CONFIG_TCP_MD5SIG
/*
* Parse MD5 Signature option
*/
u8 *tcp_parse_md5sig_option(struct tcphdr *th)
{
int length = (th->doff << 2) - sizeof (*th);
u8 *ptr = (u8*)(th + 1);
/* If the TCP option is too short, we can short cut */
if (length < TCPOLEN_MD5SIG)
return NULL;
while (length > 0) {
int opcode = *ptr++;
int opsize;
switch(opcode) {
case TCPOPT_EOL:
return NULL;
case TCPOPT_NOP:
length--;
continue;
default:
opsize = *ptr++;
if (opsize < 2 || opsize > length)
return NULL;
if (opcode == TCPOPT_MD5SIG)
return ptr;
}
ptr += opsize - 2;
length -= opsize;
}
return NULL;
}
#endif
static inline void tcp_store_ts_recent(struct tcp_sock *tp) static inline void tcp_store_ts_recent(struct tcp_sock *tp)
{ {
tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval; tp->rx_opt.ts_recent = tp->rx_opt.rcv_tsval;
...@@ -5465,6 +5502,9 @@ EXPORT_SYMBOL(sysctl_tcp_ecn); ...@@ -5465,6 +5502,9 @@ EXPORT_SYMBOL(sysctl_tcp_ecn);
EXPORT_SYMBOL(sysctl_tcp_reordering); EXPORT_SYMBOL(sysctl_tcp_reordering);
EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
EXPORT_SYMBOL(tcp_parse_options); EXPORT_SYMBOL(tcp_parse_options);
#ifdef CONFIG_TCP_MD5SIG
EXPORT_SYMBOL(tcp_parse_md5sig_option);
#endif
EXPORT_SYMBOL(tcp_rcv_established); EXPORT_SYMBOL(tcp_rcv_established);
EXPORT_SYMBOL(tcp_rcv_state_process); EXPORT_SYMBOL(tcp_rcv_state_process);
EXPORT_SYMBOL(tcp_initialize_rcv_mss); EXPORT_SYMBOL(tcp_initialize_rcv_mss);
...@@ -93,8 +93,13 @@ static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, ...@@ -93,8 +93,13 @@ static struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk,
__be32 addr); __be32 addr);
static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
__be32 saddr, __be32 daddr, __be32 saddr, __be32 daddr,
struct tcphdr *th, int protocol, struct tcphdr *th, unsigned int tcplen);
unsigned int tcplen); #else
static inline
struct tcp_md5sig_key *tcp_v4_md5_do_lookup(struct sock *sk, __be32 addr)
{
return NULL;
}
#endif #endif
struct inet_hashinfo __cacheline_aligned tcp_hashinfo = { struct inet_hashinfo __cacheline_aligned tcp_hashinfo = {
...@@ -584,8 +589,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) ...@@ -584,8 +589,7 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
key, key,
ip_hdr(skb)->daddr, ip_hdr(skb)->daddr,
ip_hdr(skb)->saddr, ip_hdr(skb)->saddr,
&rep.th, IPPROTO_TCP, &rep.th, arg.iov[0].iov_len);
arg.iov[0].iov_len);
} }
#endif #endif
arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
...@@ -604,9 +608,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb) ...@@ -604,9 +608,9 @@ static void tcp_v4_send_reset(struct sock *sk, struct sk_buff *skb)
outside socket context is ugly, certainly. What can I do? outside socket context is ugly, certainly. What can I do?
*/ */
static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, static void tcp_v4_send_ack(struct sk_buff *skb, u32 seq, u32 ack,
struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts, int oif,
u32 win, u32 ts) struct tcp_md5sig_key *key)
{ {
struct tcphdr *th = tcp_hdr(skb); struct tcphdr *th = tcp_hdr(skb);
struct { struct {
...@@ -618,10 +622,6 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, ...@@ -618,10 +622,6 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
]; ];
} rep; } rep;
struct ip_reply_arg arg; struct ip_reply_arg arg;
#ifdef CONFIG_TCP_MD5SIG
struct tcp_md5sig_key *key;
struct tcp_md5sig_key tw_key;
#endif
memset(&rep.th, 0, sizeof(struct tcphdr)); memset(&rep.th, 0, sizeof(struct tcphdr));
memset(&arg, 0, sizeof(arg)); memset(&arg, 0, sizeof(arg));
...@@ -647,23 +647,6 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, ...@@ -647,23 +647,6 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
rep.th.window = htons(win); rep.th.window = htons(win);
#ifdef CONFIG_TCP_MD5SIG #ifdef CONFIG_TCP_MD5SIG
/*
* The SKB holds an imcoming packet, but may not have a valid ->sk
* pointer. This is especially the case when we're dealing with a
* TIME_WAIT ack, because the sk structure is long gone, and only
* the tcp_timewait_sock remains. So the md5 key is stashed in that
* structure, and we use it in preference. I believe that (twsk ||
* skb->sk) holds true, but we program defensively.
*/
if (!twsk && skb->sk) {
key = tcp_v4_md5_do_lookup(skb->sk, ip_hdr(skb)->daddr);
} else if (twsk && twsk->tw_md5_keylen) {
tw_key.key = twsk->tw_md5_key;
tw_key.keylen = twsk->tw_md5_keylen;
key = &tw_key;
} else
key = NULL;
if (key) { if (key) {
int offset = (ts) ? 3 : 0; int offset = (ts) ? 3 : 0;
...@@ -678,16 +661,15 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk, ...@@ -678,16 +661,15 @@ static void tcp_v4_send_ack(struct tcp_timewait_sock *twsk,
key, key,
ip_hdr(skb)->daddr, ip_hdr(skb)->daddr,
ip_hdr(skb)->saddr, ip_hdr(skb)->saddr,
&rep.th, IPPROTO_TCP, &rep.th, arg.iov[0].iov_len);
arg.iov[0].iov_len);
} }
#endif #endif
arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr, arg.csum = csum_tcpudp_nofold(ip_hdr(skb)->daddr,
ip_hdr(skb)->saddr, /* XXX */ ip_hdr(skb)->saddr, /* XXX */
arg.iov[0].iov_len, IPPROTO_TCP, 0); arg.iov[0].iov_len, IPPROTO_TCP, 0);
arg.csumoffset = offsetof(struct tcphdr, check) / 2; arg.csumoffset = offsetof(struct tcphdr, check) / 2;
if (twsk) if (oif)
arg.bound_dev_if = twsk->tw_sk.tw_bound_dev_if; arg.bound_dev_if = oif;
ip_send_reply(dev_net(skb->dev)->ipv4.tcp_sock, skb, ip_send_reply(dev_net(skb->dev)->ipv4.tcp_sock, skb,
&arg, arg.iov[0].iov_len); &arg, arg.iov[0].iov_len);
...@@ -700,9 +682,12 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) ...@@ -700,9 +682,12 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
struct inet_timewait_sock *tw = inet_twsk(sk); struct inet_timewait_sock *tw = inet_twsk(sk);
struct tcp_timewait_sock *tcptw = tcp_twsk(sk); struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
tcp_v4_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcp_v4_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
tcptw->tw_ts_recent); tcptw->tw_ts_recent,
tw->tw_bound_dev_if,
tcp_twsk_md5_key(tcptw)
);
inet_twsk_put(tw); inet_twsk_put(tw);
} }
...@@ -710,9 +695,11 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb) ...@@ -710,9 +695,11 @@ static void tcp_v4_timewait_ack(struct sock *sk, struct sk_buff *skb)
static void tcp_v4_reqsk_send_ack(struct sk_buff *skb, static void tcp_v4_reqsk_send_ack(struct sk_buff *skb,
struct request_sock *req) struct request_sock *req)
{ {
tcp_v4_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_v4_send_ack(skb, tcp_rsk(req)->snt_isn + 1,
tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd,
req->ts_recent); req->ts_recent,
0,
tcp_v4_md5_do_lookup(skb->sk, ip_hdr(skb)->daddr));
} }
/* /*
...@@ -1004,18 +991,12 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval, ...@@ -1004,18 +991,12 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, char __user *optval,
static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
__be32 saddr, __be32 daddr, __be32 saddr, __be32 daddr,
struct tcphdr *th, int protocol, struct tcphdr *th,
unsigned int tcplen) unsigned int tcplen)
{ {
struct scatterlist sg[4];
__u16 data_len;
int block = 0;
__sum16 old_checksum;
struct tcp_md5sig_pool *hp; struct tcp_md5sig_pool *hp;
struct tcp4_pseudohdr *bp; struct tcp4_pseudohdr *bp;
struct hash_desc *desc;
int err; int err;
unsigned int nbytes = 0;
/* /*
* Okay, so RFC2385 is turned on for this connection, * Okay, so RFC2385 is turned on for this connection,
...@@ -1027,63 +1008,25 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, ...@@ -1027,63 +1008,25 @@ static int tcp_v4_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
goto clear_hash_noput; goto clear_hash_noput;
bp = &hp->md5_blk.ip4; bp = &hp->md5_blk.ip4;
desc = &hp->md5_desc;
/* /*
* 1. the TCP pseudo-header (in the order: source IP address, * The TCP pseudo-header (in the order: source IP address,
* destination IP address, zero-padded protocol number, and * destination IP address, zero-padded protocol number, and
* segment length) * segment length)
*/ */
bp->saddr = saddr; bp->saddr = saddr;
bp->daddr = daddr; bp->daddr = daddr;
bp->pad = 0; bp->pad = 0;
bp->protocol = protocol; bp->protocol = IPPROTO_TCP;
bp->len = htons(tcplen); bp->len = htons(tcplen);
sg_init_table(sg, 4); err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp),
th, tcplen, hp);
sg_set_buf(&sg[block++], bp, sizeof(*bp));
nbytes += sizeof(*bp);
/* 2. the TCP header, excluding options, and assuming a
* checksum of zero/
*/
old_checksum = th->check;
th->check = 0;
sg_set_buf(&sg[block++], th, sizeof(struct tcphdr));
nbytes += sizeof(struct tcphdr);
/* 3. the TCP segment data (if any) */
data_len = tcplen - (th->doff << 2);
if (data_len > 0) {
unsigned char *data = (unsigned char *)th + (th->doff << 2);
sg_set_buf(&sg[block++], data, data_len);
nbytes += data_len;
}
/* 4. an independently-specified key or password, known to both
* TCPs and presumably connection-specific
*/
sg_set_buf(&sg[block++], key->key, key->keylen);
nbytes += key->keylen;
sg_mark_end(&sg[block - 1]);
/* Now store the Hash into the packet */
err = crypto_hash_init(desc);
if (err)
goto clear_hash;
err = crypto_hash_update(desc, sg, nbytes);
if (err)
goto clear_hash;
err = crypto_hash_final(desc, md5_hash);
if (err) if (err)
goto clear_hash; goto clear_hash;
/* Reset header, and free up the crypto */ /* Free up the crypto pool */
tcp_put_md5sig_pool(); tcp_put_md5sig_pool();
th->check = old_checksum;
out: out:
return 0; return 0;
clear_hash: clear_hash:
...@@ -1097,7 +1040,7 @@ int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, ...@@ -1097,7 +1040,7 @@ int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
struct sock *sk, struct sock *sk,
struct dst_entry *dst, struct dst_entry *dst,
struct request_sock *req, struct request_sock *req,
struct tcphdr *th, int protocol, struct tcphdr *th,
unsigned int tcplen) unsigned int tcplen)
{ {
__be32 saddr, daddr; __be32 saddr, daddr;
...@@ -1113,7 +1056,7 @@ int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, ...@@ -1113,7 +1056,7 @@ int tcp_v4_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
} }
return tcp_v4_do_calc_md5_hash(md5_hash, key, return tcp_v4_do_calc_md5_hash(md5_hash, key,
saddr, daddr, saddr, daddr,
th, protocol, tcplen); th, tcplen);
} }
EXPORT_SYMBOL(tcp_v4_calc_md5_hash); EXPORT_SYMBOL(tcp_v4_calc_md5_hash);
...@@ -1132,52 +1075,12 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) ...@@ -1132,52 +1075,12 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
struct tcp_md5sig_key *hash_expected; struct tcp_md5sig_key *hash_expected;
const struct iphdr *iph = ip_hdr(skb); const struct iphdr *iph = ip_hdr(skb);
struct tcphdr *th = tcp_hdr(skb); struct tcphdr *th = tcp_hdr(skb);
int length = (th->doff << 2) - sizeof(struct tcphdr);
int genhash; int genhash;
unsigned char *ptr;
unsigned char newhash[16]; unsigned char newhash[16];
hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr); hash_expected = tcp_v4_md5_do_lookup(sk, iph->saddr);
hash_location = tcp_parse_md5sig_option(th);
/*
* If the TCP option length is less than the TCP_MD5SIG
* option length, then we can shortcut
*/
if (length < TCPOLEN_MD5SIG) {
if (hash_expected)
return 1;
else
return 0;
}
/* Okay, we can't shortcut - we have to grub through the options */
ptr = (unsigned char *)(th + 1);
while (length > 0) {
int opcode = *ptr++;
int opsize;
switch (opcode) {
case TCPOPT_EOL:
goto done_opts;
case TCPOPT_NOP:
length--;
continue;
default:
opsize = *ptr++;
if (opsize < 2)
goto done_opts;
if (opsize > length)
goto done_opts;
if (opcode == TCPOPT_MD5SIG) {
hash_location = ptr;
goto done_opts;
}
}
ptr += opsize-2;
length -= opsize;
}
done_opts:
/* We've parsed the options - do we have a hash? */ /* We've parsed the options - do we have a hash? */
if (!hash_expected && !hash_location) if (!hash_expected && !hash_location)
return 0; return 0;
...@@ -1204,8 +1107,7 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb) ...@@ -1204,8 +1107,7 @@ static int tcp_v4_inbound_md5_hash(struct sock *sk, struct sk_buff *skb)
genhash = tcp_v4_do_calc_md5_hash(newhash, genhash = tcp_v4_do_calc_md5_hash(newhash,
hash_expected, hash_expected,
iph->saddr, iph->daddr, iph->saddr, iph->daddr,
th, sk->sk_protocol, th, skb->len);
skb->len);
if (genhash || memcmp(hash_location, newhash, 16) != 0) { if (genhash || memcmp(hash_location, newhash, 16) != 0) {
if (net_ratelimit()) { if (net_ratelimit()) {
......
...@@ -605,7 +605,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it, ...@@ -605,7 +605,6 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
md5, md5,
sk, NULL, NULL, sk, NULL, NULL,
tcp_hdr(skb), tcp_hdr(skb),
sk->sk_protocol,
skb->len); skb->len);
} }
#endif #endif
...@@ -2264,7 +2263,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst, ...@@ -2264,7 +2263,7 @@ struct sk_buff *tcp_make_synack(struct sock *sk, struct dst_entry *dst,
tp->af_specific->calc_md5_hash(md5_hash_location, tp->af_specific->calc_md5_hash(md5_hash_location,
md5, md5,
NULL, dst, req, NULL, dst, req,
tcp_hdr(skb), sk->sk_protocol, tcp_hdr(skb),
skb->len); skb->len);
} }
#endif #endif
......
...@@ -229,6 +229,12 @@ static inline int addrconf_qdisc_ok(struct net_device *dev) ...@@ -229,6 +229,12 @@ static inline int addrconf_qdisc_ok(struct net_device *dev)
return (dev->qdisc != &noop_qdisc); return (dev->qdisc != &noop_qdisc);
} }
/* Check if a route is valid prefix route */
static inline int addrconf_is_prefix_route(const struct rt6_info *rt)
{
return ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0);
}
static void addrconf_del_timer(struct inet6_ifaddr *ifp) static void addrconf_del_timer(struct inet6_ifaddr *ifp)
{ {
if (del_timer(&ifp->timer)) if (del_timer(&ifp->timer))
...@@ -775,7 +781,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) ...@@ -775,7 +781,7 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len); ipv6_addr_prefix(&prefix, &ifp->addr, ifp->prefix_len);
rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1); rt = rt6_lookup(net, &prefix, NULL, ifp->idev->dev->ifindex, 1);
if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { if (rt && addrconf_is_prefix_route(rt)) {
if (onlink == 0) { if (onlink == 0) {
ip6_del_rt(rt); ip6_del_rt(rt);
rt = NULL; rt = NULL;
...@@ -956,7 +962,8 @@ static inline int ipv6_saddr_preferred(int type) ...@@ -956,7 +962,8 @@ static inline int ipv6_saddr_preferred(int type)
return 0; return 0;
} }
static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score, static int ipv6_get_saddr_eval(struct net *net,
struct ipv6_saddr_score *score,
struct ipv6_saddr_dst *dst, struct ipv6_saddr_dst *dst,
int i) int i)
{ {
...@@ -1035,7 +1042,8 @@ static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score, ...@@ -1035,7 +1042,8 @@ static int ipv6_get_saddr_eval(struct ipv6_saddr_score *score,
break; break;
case IPV6_SADDR_RULE_LABEL: case IPV6_SADDR_RULE_LABEL:
/* Rule 6: Prefer matching label */ /* Rule 6: Prefer matching label */
ret = ipv6_addr_label(&score->ifa->addr, score->addr_type, ret = ipv6_addr_label(net,
&score->ifa->addr, score->addr_type,
score->ifa->idev->dev->ifindex) == dst->label; score->ifa->idev->dev->ifindex) == dst->label;
break; break;
#ifdef CONFIG_IPV6_PRIVACY #ifdef CONFIG_IPV6_PRIVACY
...@@ -1089,7 +1097,7 @@ int ipv6_dev_get_saddr(struct net_device *dst_dev, ...@@ -1089,7 +1097,7 @@ int ipv6_dev_get_saddr(struct net_device *dst_dev,
dst.addr = daddr; dst.addr = daddr;
dst.ifindex = dst_dev ? dst_dev->ifindex : 0; dst.ifindex = dst_dev ? dst_dev->ifindex : 0;
dst.scope = __ipv6_addr_src_scope(dst_type); dst.scope = __ipv6_addr_src_scope(dst_type);
dst.label = ipv6_addr_label(daddr, dst_type, dst.ifindex); dst.label = ipv6_addr_label(net, daddr, dst_type, dst.ifindex);
dst.prefs = prefs; dst.prefs = prefs;
hiscore->rule = -1; hiscore->rule = -1;
...@@ -1157,8 +1165,8 @@ int ipv6_dev_get_saddr(struct net_device *dst_dev, ...@@ -1157,8 +1165,8 @@ int ipv6_dev_get_saddr(struct net_device *dst_dev,
for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) { for (i = 0; i < IPV6_SADDR_RULE_MAX; i++) {
int minihiscore, miniscore; int minihiscore, miniscore;
minihiscore = ipv6_get_saddr_eval(hiscore, &dst, i); minihiscore = ipv6_get_saddr_eval(net, hiscore, &dst, i);
miniscore = ipv6_get_saddr_eval(score, &dst, i); miniscore = ipv6_get_saddr_eval(net, score, &dst, i);
if (minihiscore > miniscore) { if (minihiscore > miniscore) {
if (i == IPV6_SADDR_RULE_SCOPE && if (i == IPV6_SADDR_RULE_SCOPE &&
...@@ -1786,7 +1794,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) ...@@ -1786,7 +1794,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL, rt = rt6_lookup(dev_net(dev), &pinfo->prefix, NULL,
dev->ifindex, 1); dev->ifindex, 1);
if (rt && ((rt->rt6i_flags & (RTF_GATEWAY | RTF_DEFAULT)) == 0)) { if (rt && addrconf_is_prefix_route(rt)) {
/* Autoconf prefix route */ /* Autoconf prefix route */
if (valid_lft == 0) { if (valid_lft == 0) {
ip6_del_rt(rt); ip6_del_rt(rt);
......
...@@ -29,6 +29,9 @@ ...@@ -29,6 +29,9 @@
*/ */
struct ip6addrlbl_entry struct ip6addrlbl_entry
{ {
#ifdef CONFIG_NET_NS
struct net *lbl_net;
#endif
struct in6_addr prefix; struct in6_addr prefix;
int prefixlen; int prefixlen;
int ifindex; int ifindex;
...@@ -46,6 +49,16 @@ static struct ip6addrlbl_table ...@@ -46,6 +49,16 @@ static struct ip6addrlbl_table
u32 seq; u32 seq;
} ip6addrlbl_table; } ip6addrlbl_table;
static inline
struct net *ip6addrlbl_net(const struct ip6addrlbl_entry *lbl)
{
#ifdef CONFIG_NET_NS
return lbl->lbl_net;
#else
return &init_net;
#endif
}
/* /*
* Default policy table (RFC3484 + extensions) * Default policy table (RFC3484 + extensions)
* *
...@@ -65,7 +78,7 @@ static struct ip6addrlbl_table ...@@ -65,7 +78,7 @@ static struct ip6addrlbl_table
#define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL #define IPV6_ADDR_LABEL_DEFAULT 0xffffffffUL
static const __initdata struct ip6addrlbl_init_table static const __net_initdata struct ip6addrlbl_init_table
{ {
const struct in6_addr *prefix; const struct in6_addr *prefix;
int prefixlen; int prefixlen;
...@@ -108,6 +121,9 @@ static const __initdata struct ip6addrlbl_init_table ...@@ -108,6 +121,9 @@ static const __initdata struct ip6addrlbl_init_table
/* Object management */ /* Object management */
static inline void ip6addrlbl_free(struct ip6addrlbl_entry *p) static inline void ip6addrlbl_free(struct ip6addrlbl_entry *p)
{ {
#ifdef CONFIG_NET_NS
release_net(p->lbl_net);
#endif
kfree(p); kfree(p);
} }
...@@ -128,10 +144,13 @@ static inline void ip6addrlbl_put(struct ip6addrlbl_entry *p) ...@@ -128,10 +144,13 @@ static inline void ip6addrlbl_put(struct ip6addrlbl_entry *p)
} }
/* Find label */ /* Find label */
static int __ip6addrlbl_match(struct ip6addrlbl_entry *p, static int __ip6addrlbl_match(struct net *net,
struct ip6addrlbl_entry *p,
const struct in6_addr *addr, const struct in6_addr *addr,
int addrtype, int ifindex) int addrtype, int ifindex)
{ {
if (!net_eq(ip6addrlbl_net(p), net))
return 0;
if (p->ifindex && p->ifindex != ifindex) if (p->ifindex && p->ifindex != ifindex)
return 0; return 0;
if (p->addrtype && p->addrtype != addrtype) if (p->addrtype && p->addrtype != addrtype)
...@@ -141,19 +160,21 @@ static int __ip6addrlbl_match(struct ip6addrlbl_entry *p, ...@@ -141,19 +160,21 @@ static int __ip6addrlbl_match(struct ip6addrlbl_entry *p,
return 1; return 1;
} }
static struct ip6addrlbl_entry *__ipv6_addr_label(const struct in6_addr *addr, static struct ip6addrlbl_entry *__ipv6_addr_label(struct net *net,
const struct in6_addr *addr,
int type, int ifindex) int type, int ifindex)
{ {
struct hlist_node *pos; struct hlist_node *pos;
struct ip6addrlbl_entry *p; struct ip6addrlbl_entry *p;
hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) { hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
if (__ip6addrlbl_match(p, addr, type, ifindex)) if (__ip6addrlbl_match(net, p, addr, type, ifindex))
return p; return p;
} }
return NULL; return NULL;
} }
u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex) u32 ipv6_addr_label(struct net *net,
const struct in6_addr *addr, int type, int ifindex)
{ {
u32 label; u32 label;
struct ip6addrlbl_entry *p; struct ip6addrlbl_entry *p;
...@@ -161,7 +182,7 @@ u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex) ...@@ -161,7 +182,7 @@ u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex)
type &= IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK; type &= IPV6_ADDR_MAPPED | IPV6_ADDR_COMPATv4 | IPV6_ADDR_LOOPBACK;
rcu_read_lock(); rcu_read_lock();
p = __ipv6_addr_label(addr, type, ifindex); p = __ipv6_addr_label(net, addr, type, ifindex);
label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT; label = p ? p->label : IPV6_ADDR_LABEL_DEFAULT;
rcu_read_unlock(); rcu_read_unlock();
...@@ -174,7 +195,8 @@ u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex) ...@@ -174,7 +195,8 @@ u32 ipv6_addr_label(const struct in6_addr *addr, int type, int ifindex)
} }
/* allocate one entry */ /* allocate one entry */
static struct ip6addrlbl_entry *ip6addrlbl_alloc(const struct in6_addr *prefix, static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net,
const struct in6_addr *prefix,
int prefixlen, int ifindex, int prefixlen, int ifindex,
u32 label) u32 label)
{ {
...@@ -216,6 +238,9 @@ static struct ip6addrlbl_entry *ip6addrlbl_alloc(const struct in6_addr *prefix, ...@@ -216,6 +238,9 @@ static struct ip6addrlbl_entry *ip6addrlbl_alloc(const struct in6_addr *prefix,
newp->addrtype = addrtype; newp->addrtype = addrtype;
newp->label = label; newp->label = label;
INIT_HLIST_NODE(&newp->list); INIT_HLIST_NODE(&newp->list);
#ifdef CONFIG_NET_NS
newp->lbl_net = hold_net(net);
#endif
atomic_set(&newp->refcnt, 1); atomic_set(&newp->refcnt, 1);
return newp; return newp;
} }
...@@ -237,6 +262,7 @@ static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace) ...@@ -237,6 +262,7 @@ static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace)
hlist_for_each_entry_safe(p, pos, n, hlist_for_each_entry_safe(p, pos, n,
&ip6addrlbl_table.head, list) { &ip6addrlbl_table.head, list) {
if (p->prefixlen == newp->prefixlen && if (p->prefixlen == newp->prefixlen &&
net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) &&
p->ifindex == newp->ifindex && p->ifindex == newp->ifindex &&
ipv6_addr_equal(&p->prefix, &newp->prefix)) { ipv6_addr_equal(&p->prefix, &newp->prefix)) {
if (!replace) { if (!replace) {
...@@ -261,7 +287,8 @@ static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace) ...@@ -261,7 +287,8 @@ static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace)
} }
/* add a label */ /* add a label */
static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen, static int ip6addrlbl_add(struct net *net,
const struct in6_addr *prefix, int prefixlen,
int ifindex, u32 label, int replace) int ifindex, u32 label, int replace)
{ {
struct ip6addrlbl_entry *newp; struct ip6addrlbl_entry *newp;
...@@ -274,7 +301,7 @@ static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen, ...@@ -274,7 +301,7 @@ static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen,
(unsigned int)label, (unsigned int)label,
replace); replace);
newp = ip6addrlbl_alloc(prefix, prefixlen, ifindex, label); newp = ip6addrlbl_alloc(net, prefix, prefixlen, ifindex, label);
if (IS_ERR(newp)) if (IS_ERR(newp))
return PTR_ERR(newp); return PTR_ERR(newp);
spin_lock(&ip6addrlbl_table.lock); spin_lock(&ip6addrlbl_table.lock);
...@@ -286,7 +313,8 @@ static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen, ...@@ -286,7 +313,8 @@ static int ip6addrlbl_add(const struct in6_addr *prefix, int prefixlen,
} }
/* remove a label */ /* remove a label */
static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen, static int __ip6addrlbl_del(struct net *net,
const struct in6_addr *prefix, int prefixlen,
int ifindex) int ifindex)
{ {
struct ip6addrlbl_entry *p = NULL; struct ip6addrlbl_entry *p = NULL;
...@@ -300,6 +328,7 @@ static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen, ...@@ -300,6 +328,7 @@ static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) { hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
if (p->prefixlen == prefixlen && if (p->prefixlen == prefixlen &&
net_eq(ip6addrlbl_net(p), net) &&
p->ifindex == ifindex && p->ifindex == ifindex &&
ipv6_addr_equal(&p->prefix, prefix)) { ipv6_addr_equal(&p->prefix, prefix)) {
hlist_del_rcu(&p->list); hlist_del_rcu(&p->list);
...@@ -311,7 +340,8 @@ static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen, ...@@ -311,7 +340,8 @@ static int __ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
return ret; return ret;
} }
static int ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen, static int ip6addrlbl_del(struct net *net,
const struct in6_addr *prefix, int prefixlen,
int ifindex) int ifindex)
{ {
struct in6_addr prefix_buf; struct in6_addr prefix_buf;
...@@ -324,13 +354,13 @@ static int ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen, ...@@ -324,13 +354,13 @@ static int ip6addrlbl_del(const struct in6_addr *prefix, int prefixlen,
ipv6_addr_prefix(&prefix_buf, prefix, prefixlen); ipv6_addr_prefix(&prefix_buf, prefix, prefixlen);
spin_lock(&ip6addrlbl_table.lock); spin_lock(&ip6addrlbl_table.lock);
ret = __ip6addrlbl_del(&prefix_buf, prefixlen, ifindex); ret = __ip6addrlbl_del(net, &prefix_buf, prefixlen, ifindex);
spin_unlock(&ip6addrlbl_table.lock); spin_unlock(&ip6addrlbl_table.lock);
return ret; return ret;
} }
/* add default label */ /* add default label */
static __init int ip6addrlbl_init(void) static int __net_init ip6addrlbl_net_init(struct net *net)
{ {
int err = 0; int err = 0;
int i; int i;
...@@ -338,7 +368,8 @@ static __init int ip6addrlbl_init(void) ...@@ -338,7 +368,8 @@ static __init int ip6addrlbl_init(void)
ADDRLABEL(KERN_DEBUG "%s()\n", __func__); ADDRLABEL(KERN_DEBUG "%s()\n", __func__);
for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) { for (i = 0; i < ARRAY_SIZE(ip6addrlbl_init_table); i++) {
int ret = ip6addrlbl_add(ip6addrlbl_init_table[i].prefix, int ret = ip6addrlbl_add(net,
ip6addrlbl_init_table[i].prefix,
ip6addrlbl_init_table[i].prefixlen, ip6addrlbl_init_table[i].prefixlen,
0, 0,
ip6addrlbl_init_table[i].label, 0); ip6addrlbl_init_table[i].label, 0);
...@@ -349,11 +380,32 @@ static __init int ip6addrlbl_init(void) ...@@ -349,11 +380,32 @@ static __init int ip6addrlbl_init(void)
return err; return err;
} }
static void __net_exit ip6addrlbl_net_exit(struct net *net)
{
struct ip6addrlbl_entry *p = NULL;
struct hlist_node *pos, *n;
/* Remove all labels belonging to the exiting net */
spin_lock(&ip6addrlbl_table.lock);
hlist_for_each_entry_safe(p, pos, n, &ip6addrlbl_table.head, list) {
if (net_eq(ip6addrlbl_net(p), net)) {
hlist_del_rcu(&p->list);
ip6addrlbl_put(p);
}
}
spin_unlock(&ip6addrlbl_table.lock);
}
static struct pernet_operations ipv6_addr_label_ops = {
.init = ip6addrlbl_net_init,
.exit = ip6addrlbl_net_exit,
};
int __init ipv6_addr_label_init(void) int __init ipv6_addr_label_init(void)
{ {
spin_lock_init(&ip6addrlbl_table.lock); spin_lock_init(&ip6addrlbl_table.lock);
return ip6addrlbl_init(); return register_pernet_subsys(&ipv6_addr_label_ops);
} }
static const struct nla_policy ifal_policy[IFAL_MAX+1] = { static const struct nla_policy ifal_policy[IFAL_MAX+1] = {
...@@ -371,9 +423,6 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -371,9 +423,6 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
u32 label; u32 label;
int err = 0; int err = 0;
if (net != &init_net)
return 0;
err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy); err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
if (err < 0) if (err < 0)
return err; return err;
...@@ -385,7 +434,7 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -385,7 +434,7 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
return -EINVAL; return -EINVAL;
if (ifal->ifal_index && if (ifal->ifal_index &&
!__dev_get_by_index(&init_net, ifal->ifal_index)) !__dev_get_by_index(net, ifal->ifal_index))
return -EINVAL; return -EINVAL;
if (!tb[IFAL_ADDRESS]) if (!tb[IFAL_ADDRESS])
...@@ -403,12 +452,12 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -403,12 +452,12 @@ static int ip6addrlbl_newdel(struct sk_buff *skb, struct nlmsghdr *nlh,
switch(nlh->nlmsg_type) { switch(nlh->nlmsg_type) {
case RTM_NEWADDRLABEL: case RTM_NEWADDRLABEL:
err = ip6addrlbl_add(pfx, ifal->ifal_prefixlen, err = ip6addrlbl_add(net, pfx, ifal->ifal_prefixlen,
ifal->ifal_index, label, ifal->ifal_index, label,
nlh->nlmsg_flags & NLM_F_REPLACE); nlh->nlmsg_flags & NLM_F_REPLACE);
break; break;
case RTM_DELADDRLABEL: case RTM_DELADDRLABEL:
err = ip6addrlbl_del(pfx, ifal->ifal_prefixlen, err = ip6addrlbl_del(net, pfx, ifal->ifal_prefixlen,
ifal->ifal_index); ifal->ifal_index);
break; break;
default: default:
...@@ -458,12 +507,10 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -458,12 +507,10 @@ static int ip6addrlbl_dump(struct sk_buff *skb, struct netlink_callback *cb)
int idx = 0, s_idx = cb->args[0]; int idx = 0, s_idx = cb->args[0];
int err; int err;
if (net != &init_net)
return 0;
rcu_read_lock(); rcu_read_lock();
hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) { hlist_for_each_entry_rcu(p, pos, &ip6addrlbl_table.head, list) {
if (idx >= s_idx) { if (idx >= s_idx &&
net_eq(ip6addrlbl_net(p), net)) {
if ((err = ip6addrlbl_fill(skb, p, if ((err = ip6addrlbl_fill(skb, p,
ip6addrlbl_table.seq, ip6addrlbl_table.seq,
NETLINK_CB(cb->skb).pid, NETLINK_CB(cb->skb).pid,
...@@ -499,9 +546,6 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, ...@@ -499,9 +546,6 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
struct ip6addrlbl_entry *p; struct ip6addrlbl_entry *p;
struct sk_buff *skb; struct sk_buff *skb;
if (net != &init_net)
return 0;
err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy); err = nlmsg_parse(nlh, sizeof(*ifal), tb, IFAL_MAX, ifal_policy);
if (err < 0) if (err < 0)
return err; return err;
...@@ -513,7 +557,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, ...@@ -513,7 +557,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
return -EINVAL; return -EINVAL;
if (ifal->ifal_index && if (ifal->ifal_index &&
!__dev_get_by_index(&init_net, ifal->ifal_index)) !__dev_get_by_index(net, ifal->ifal_index))
return -EINVAL; return -EINVAL;
if (!tb[IFAL_ADDRESS]) if (!tb[IFAL_ADDRESS])
...@@ -524,7 +568,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, ...@@ -524,7 +568,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
return -EINVAL; return -EINVAL;
rcu_read_lock(); rcu_read_lock();
p = __ipv6_addr_label(addr, ipv6_addr_type(addr), ifal->ifal_index); p = __ipv6_addr_label(net, addr, ipv6_addr_type(addr), ifal->ifal_index);
if (p && ip6addrlbl_hold(p)) if (p && ip6addrlbl_hold(p))
p = NULL; p = NULL;
lseq = ip6addrlbl_table.seq; lseq = ip6addrlbl_table.seq;
...@@ -552,7 +596,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh, ...@@ -552,7 +596,7 @@ static int ip6addrlbl_get(struct sk_buff *in_skb, struct nlmsghdr* nlh,
goto out; goto out;
} }
err = rtnl_unicast(skb, &init_net, NETLINK_CB(in_skb).pid); err = rtnl_unicast(skb, net, NETLINK_CB(in_skb).pid);
out: out:
return err; return err;
} }
......
...@@ -1240,7 +1240,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int ...@@ -1240,7 +1240,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
#endif #endif
/* /*
* Spurious command, or MRT_VERSION which you cannot * Spurious command, or MRT6_VERSION which you cannot
* set. * set.
*/ */
default: default:
......
...@@ -162,7 +162,6 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, ...@@ -162,7 +162,6 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \ ((MLDV2_MASK(value, nbmant) | (1<<(nbmant))) << \
(MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp)))) (MLDV2_MASK((value) >> (nbmant), nbexp) + (nbexp))))
#define MLDV2_QQIC(value) MLDV2_EXP(0x80, 4, 3, value)
#define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value) #define MLDV2_MRC(value) MLDV2_EXP(0x8000, 12, 3, value)
#define IPV6_MLD_MAX_MSF 64 #define IPV6_MLD_MAX_MSF 64
......
...@@ -80,6 +80,12 @@ static struct inet_connection_sock_af_ops ipv6_specific; ...@@ -80,6 +80,12 @@ static struct inet_connection_sock_af_ops ipv6_specific;
#ifdef CONFIG_TCP_MD5SIG #ifdef CONFIG_TCP_MD5SIG
static struct tcp_sock_af_ops tcp_sock_ipv6_specific; static struct tcp_sock_af_ops tcp_sock_ipv6_specific;
static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific; static struct tcp_sock_af_ops tcp_sock_ipv6_mapped_specific;
#else
static struct tcp_md5sig_key *tcp_v6_md5_do_lookup(struct sock *sk,
struct in6_addr *addr)
{
return NULL;
}
#endif #endif
static void tcp_v6_hash(struct sock *sk) static void tcp_v6_hash(struct sock *sk)
...@@ -734,78 +740,34 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval, ...@@ -734,78 +740,34 @@ static int tcp_v6_parse_md5_keys (struct sock *sk, char __user *optval,
static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, static int tcp_v6_do_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
struct in6_addr *saddr, struct in6_addr *saddr,
struct in6_addr *daddr, struct in6_addr *daddr,
struct tcphdr *th, int protocol, struct tcphdr *th, unsigned int tcplen)
unsigned int tcplen)
{ {
struct scatterlist sg[4];
__u16 data_len;
int block = 0;
__sum16 cksum;
struct tcp_md5sig_pool *hp; struct tcp_md5sig_pool *hp;
struct tcp6_pseudohdr *bp; struct tcp6_pseudohdr *bp;
struct hash_desc *desc;
int err; int err;
unsigned int nbytes = 0;
hp = tcp_get_md5sig_pool(); hp = tcp_get_md5sig_pool();
if (!hp) { if (!hp) {
printk(KERN_WARNING "%s(): hash pool not found...\n", __func__); printk(KERN_WARNING "%s(): hash pool not found...\n", __func__);
goto clear_hash_noput; goto clear_hash_noput;
} }
bp = &hp->md5_blk.ip6; bp = &hp->md5_blk.ip6;
desc = &hp->md5_desc;
/* 1. TCP pseudo-header (RFC2460) */ /* 1. TCP pseudo-header (RFC2460) */
ipv6_addr_copy(&bp->saddr, saddr); ipv6_addr_copy(&bp->saddr, saddr);
ipv6_addr_copy(&bp->daddr, daddr); ipv6_addr_copy(&bp->daddr, daddr);
bp->len = htonl(tcplen); bp->len = htonl(tcplen);
bp->protocol = htonl(protocol); bp->protocol = htonl(IPPROTO_TCP);
sg_init_table(sg, 4);
sg_set_buf(&sg[block++], bp, sizeof(*bp)); err = tcp_calc_md5_hash(md5_hash, key, sizeof(*bp),
nbytes += sizeof(*bp); th, tcplen, hp);
/* 2. TCP header, excluding options */ if (err)
cksum = th->check;
th->check = 0;
sg_set_buf(&sg[block++], th, sizeof(*th));
nbytes += sizeof(*th);
/* 3. TCP segment data (if any) */
data_len = tcplen - (th->doff << 2);
if (data_len > 0) {
u8 *data = (u8 *)th + (th->doff << 2);
sg_set_buf(&sg[block++], data, data_len);
nbytes += data_len;
}
/* 4. shared key */
sg_set_buf(&sg[block++], key->key, key->keylen);
nbytes += key->keylen;
sg_mark_end(&sg[block - 1]);
/* Now store the hash into the packet */
err = crypto_hash_init(desc);
if (err) {
printk(KERN_WARNING "%s(): hash_init failed\n", __func__);
goto clear_hash;
}
err = crypto_hash_update(desc, sg, nbytes);
if (err) {
printk(KERN_WARNING "%s(): hash_update failed\n", __func__);
goto clear_hash;
}
err = crypto_hash_final(desc, md5_hash);
if (err) {
printk(KERN_WARNING "%s(): hash_final failed\n", __func__);
goto clear_hash; goto clear_hash;
}
/* Reset header, and free up the crypto */ /* Free up the crypto pool */
tcp_put_md5sig_pool(); tcp_put_md5sig_pool();
th->check = cksum;
out: out:
return 0; return 0;
clear_hash: clear_hash:
...@@ -819,8 +781,7 @@ static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, ...@@ -819,8 +781,7 @@ static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
struct sock *sk, struct sock *sk,
struct dst_entry *dst, struct dst_entry *dst,
struct request_sock *req, struct request_sock *req,
struct tcphdr *th, int protocol, struct tcphdr *th, unsigned int tcplen)
unsigned int tcplen)
{ {
struct in6_addr *saddr, *daddr; struct in6_addr *saddr, *daddr;
...@@ -833,7 +794,7 @@ static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key, ...@@ -833,7 +794,7 @@ static int tcp_v6_calc_md5_hash(char *md5_hash, struct tcp_md5sig_key *key,
} }
return tcp_v6_do_calc_md5_hash(md5_hash, key, return tcp_v6_do_calc_md5_hash(md5_hash, key,
saddr, daddr, saddr, daddr,
th, protocol, tcplen); th, tcplen);
} }
static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
...@@ -842,43 +803,12 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) ...@@ -842,43 +803,12 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
struct tcp_md5sig_key *hash_expected; struct tcp_md5sig_key *hash_expected;
struct ipv6hdr *ip6h = ipv6_hdr(skb); struct ipv6hdr *ip6h = ipv6_hdr(skb);
struct tcphdr *th = tcp_hdr(skb); struct tcphdr *th = tcp_hdr(skb);
int length = (th->doff << 2) - sizeof (*th);
int genhash; int genhash;
u8 *ptr;
u8 newhash[16]; u8 newhash[16];
hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr); hash_expected = tcp_v6_md5_do_lookup(sk, &ip6h->saddr);
hash_location = tcp_parse_md5sig_option(th);
/* If the TCP option is too short, we can short cut */
if (length < TCPOLEN_MD5SIG)
return hash_expected ? 1 : 0;
/* parse options */
ptr = (u8*)(th + 1);
while (length > 0) {
int opcode = *ptr++;
int opsize;
switch(opcode) {
case TCPOPT_EOL:
goto done_opts;
case TCPOPT_NOP:
length--;
continue;
default:
opsize = *ptr++;
if (opsize < 2 || opsize > length)
goto done_opts;
if (opcode == TCPOPT_MD5SIG) {
hash_location = ptr;
goto done_opts;
}
}
ptr += opsize - 2;
length -= opsize;
}
done_opts:
/* do we have a hash as expected? */ /* do we have a hash as expected? */
if (!hash_expected) { if (!hash_expected) {
if (!hash_location) if (!hash_location)
...@@ -908,8 +838,7 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb) ...@@ -908,8 +838,7 @@ static int tcp_v6_inbound_md5_hash (struct sock *sk, struct sk_buff *skb)
genhash = tcp_v6_do_calc_md5_hash(newhash, genhash = tcp_v6_do_calc_md5_hash(newhash,
hash_expected, hash_expected,
&ip6h->saddr, &ip6h->daddr, &ip6h->saddr, &ip6h->daddr,
th, sk->sk_protocol, th, skb->len);
skb->len);
if (genhash || memcmp(hash_location, newhash, 16) != 0) { if (genhash || memcmp(hash_location, newhash, 16) != 0) {
if (net_ratelimit()) { if (net_ratelimit()) {
printk(KERN_INFO "MD5 Hash %s for " printk(KERN_INFO "MD5 Hash %s for "
...@@ -1049,7 +978,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) ...@@ -1049,7 +978,7 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key, tcp_v6_do_calc_md5_hash((__u8 *)&opt[1], key,
&ipv6_hdr(skb)->daddr, &ipv6_hdr(skb)->daddr,
&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->saddr,
t1, IPPROTO_TCP, tot_len); t1, tot_len);
} }
#endif #endif
...@@ -1086,8 +1015,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb) ...@@ -1086,8 +1015,8 @@ static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb)
kfree_skb(buff); kfree_skb(buff);
} }
static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, static void tcp_v6_send_ack(struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts,
struct sk_buff *skb, u32 seq, u32 ack, u32 win, u32 ts) struct tcp_md5sig_key *key)
{ {
struct tcphdr *th = tcp_hdr(skb), *t1; struct tcphdr *th = tcp_hdr(skb), *t1;
struct sk_buff *buff; struct sk_buff *buff;
...@@ -1096,22 +1025,6 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, ...@@ -1096,22 +1025,6 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw,
struct sock *ctl_sk = net->ipv6.tcp_sk; struct sock *ctl_sk = net->ipv6.tcp_sk;
unsigned int tot_len = sizeof(struct tcphdr); unsigned int tot_len = sizeof(struct tcphdr);
__be32 *topt; __be32 *topt;
#ifdef CONFIG_TCP_MD5SIG
struct tcp_md5sig_key *key;
struct tcp_md5sig_key tw_key;
#endif
#ifdef CONFIG_TCP_MD5SIG
if (!tw && skb->sk) {
key = tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr);
} else if (tw && tw->tw_md5_keylen) {
tw_key.key = tw->tw_md5_key;
tw_key.keylen = tw->tw_md5_keylen;
key = &tw_key;
} else {
key = NULL;
}
#endif
if (ts) if (ts)
tot_len += TCPOLEN_TSTAMP_ALIGNED; tot_len += TCPOLEN_TSTAMP_ALIGNED;
...@@ -1155,7 +1068,7 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw, ...@@ -1155,7 +1068,7 @@ static void tcp_v6_send_ack(struct tcp_timewait_sock *tw,
tcp_v6_do_calc_md5_hash((__u8 *)topt, key, tcp_v6_do_calc_md5_hash((__u8 *)topt, key,
&ipv6_hdr(skb)->daddr, &ipv6_hdr(skb)->daddr,
&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->saddr,
t1, IPPROTO_TCP, tot_len); t1, tot_len);
} }
#endif #endif
...@@ -1191,16 +1104,17 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb) ...@@ -1191,16 +1104,17 @@ static void tcp_v6_timewait_ack(struct sock *sk, struct sk_buff *skb)
struct inet_timewait_sock *tw = inet_twsk(sk); struct inet_timewait_sock *tw = inet_twsk(sk);
struct tcp_timewait_sock *tcptw = tcp_twsk(sk); struct tcp_timewait_sock *tcptw = tcp_twsk(sk);
tcp_v6_send_ack(tcptw, skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt, tcp_v6_send_ack(skb, tcptw->tw_snd_nxt, tcptw->tw_rcv_nxt,
tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale, tcptw->tw_rcv_wnd >> tw->tw_rcv_wscale,
tcptw->tw_ts_recent); tcptw->tw_ts_recent, tcp_twsk_md5_key(tcptw));
inet_twsk_put(tw); inet_twsk_put(tw);
} }
static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req) static void tcp_v6_reqsk_send_ack(struct sk_buff *skb, struct request_sock *req)
{ {
tcp_v6_send_ack(NULL, skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent); tcp_v6_send_ack(skb, tcp_rsk(req)->snt_isn + 1, tcp_rsk(req)->rcv_isn + 1, req->rcv_wnd, req->ts_recent,
tcp_v6_md5_do_lookup(skb->sk, &ipv6_hdr(skb)->daddr));
} }
......
This diff is collapsed.
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