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

Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5

into kernel.bkbits.net:/home/davem/net-2.5
parents d691958b 7aeb5c3f
...@@ -619,6 +619,37 @@ ratelimit - INTEGER ...@@ -619,6 +619,37 @@ ratelimit - INTEGER
0 to disable any limiting, otherwise the maximal rate in jiffies(1) 0 to disable any limiting, otherwise the maximal rate in jiffies(1)
Default: 100 Default: 100
use_tempaddr - INTEGER
Preference for Privacy Extensions (RFC3041).
<= 0 : disable Privacy Extensions
== 1 : enable Privacy Extensions, but prefer public
addresses over temporary addresses.
> 1 : enable Privacy Extensions and prefer temporary
addresses over public addresses.
Default: 0 (for most devices)
-1 (for point-to-point devices and loopback devices)
temp_valid_lft - INTEGER
valid lifetime (in seconds) for temporary addresses.
Default: 604800 (7 days)
temp_prefered_lft - INTEGER
Preferred lifetime (in seconds) for temorary addresses.
Default: 86400 (1 day)
max_desync_factor - INTEGER
Maximum value for DESYNC_FACTOR, which is a random value
that ensures that clients don't synchronize with each
other and generage new addresses at exactly the same time.
value is in seconds.
Default: 600
regen_max_retry - INTEGER
Number of attempts before give up attempting to generate
valid temporary addresses.
Default: 5
IPv6 Update by: IPv6 Update by:
Pekka Savola <pekkas@netcore.fi> Pekka Savola <pekkas@netcore.fi>
YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org> YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
......
...@@ -1262,6 +1262,8 @@ P: Alexey Kuznetsov ...@@ -1262,6 +1262,8 @@ P: Alexey Kuznetsov
M: kuznet@ms2.inr.ac.ru M: kuznet@ms2.inr.ac.ru
P: Pekka Savola (ipv6) P: Pekka Savola (ipv6)
M: pekkas@netcore.fi M: pekkas@netcore.fi
P: James Morris
M: jmorris@intercode.com.au
L: netdev@oss.sgi.com L: netdev@oss.sgi.com
S: Maintained S: Maintained
......
...@@ -336,6 +336,7 @@ enum ...@@ -336,6 +336,7 @@ enum
/* ifa_flags */ /* ifa_flags */
#define IFA_F_SECONDARY 0x01 #define IFA_F_SECONDARY 0x01
#define IFA_F_TEMPORARY IFA_F_SECONDARY
#define IFA_F_DEPRECATED 0x20 #define IFA_F_DEPRECATED 0x20
#define IFA_F_TENTATIVE 0x40 #define IFA_F_TENTATIVE 0x40
......
...@@ -777,7 +777,7 @@ static inline int skb_is_nonlinear(const struct sk_buff *skb) ...@@ -777,7 +777,7 @@ static inline int skb_is_nonlinear(const struct sk_buff *skb)
return skb->data_len; return skb->data_len;
} }
static inline int skb_headlen(const struct sk_buff *skb) static inline unsigned int skb_headlen(const struct sk_buff *skb)
{ {
return skb->len - skb->data_len; return skb->len - skb->data_len;
} }
......
...@@ -388,7 +388,12 @@ enum { ...@@ -388,7 +388,12 @@ enum {
NET_IPV6_DAD_TRANSMITS=7, NET_IPV6_DAD_TRANSMITS=7,
NET_IPV6_RTR_SOLICITS=8, NET_IPV6_RTR_SOLICITS=8,
NET_IPV6_RTR_SOLICIT_INTERVAL=9, NET_IPV6_RTR_SOLICIT_INTERVAL=9,
NET_IPV6_RTR_SOLICIT_DELAY=10 NET_IPV6_RTR_SOLICIT_DELAY=10,
NET_IPV6_USE_TEMPADDR=11,
NET_IPV6_TEMP_VALID_LFT=12,
NET_IPV6_TEMP_PREFERED_LFT=13,
NET_IPV6_REGEN_MAX_RETRY=14,
NET_IPV6_MAX_DESYNC_FACTOR=15
}; };
/* /proc/sys/net/ipv6/icmp */ /* /proc/sys/net/ipv6/icmp */
......
...@@ -6,6 +6,11 @@ ...@@ -6,6 +6,11 @@
#define MAX_RTR_SOLICITATIONS 3 #define MAX_RTR_SOLICITATIONS 3
#define RTR_SOLICITATION_INTERVAL (4*HZ) #define RTR_SOLICITATION_INTERVAL (4*HZ)
#define TEMP_VALID_LIFETIME (7*86400)
#define TEMP_PREFERRED_LIFETIME (86400)
#define REGEN_MAX_RETRY (5)
#define MAX_DESYNC_FACTOR (600)
#define ADDR_CHECK_FREQUENCY (120*HZ) #define ADDR_CHECK_FREQUENCY (120*HZ)
struct prefix_info { struct prefix_info {
......
...@@ -43,6 +43,12 @@ struct inet6_ifaddr ...@@ -43,6 +43,12 @@ struct inet6_ifaddr
struct inet6_ifaddr *lst_next; /* next addr in addr_lst */ struct inet6_ifaddr *lst_next; /* next addr in addr_lst */
struct inet6_ifaddr *if_next; /* next addr in inet6_dev */ struct inet6_ifaddr *if_next; /* next addr in inet6_dev */
#ifdef CONFIG_IPV6_PRIVACY
struct inet6_ifaddr *tmp_next; /* next addr in tempaddr_lst */
struct inet6_ifaddr *ifpub;
int regen_count;
#endif
int dead; int dead;
}; };
...@@ -86,7 +92,13 @@ struct ipv6_devconf ...@@ -86,7 +92,13 @@ struct ipv6_devconf
int rtr_solicits; int rtr_solicits;
int rtr_solicit_interval; int rtr_solicit_interval;
int rtr_solicit_delay; int rtr_solicit_delay;
#ifdef CONFIG_IPV6_PRIVACY
int use_tempaddr;
int temp_valid_lft;
int temp_prefered_lft;
int regen_max_retry;
int max_desync_factor;
#endif
void *sysctl; void *sysctl;
}; };
...@@ -101,6 +113,13 @@ struct inet6_dev ...@@ -101,6 +113,13 @@ struct inet6_dev
__u32 if_flags; __u32 if_flags;
int dead; int dead;
#ifdef CONFIG_IPV6_PRIVACY
u8 rndid[8];
u8 entropy[8];
struct timer_list regen_timer;
struct inet6_ifaddr *tempaddr_list;
#endif
struct neigh_parms *nd_parms; struct neigh_parms *nd_parms;
struct inet6_dev *next; struct inet6_dev *next;
struct ipv6_devconf cnf; struct ipv6_devconf cnf;
......
...@@ -30,6 +30,8 @@ extern void ip6_route_input(struct sk_buff *skb); ...@@ -30,6 +30,8 @@ extern void ip6_route_input(struct sk_buff *skb);
extern struct dst_entry * ip6_route_output(struct sock *sk, extern struct dst_entry * ip6_route_output(struct sock *sk,
struct flowi *fl); struct flowi *fl);
extern int ip6_route_me_harder(struct sk_buff *skb);
extern void ip6_route_init(void); extern void ip6_route_init(void);
extern void ip6_route_cleanup(void); extern void ip6_route_cleanup(void);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <net/arp.h> #include <net/arp.h>
#include <net/dst.h> #include <net/dst.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/spinlock.h>
/* TokenRing if needed */ /* TokenRing if needed */
#ifdef CONFIG_TR #ifdef CONFIG_TR
...@@ -35,6 +36,10 @@ ...@@ -35,6 +36,10 @@
#include <linux/if_bridge.h> #include <linux/if_bridge.h>
#include "../bridge/br_private.h" #include "../bridge/br_private.h"
static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00}; static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br,
unsigned char *addr);
extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
#endif #endif
/* Modular too */ /* Modular too */
...@@ -51,10 +56,7 @@ static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00}; ...@@ -51,10 +56,7 @@ static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
#define DPRINTK(format,args...) #define DPRINTK(format,args...)
#endif #endif
extern struct net_bridge_fdb_entry *(*br_fdb_get_hook)(struct net_bridge *br, static spinlock_t lec_arp_spinlock = SPIN_LOCK_UNLOCKED;
unsigned char *addr);
extern void (*br_fdb_put_hook)(struct net_bridge_fdb_entry *ent);
#define DUMP_PACKETS 0 /* 0 = None, #define DUMP_PACKETS 0 /* 0 = None,
* 1 = 30 first bytes * 1 = 30 first bytes
...@@ -196,6 +198,23 @@ lec_open(struct net_device *dev) ...@@ -196,6 +198,23 @@ lec_open(struct net_device *dev)
return 0; return 0;
} }
static __inline__ void
lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv)
{
if (atm_may_send(vcc, skb->len)) {
atomic_add(skb->truesize, &vcc->tx_inuse);
ATM_SKB(skb)->vcc = vcc;
ATM_SKB(skb)->iovcnt = 0;
ATM_SKB(skb)->atm_options = vcc->atm_options;
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
vcc->send(vcc, skb);
} else {
priv->stats.tx_dropped++;
dev_kfree_skb(skb);
}
}
static int static int
lec_send_packet(struct sk_buff *skb, struct net_device *dev) lec_send_packet(struct sk_buff *skb, struct net_device *dev)
{ {
...@@ -341,34 +360,10 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev) ...@@ -341,34 +360,10 @@ lec_send_packet(struct sk_buff *skb, struct net_device *dev)
DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n", DPRINTK("MAC address 0x%02x:%02x:%02x:%02x:%02x:%02x\n",
lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2], lec_h->h_dest[0], lec_h->h_dest[1], lec_h->h_dest[2],
lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]); lec_h->h_dest[3], lec_h->h_dest[4], lec_h->h_dest[5]);
ATM_SKB(skb2)->vcc = send_vcc; lec_send(send_vcc, skb2, priv);
ATM_SKB(skb2)->iovcnt = 0; }
ATM_SKB(skb2)->atm_options = send_vcc->atm_options;
DPRINTK("%s:sending to vpi:%d vci:%d\n", dev->name, lec_send(send_vcc, skb, priv);
send_vcc->vpi, send_vcc->vci);
if (atm_may_send(send_vcc, skb2->len)) {
atomic_add(skb2->truesize, &send_vcc->tx_inuse);
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb2->len;
send_vcc->send(send_vcc, skb2);
} else {
priv->stats.tx_dropped++;
dev_kfree_skb(skb2);
}
}
ATM_SKB(skb)->vcc = send_vcc;
ATM_SKB(skb)->iovcnt = 0;
ATM_SKB(skb)->atm_options = send_vcc->atm_options;
if (atm_may_send(send_vcc, skb->len)) {
atomic_add(skb->truesize, &send_vcc->tx_inuse);
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
send_vcc->send(send_vcc, skb);
} else {
priv->stats.tx_dropped++;
dev_kfree_skb(skb);
}
#if 0 #if 0
/* Should we wait for card's device driver to notify us? */ /* Should we wait for card's device driver to notify us? */
...@@ -1044,15 +1039,15 @@ void dump_arp_table(struct lec_priv *priv); ...@@ -1044,15 +1039,15 @@ void dump_arp_table(struct lec_priv *priv);
#define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE -1)) #define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE -1))
static __inline__ void static __inline__ void
lec_arp_lock(struct lec_priv *priv) lec_arp_get(struct lec_priv *priv)
{ {
atomic_inc(&priv->lec_arp_lock_var); atomic_inc(&priv->lec_arp_users);
} }
static __inline__ void static __inline__ void
lec_arp_unlock(struct lec_priv *priv) lec_arp_put(struct lec_priv *priv)
{ {
atomic_dec(&priv->lec_arp_lock_var); atomic_dec(&priv->lec_arp_users);
} }
/* /*
...@@ -1103,33 +1098,33 @@ lec_arp_clear_vccs(struct lec_arp_table *entry) ...@@ -1103,33 +1098,33 @@ lec_arp_clear_vccs(struct lec_arp_table *entry)
* LANE2: Add to the end of the list to satisfy 8.1.13 * LANE2: Add to the end of the list to satisfy 8.1.13
*/ */
static __inline__ void static __inline__ void
lec_arp_put(struct lec_arp_table **lec_arp_tables, lec_arp_add(struct lec_arp_table **lec_arp_tables,
struct lec_arp_table *to_put) struct lec_arp_table *to_add)
{ {
unsigned short place;
unsigned long flags; unsigned long flags;
unsigned short place;
struct lec_arp_table *tmp; struct lec_arp_table *tmp;
save_flags(flags); spin_lock_irqsave(&lec_arp_spinlock, flags);
cli();
place = HASH(to_put->mac_addr[ETH_ALEN-1]); place = HASH(to_add->mac_addr[ETH_ALEN-1]);
tmp = lec_arp_tables[place]; tmp = lec_arp_tables[place];
to_put->next = NULL; to_add->next = NULL;
if (tmp == NULL) if (tmp == NULL)
lec_arp_tables[place] = to_put; lec_arp_tables[place] = to_add;
else { /* add to the end */ else { /* add to the end */
while (tmp->next) while (tmp->next)
tmp = tmp->next; tmp = tmp->next;
tmp->next = to_put; tmp->next = to_add;
} }
restore_flags(flags); spin_unlock_irqrestore(&lec_arp_spinlock, flags);
DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", DPRINTK("LEC_ARP: Added entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
0xff&to_put->mac_addr[0], 0xff&to_put->mac_addr[1], 0xff&to_add->mac_addr[0], 0xff&to_add->mac_addr[1],
0xff&to_put->mac_addr[2], 0xff&to_put->mac_addr[3], 0xff&to_add->mac_addr[2], 0xff&to_add->mac_addr[3],
0xff&to_put->mac_addr[4], 0xff&to_put->mac_addr[5]); 0xff&to_add->mac_addr[4], 0xff&to_add->mac_addr[5]);
} }
/* /*
...@@ -1139,16 +1134,15 @@ static __inline__ int ...@@ -1139,16 +1134,15 @@ static __inline__ int
lec_arp_remove(struct lec_arp_table **lec_arp_tables, lec_arp_remove(struct lec_arp_table **lec_arp_tables,
struct lec_arp_table *to_remove) struct lec_arp_table *to_remove)
{ {
unsigned long flags;
unsigned short place; unsigned short place;
struct lec_arp_table *tmp; struct lec_arp_table *tmp;
unsigned long flags;
int remove_vcc=1; int remove_vcc=1;
save_flags(flags); spin_lock_irqsave(&lec_arp_spinlock, flags);
cli();
if (!to_remove) { if (!to_remove) {
restore_flags(flags); spin_unlock_irqrestore(&lec_arp_spinlock, flags);
return -1; return -1;
} }
place = HASH(to_remove->mac_addr[ETH_ALEN-1]); place = HASH(to_remove->mac_addr[ETH_ALEN-1]);
...@@ -1160,7 +1154,7 @@ lec_arp_remove(struct lec_arp_table **lec_arp_tables, ...@@ -1160,7 +1154,7 @@ lec_arp_remove(struct lec_arp_table **lec_arp_tables,
tmp = tmp->next; tmp = tmp->next;
} }
if (!tmp) {/* Entry was not found */ if (!tmp) {/* Entry was not found */
restore_flags(flags); spin_unlock_irqrestore(&lec_arp_spinlock, flags);
return -1; return -1;
} }
} }
...@@ -1186,7 +1180,9 @@ lec_arp_remove(struct lec_arp_table **lec_arp_tables, ...@@ -1186,7 +1180,9 @@ lec_arp_remove(struct lec_arp_table **lec_arp_tables,
lec_arp_clear_vccs(to_remove); lec_arp_clear_vccs(to_remove);
} }
skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */ skb_queue_purge(&to_remove->tx_wait); /* FIXME: good place for this? */
restore_flags(flags);
spin_unlock_irqrestore(&lec_arp_spinlock, flags);
DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", DPRINTK("LEC_ARP: Removed entry:%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1], 0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1],
0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3], 0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3],
...@@ -1371,12 +1367,8 @@ void ...@@ -1371,12 +1367,8 @@ void
lec_arp_destroy(struct lec_priv *priv) lec_arp_destroy(struct lec_priv *priv)
{ {
struct lec_arp_table *entry, *next; struct lec_arp_table *entry, *next;
unsigned long flags;
int i; int i;
save_flags(flags);
cli();
del_timer(&priv->lec_arp_timer); del_timer(&priv->lec_arp_timer);
/* /*
...@@ -1419,7 +1411,6 @@ lec_arp_destroy(struct lec_priv *priv) ...@@ -1419,7 +1411,6 @@ lec_arp_destroy(struct lec_priv *priv)
priv->mcast_vcc = NULL; priv->mcast_vcc = NULL;
memset(priv->lec_arp_tables, 0, memset(priv->lec_arp_tables, 0,
sizeof(struct lec_arp_table*)*LEC_ARP_TABLE_SIZE); sizeof(struct lec_arp_table*)*LEC_ARP_TABLE_SIZE);
restore_flags(flags);
} }
...@@ -1436,18 +1427,18 @@ lec_arp_find(struct lec_priv *priv, ...@@ -1436,18 +1427,18 @@ lec_arp_find(struct lec_priv *priv,
DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n", DPRINTK("LEC_ARP: lec_arp_find :%2.2x %2.2x %2.2x %2.2x %2.2x %2.2x\n",
mac_addr[0]&0xff, mac_addr[1]&0xff, mac_addr[2]&0xff, mac_addr[0]&0xff, mac_addr[1]&0xff, mac_addr[2]&0xff,
mac_addr[3]&0xff, mac_addr[4]&0xff, mac_addr[5]&0xff); mac_addr[3]&0xff, mac_addr[4]&0xff, mac_addr[5]&0xff);
lec_arp_lock(priv); lec_arp_get(priv);
place = HASH(mac_addr[ETH_ALEN-1]); place = HASH(mac_addr[ETH_ALEN-1]);
to_return = priv->lec_arp_tables[place]; to_return = priv->lec_arp_tables[place];
while(to_return) { while(to_return) {
if (memcmp(mac_addr, to_return->mac_addr, ETH_ALEN) == 0) { if (memcmp(mac_addr, to_return->mac_addr, ETH_ALEN) == 0) {
lec_arp_unlock(priv); lec_arp_put(priv);
return to_return; return to_return;
} }
to_return = to_return->next; to_return = to_return->next;
} }
lec_arp_unlock(priv); lec_arp_put(priv);
return NULL; return NULL;
} }
...@@ -1574,11 +1565,11 @@ lec_arp_check_expire(unsigned long data) ...@@ -1574,11 +1565,11 @@ lec_arp_check_expire(unsigned long data)
del_timer(&priv->lec_arp_timer); del_timer(&priv->lec_arp_timer);
DPRINTK("lec_arp_check_expire %p,%d\n",priv, DPRINTK("lec_arp_check_expire %p,%d\n",priv,
priv->lec_arp_lock_var.counter); atomic_read(&priv->lec_arp_users));
DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones, DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones,
priv->lec_no_forward); priv->lec_no_forward);
if (!priv->lec_arp_lock_var.counter) { if (!atomic_read(&priv->lec_arp_users)) {
lec_arp_lock(priv); lec_arp_get(priv);
now = jiffies; now = jiffies;
for(i=0;i<LEC_ARP_TABLE_SIZE;i++) { for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
for(entry = lec_arp_tables[i];entry != NULL;) { for(entry = lec_arp_tables[i];entry != NULL;) {
...@@ -1616,6 +1607,10 @@ lec_arp_check_expire(unsigned long data) ...@@ -1616,6 +1607,10 @@ lec_arp_check_expire(unsigned long data)
&& &&
time_after_eq(now, entry->timestamp+ time_after_eq(now, entry->timestamp+
priv->path_switching_delay)) { priv->path_switching_delay)) {
struct sk_buff *skb;
while ((skb = skb_dequeue(&entry->tx_wait)))
lec_send(entry->vcc, skb, entry->priv);
entry->last_used = jiffies; entry->last_used = jiffies;
entry->status = entry->status =
ESI_FORWARD_DIRECT; ESI_FORWARD_DIRECT;
...@@ -1624,7 +1619,7 @@ lec_arp_check_expire(unsigned long data) ...@@ -1624,7 +1619,7 @@ lec_arp_check_expire(unsigned long data)
} }
} }
} }
lec_arp_unlock(priv); lec_arp_put(priv);
} }
priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL; priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL;
add_timer(&priv->lec_arp_timer); add_timer(&priv->lec_arp_timer);
...@@ -1686,7 +1681,7 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc, ...@@ -1686,7 +1681,7 @@ lec_arp_resolve(struct lec_priv *priv, unsigned char *mac_to_find, int is_rdesc,
if (!entry) { if (!entry) {
return priv->mcast_vcc; return priv->mcast_vcc;
} }
lec_arp_put(priv->lec_arp_tables, entry); lec_arp_add(priv->lec_arp_tables, entry);
/* We want arp-request(s) to be sent */ /* We want arp-request(s) to be sent */
entry->packets_flooded =1; entry->packets_flooded =1;
entry->status = ESI_ARP_PENDING; entry->status = ESI_ARP_PENDING;
...@@ -1711,7 +1706,7 @@ lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, ...@@ -1711,7 +1706,7 @@ lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
struct lec_arp_table *entry, *next; struct lec_arp_table *entry, *next;
int i; int i;
lec_arp_lock(priv); lec_arp_get(priv);
DPRINTK("lec_addr_delete\n"); DPRINTK("lec_addr_delete\n");
for(i=0;i<LEC_ARP_TABLE_SIZE;i++) { for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
for(entry=priv->lec_arp_tables[i];entry != NULL; entry=next) { for(entry=priv->lec_arp_tables[i];entry != NULL; entry=next) {
...@@ -1722,11 +1717,11 @@ lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr, ...@@ -1722,11 +1717,11 @@ lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
lec_arp_remove(priv->lec_arp_tables, entry); lec_arp_remove(priv->lec_arp_tables, entry);
kfree(entry); kfree(entry);
} }
lec_arp_unlock(priv); lec_arp_put(priv);
return 0; return 0;
} }
} }
lec_arp_unlock(priv); lec_arp_put(priv);
return -1; return -1;
} }
...@@ -1751,7 +1746,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, ...@@ -1751,7 +1746,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
return; /* LANE2: ignore targetless LE_ARPs for which return; /* LANE2: ignore targetless LE_ARPs for which
* we have no entry in the cache. 7.1.30 * we have no entry in the cache. 7.1.30
*/ */
lec_arp_lock(priv); lec_arp_get(priv);
if (priv->lec_arp_empty_ones) { if (priv->lec_arp_empty_ones) {
entry = priv->lec_arp_empty_ones; entry = priv->lec_arp_empty_ones;
if (!memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN)) { if (!memcmp(entry->atm_addr, atm_addr, ATM_ESA_LEN)) {
...@@ -1785,13 +1780,13 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, ...@@ -1785,13 +1780,13 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
entry->status = ESI_FORWARD_DIRECT; entry->status = ESI_FORWARD_DIRECT;
memcpy(entry->mac_addr, mac_addr, ETH_ALEN); memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
entry->last_used = jiffies; entry->last_used = jiffies;
lec_arp_put(priv->lec_arp_tables, entry); lec_arp_add(priv->lec_arp_tables, entry);
} }
if (remoteflag) if (remoteflag)
entry->flags|=LEC_REMOTE_FLAG; entry->flags|=LEC_REMOTE_FLAG;
else else
entry->flags&=~LEC_REMOTE_FLAG; entry->flags&=~LEC_REMOTE_FLAG;
lec_arp_unlock(priv); lec_arp_put(priv);
DPRINTK("After update\n"); DPRINTK("After update\n");
dump_arp_table(priv); dump_arp_table(priv);
return; return;
...@@ -1801,11 +1796,11 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, ...@@ -1801,11 +1796,11 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
if (!entry) { if (!entry) {
entry = make_entry(priv, mac_addr); entry = make_entry(priv, mac_addr);
if (!entry) { if (!entry) {
lec_arp_unlock(priv); lec_arp_put(priv);
return; return;
} }
entry->status = ESI_UNKNOWN; entry->status = ESI_UNKNOWN;
lec_arp_put(priv->lec_arp_tables, entry); lec_arp_add(priv->lec_arp_tables, entry);
/* Temporary, changes before end of function */ /* Temporary, changes before end of function */
} }
memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN); memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
...@@ -1840,7 +1835,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr, ...@@ -1840,7 +1835,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
} }
DPRINTK("After update2\n"); DPRINTK("After update2\n");
dump_arp_table(priv); dump_arp_table(priv);
lec_arp_unlock(priv); lec_arp_put(priv);
} }
/* /*
...@@ -1854,7 +1849,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, ...@@ -1854,7 +1849,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
struct lec_arp_table *entry; struct lec_arp_table *entry;
int i, found_entry=0; int i, found_entry=0;
lec_arp_lock(priv); lec_arp_get(priv);
if (ioc_data->receive == 2) { if (ioc_data->receive == 2) {
/* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */ /* Vcc for Multicast Forward. No timer, LANEv2 7.1.20 and 2.3.5.3 */
...@@ -1863,7 +1858,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, ...@@ -1863,7 +1858,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
entry = lec_arp_find(priv, bus_mac); entry = lec_arp_find(priv, bus_mac);
if (!entry) { if (!entry) {
printk("LEC_ARP: Multicast entry not found!\n"); printk("LEC_ARP: Multicast entry not found!\n");
lec_arp_unlock(priv); lec_arp_put(priv);
return; return;
} }
memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
...@@ -1872,7 +1867,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, ...@@ -1872,7 +1867,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
#endif #endif
entry = make_entry(priv, bus_mac); entry = make_entry(priv, bus_mac);
if (entry == NULL) { if (entry == NULL) {
lec_arp_unlock(priv); lec_arp_put(priv);
return; return;
} }
del_timer(&entry->timer); del_timer(&entry->timer);
...@@ -1881,7 +1876,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, ...@@ -1881,7 +1876,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
entry->old_recv_push = old_push; entry->old_recv_push = old_push;
entry->next = priv->mcast_fwds; entry->next = priv->mcast_fwds;
priv->mcast_fwds = entry; priv->mcast_fwds = entry;
lec_arp_unlock(priv); lec_arp_put(priv);
return; return;
} else if (ioc_data->receive == 1) { } else if (ioc_data->receive == 1) {
/* Vcc which we don't want to make default vcc, attach it /* Vcc which we don't want to make default vcc, attach it
...@@ -1899,7 +1894,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, ...@@ -1899,7 +1894,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
ioc_data->atm_addr[18],ioc_data->atm_addr[19]); ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
entry = make_entry(priv, bus_mac); entry = make_entry(priv, bus_mac);
if (entry == NULL) { if (entry == NULL) {
lec_arp_unlock(priv); lec_arp_put(priv);
return; return;
} }
memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN); memcpy(entry->atm_addr, ioc_data->atm_addr, ATM_ESA_LEN);
...@@ -1912,7 +1907,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, ...@@ -1912,7 +1907,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
add_timer(&entry->timer); add_timer(&entry->timer);
entry->next = priv->lec_no_forward; entry->next = priv->lec_no_forward;
priv->lec_no_forward = entry; priv->lec_no_forward = entry;
lec_arp_unlock(priv); lec_arp_put(priv);
dump_arp_table(priv); dump_arp_table(priv);
return; return;
} }
...@@ -1971,7 +1966,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, ...@@ -1971,7 +1966,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
} }
} }
if (found_entry) { if (found_entry) {
lec_arp_unlock(priv); lec_arp_put(priv);
DPRINTK("After vcc was added\n"); DPRINTK("After vcc was added\n");
dump_arp_table(priv); dump_arp_table(priv);
return; return;
...@@ -1980,7 +1975,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, ...@@ -1980,7 +1975,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
this vcc */ this vcc */
entry = make_entry(priv, bus_mac); entry = make_entry(priv, bus_mac);
if (!entry) { if (!entry) {
lec_arp_unlock(priv); lec_arp_put(priv);
return; return;
} }
entry->vcc = vcc; entry->vcc = vcc;
...@@ -1993,7 +1988,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data, ...@@ -1993,7 +1988,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
entry->timer.expires = jiffies + priv->vcc_timeout_period; entry->timer.expires = jiffies + priv->vcc_timeout_period;
entry->timer.function = lec_arp_expire_vcc; entry->timer.function = lec_arp_expire_vcc;
add_timer(&entry->timer); add_timer(&entry->timer);
lec_arp_unlock(priv); lec_arp_put(priv);
DPRINTK("After vcc was added\n"); DPRINTK("After vcc was added\n");
dump_arp_table(priv); dump_arp_table(priv);
} }
...@@ -2009,6 +2004,10 @@ lec_flush_complete(struct lec_priv *priv, unsigned long tran_id) ...@@ -2009,6 +2004,10 @@ lec_flush_complete(struct lec_priv *priv, unsigned long tran_id)
for (entry=priv->lec_arp_tables[i];entry;entry=entry->next) { for (entry=priv->lec_arp_tables[i];entry;entry=entry->next) {
if (entry->flush_tran_id == tran_id && if (entry->flush_tran_id == tran_id &&
entry->status == ESI_FLUSH_PENDING) { entry->status == ESI_FLUSH_PENDING) {
struct sk_buff *skb;
while ((skb = skb_dequeue(&entry->tx_wait)))
lec_send(entry->vcc, skb, entry->priv);
entry->status = ESI_FORWARD_DIRECT; entry->status = ESI_FORWARD_DIRECT;
DPRINTK("LEC_ARP: Flushed\n"); DPRINTK("LEC_ARP: Flushed\n");
} }
...@@ -2039,10 +2038,10 @@ lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc) ...@@ -2039,10 +2038,10 @@ lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
struct lec_arp_table *to_add; struct lec_arp_table *to_add;
lec_arp_lock(priv); lec_arp_get(priv);
to_add = make_entry(priv, mac_addr); to_add = make_entry(priv, mac_addr);
if (!to_add) { if (!to_add) {
lec_arp_unlock(priv); lec_arp_put(priv);
return -ENOMEM; return -ENOMEM;
} }
memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN); memcpy(to_add->atm_addr, vcc->remote.sas_addr.prv, ATM_ESA_LEN);
...@@ -2052,8 +2051,8 @@ lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc) ...@@ -2052,8 +2051,8 @@ lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
to_add->old_push = vcc->push; to_add->old_push = vcc->push;
vcc->push = lec_push; vcc->push = lec_push;
priv->mcast_vcc = vcc; priv->mcast_vcc = vcc;
lec_arp_put(priv->lec_arp_tables, to_add); lec_arp_add(priv->lec_arp_tables, to_add);
lec_arp_unlock(priv); lec_arp_put(priv);
return 0; return 0;
} }
...@@ -2065,7 +2064,7 @@ lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) ...@@ -2065,7 +2064,7 @@ lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n",vcc->vpi,vcc->vci); DPRINTK("LEC_ARP: lec_vcc_close vpi:%d vci:%d\n",vcc->vpi,vcc->vci);
dump_arp_table(priv); dump_arp_table(priv);
lec_arp_lock(priv); lec_arp_get(priv);
for(i=0;i<LEC_ARP_TABLE_SIZE;i++) { for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
for(entry = priv->lec_arp_tables[i];entry; entry=next) { for(entry = priv->lec_arp_tables[i];entry; entry=next) {
next = entry->next; next = entry->next;
...@@ -2127,7 +2126,7 @@ lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc) ...@@ -2127,7 +2126,7 @@ lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
entry = next; entry = next;
} }
lec_arp_unlock(priv); lec_arp_put(priv);
dump_arp_table(priv); dump_arp_table(priv);
} }
...@@ -2135,9 +2134,9 @@ void ...@@ -2135,9 +2134,9 @@ void
lec_arp_check_empties(struct lec_priv *priv, lec_arp_check_empties(struct lec_priv *priv,
struct atm_vcc *vcc, struct sk_buff *skb) struct atm_vcc *vcc, struct sk_buff *skb)
{ {
unsigned long flags;
struct lec_arp_table *entry, *prev; struct lec_arp_table *entry, *prev;
struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data; struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
unsigned long flags;
unsigned char *src; unsigned char *src;
#ifdef CONFIG_TR #ifdef CONFIG_TR
struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data; struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
...@@ -2147,26 +2146,26 @@ lec_arp_check_empties(struct lec_priv *priv, ...@@ -2147,26 +2146,26 @@ lec_arp_check_empties(struct lec_priv *priv,
#endif #endif
src = hdr->h_source; src = hdr->h_source;
lec_arp_lock(priv); lec_arp_get(priv);
entry = priv->lec_arp_empty_ones; entry = priv->lec_arp_empty_ones;
if (vcc == entry->vcc) { if (vcc == entry->vcc) {
save_flags(flags); spin_lock_irqsave(&lec_arp_spinlock, flags);
cli();
del_timer(&entry->timer); del_timer(&entry->timer);
memcpy(entry->mac_addr, src, ETH_ALEN); memcpy(entry->mac_addr, src, ETH_ALEN);
entry->status = ESI_FORWARD_DIRECT; entry->status = ESI_FORWARD_DIRECT;
entry->last_used = jiffies; entry->last_used = jiffies;
priv->lec_arp_empty_ones = entry->next; priv->lec_arp_empty_ones = entry->next;
restore_flags(flags); spin_unlock_irqrestore(&lec_arp_spinlock, flags);
/* We might have got an entry */ /* We might have got an entry */
if ((prev=lec_arp_find(priv,src))) { if ((prev=lec_arp_find(priv,src))) {
lec_arp_remove(priv->lec_arp_tables, prev); lec_arp_remove(priv->lec_arp_tables, prev);
kfree(prev); kfree(prev);
} }
lec_arp_put(priv->lec_arp_tables, entry); lec_arp_add(priv->lec_arp_tables, entry);
lec_arp_unlock(priv); lec_arp_put(priv);
return; return;
} }
spin_lock_irqsave(&lec_arp_spinlock, flags);
prev = entry; prev = entry;
entry = entry->next; entry = entry->next;
while (entry && entry->vcc != vcc) { while (entry && entry->vcc != vcc) {
...@@ -2175,22 +2174,21 @@ lec_arp_check_empties(struct lec_priv *priv, ...@@ -2175,22 +2174,21 @@ lec_arp_check_empties(struct lec_priv *priv,
} }
if (!entry) { if (!entry) {
DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n"); DPRINTK("LEC_ARP: Arp_check_empties: entry not found!\n");
lec_arp_unlock(priv); lec_arp_put(priv);
spin_unlock_irqrestore(&lec_arp_spinlock, flags);
return; return;
} }
save_flags(flags);
cli();
del_timer(&entry->timer); del_timer(&entry->timer);
memcpy(entry->mac_addr, src, ETH_ALEN); memcpy(entry->mac_addr, src, ETH_ALEN);
entry->status = ESI_FORWARD_DIRECT; entry->status = ESI_FORWARD_DIRECT;
entry->last_used = jiffies; entry->last_used = jiffies;
prev->next = entry->next; prev->next = entry->next;
restore_flags(flags); spin_unlock_irqrestore(&lec_arp_spinlock, flags);
if ((prev = lec_arp_find(priv, src))) { if ((prev = lec_arp_find(priv, src))) {
lec_arp_remove(priv->lec_arp_tables,prev); lec_arp_remove(priv->lec_arp_tables,prev);
kfree(prev); kfree(prev);
} }
lec_arp_put(priv->lec_arp_tables,entry); lec_arp_add(priv->lec_arp_tables,entry);
lec_arp_unlock(priv); lec_arp_put(priv);
} }
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -98,7 +98,7 @@ struct lec_priv { ...@@ -98,7 +98,7 @@ struct lec_priv {
establishes multiple Multicast Forward VCCs to us. This list establishes multiple Multicast Forward VCCs to us. This list
collects all those VCCs. LANEv1 client has only one item in this collects all those VCCs. LANEv1 client has only one item in this
list. These entries are not aged out. */ list. These entries are not aged out. */
atomic_t lec_arp_lock_var; atomic_t lec_arp_users;
struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */ struct atm_vcc *mcast_vcc; /* Default Multicast Send VCC */
struct atm_vcc *lecd; struct atm_vcc *lecd;
struct timer_list lec_arp_timer; struct timer_list lec_arp_timer;
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/file.h> #include <linux/file.h>
#include <linux/init.h>
#include <net/sock.h> #include <net/sock.h>
#include <asm/system.h> #include <asm/system.h>
......
...@@ -223,57 +223,28 @@ struct icmp_control { ...@@ -223,57 +223,28 @@ struct icmp_control {
static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1]; static struct icmp_control icmp_pointers[NR_ICMP_TYPES+1];
/* /*
* The ICMP socket. This is the most convenient way to flow control * The ICMP socket(s). This is the most convenient way to flow control
* our ICMP output as well as maintain a clean interface throughout * our ICMP output as well as maintain a clean interface throughout
* all layers. All Socketless IP sends will soon be gone. * all layers. All Socketless IP sends will soon be gone.
*
* On SMP we have one ICMP socket per-cpu.
*/ */
struct socket *icmp_socket; static DEFINE_PER_CPU(struct socket *, __icmp_socket) = NULL;
#define icmp_socket per_cpu(__icmp_socket, smp_processor_id())
/* ICMPv4 socket is only a bit non-reenterable (unlike ICMPv6,
which is strongly non-reenterable). A bit later it will be made
reenterable and the lock may be removed then.
*/
static int icmp_xmit_holder = -1;
static int icmp_xmit_lock_bh(void)
{
int rc;
if (!spin_trylock(&icmp_socket->sk->lock.slock)) {
rc = -EAGAIN;
if (icmp_xmit_holder == smp_processor_id())
goto out;
spin_lock(&icmp_socket->sk->lock.slock);
}
rc = 0;
icmp_xmit_holder = smp_processor_id();
out:
return rc;
}
static __inline__ int icmp_xmit_lock(void) static __inline__ void icmp_xmit_lock(void)
{ {
int ret;
local_bh_disable(); local_bh_disable();
ret = icmp_xmit_lock_bh();
if (ret)
local_bh_enable();
return ret;
}
static void icmp_xmit_unlock_bh(void) if (unlikely(!spin_trylock(&icmp_socket->sk->lock.slock)))
{ BUG();
icmp_xmit_holder = -1;
spin_unlock(&icmp_socket->sk->lock.slock);
} }
static __inline__ void icmp_xmit_unlock(void) static void icmp_xmit_unlock(void)
{ {
icmp_xmit_unlock_bh(); spin_unlock_bh(&icmp_socket->sk->lock.slock);
local_bh_enable();
} }
/* /*
* Send an ICMP frame. * Send an ICMP frame.
*/ */
...@@ -404,10 +375,11 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) ...@@ -404,10 +375,11 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
struct rtable *rt = (struct rtable *)skb->dst; struct rtable *rt = (struct rtable *)skb->dst;
u32 daddr; u32 daddr;
if (ip_options_echo(&icmp_param->replyopts, skb) || if (ip_options_echo(&icmp_param->replyopts, skb))
icmp_xmit_lock_bh())
goto out; goto out;
icmp_xmit_lock();
icmp_param->data.icmph.checksum = 0; icmp_param->data.icmph.checksum = 0;
icmp_out_count(icmp_param->data.icmph.type); icmp_out_count(icmp_param->data.icmph.type);
...@@ -434,7 +406,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb) ...@@ -434,7 +406,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
icmp_push_reply(icmp_param, &ipc, rt); icmp_push_reply(icmp_param, &ipc, rt);
ip_rt_put(rt); ip_rt_put(rt);
out_unlock: out_unlock:
icmp_xmit_unlock_bh(); icmp_xmit_unlock();
out:; out:;
} }
...@@ -519,8 +491,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info) ...@@ -519,8 +491,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
} }
} }
if (icmp_xmit_lock()) icmp_xmit_lock();
goto out;
/* /*
* Construct source address and options. * Construct source address and options.
...@@ -1141,19 +1112,30 @@ static struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { ...@@ -1141,19 +1112,30 @@ static struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
void __init icmp_init(struct net_proto_family *ops) void __init icmp_init(struct net_proto_family *ops)
{ {
struct inet_opt *inet; struct inet_opt *inet;
int err = sock_create(PF_INET, SOCK_RAW, IPPROTO_ICMP, &icmp_socket); int i;
if (err < 0) for (i = 0; i < NR_CPUS; i++) {
panic("Failed to create the ICMP control socket.\n"); int err;
icmp_socket->sk->allocation = GFP_ATOMIC;
icmp_socket->sk->sndbuf = SK_WMEM_MAX * 2; if (!cpu_possible(i))
inet = inet_sk(icmp_socket->sk); continue;
inet->ttl = MAXTTL;
inet->pmtudisc = IP_PMTUDISC_DONT; err = sock_create(PF_INET, SOCK_RAW, IPPROTO_ICMP,
&per_cpu(__icmp_socket, i));
/* Unhash it so that IP input processing does not even
* see it, we do not wish this socket to see incoming if (err < 0)
* packets. panic("Failed to create the ICMP control socket.\n");
*/
icmp_socket->sk->prot->unhash(icmp_socket->sk); per_cpu(__icmp_socket, i)->sk->allocation = GFP_ATOMIC;
per_cpu(__icmp_socket, i)->sk->sndbuf = SK_WMEM_MAX * 2;
inet = inet_sk(per_cpu(__icmp_socket, i)->sk);
inet->ttl = MAXTTL;
inet->pmtudisc = IP_PMTUDISC_DONT;
/* Unhash it so that IP input processing does not even
* see it, we do not wish this socket to see incoming
* packets.
*/
per_cpu(__icmp_socket, i)->sk->prot->unhash(per_cpu(__icmp_socket, i)->sk);
}
} }
...@@ -13,9 +13,6 @@ ...@@ -13,9 +13,6 @@
* - export ip_conntrack[_expect]_{find_get,put} functions * - export ip_conntrack[_expect]_{find_get,put} functions
* */ * */
#ifdef MODULE
#define __NO_VERSION__
#endif
#include <linux/version.h> #include <linux/version.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/types.h> #include <linux/types.h>
......
#define __NO_VERSION__
#include <linux/types.h> #include <linux/types.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/timer.h> #include <linux/timer.h>
......
...@@ -2,9 +2,6 @@ ...@@ -2,9 +2,6 @@
/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General /* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
Public Licence. */ Public Licence. */
#ifdef MODULE
#define __NO_VERSION__
#endif
#include <linux/version.h> #include <linux/version.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/types.h> #include <linux/types.h>
......
/* Everything about the rules for NAT. */ /* Everything about the rules for NAT. */
#define __NO_VERSION__
#include <linux/types.h> #include <linux/types.h>
#include <linux/ip.h> #include <linux/ip.h>
#include <linux/netfilter.h> #include <linux/netfilter.h>
......
# #
# IPv6 configuration # IPv6 configuration
# #
config IPV6_PRIVACY
bool "IPv6: Privacy Extensions (RFC 3041) support"
depends on IPV6
---help---
Privacy Extensions for Stateless Address Autoconfiguration in IPv6
support. With this option, additional periodically-alter
pseudo-random global-scope unicast address(es) will assigned to
your interface(s).
By default, kernel do not generate temporary addresses.
To use temporary addresses, do
echo 2 >/proc/sys/net/ipv6/conf/all/use_tempaddr
See <file:Documentation/networking/ip-sysctl.txt> for details.
source "net/ipv6/netfilter/Kconfig" source "net/ipv6/netfilter/Kconfig"
...@@ -28,6 +28,8 @@ ...@@ -28,6 +28,8 @@
* packets. * packets.
* YOSHIFUJI Hideaki @USAGI : improved accuracy of * YOSHIFUJI Hideaki @USAGI : improved accuracy of
* address validation timer. * address validation timer.
* YOSHIFUJI Hideaki @USAGI : Privacy Extensions (RFC3041)
* support.
*/ */
#include <linux/config.h> #include <linux/config.h>
...@@ -62,6 +64,12 @@ ...@@ -62,6 +64,12 @@
#include <linux/if_tunnel.h> #include <linux/if_tunnel.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#ifdef CONFIG_IPV6_PRIVACY
#include <linux/random.h>
#include <linux/crypto.h>
#include <asm/scatterlist.h>
#endif
#include <asm/uaccess.h> #include <asm/uaccess.h>
#define IPV6_MAX_ADDRESSES 16 #define IPV6_MAX_ADDRESSES 16
...@@ -83,6 +91,16 @@ static void addrconf_sysctl_unregister(struct ipv6_devconf *p); ...@@ -83,6 +91,16 @@ static void addrconf_sysctl_unregister(struct ipv6_devconf *p);
int inet6_dev_count; int inet6_dev_count;
int inet6_ifa_count; int inet6_ifa_count;
#ifdef CONFIG_IPV6_PRIVACY
static int __ipv6_regen_rndid(struct inet6_dev *idev);
static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr);
static void ipv6_regen_rndid(unsigned long data);
static int desync_factor = MAX_DESYNC_FACTOR * HZ;
#endif
static int ipv6_count_addresses(struct inet6_dev *idev);
/* /*
* Configured unicast address hash table * Configured unicast address hash table
*/ */
...@@ -120,6 +138,13 @@ struct ipv6_devconf ipv6_devconf = ...@@ -120,6 +138,13 @@ struct ipv6_devconf ipv6_devconf =
MAX_RTR_SOLICITATIONS, /* router solicits */ MAX_RTR_SOLICITATIONS, /* router solicits */
RTR_SOLICITATION_INTERVAL, /* rtr solicit interval */ RTR_SOLICITATION_INTERVAL, /* rtr solicit interval */
MAX_RTR_SOLICITATION_DELAY, /* rtr solicit delay */ MAX_RTR_SOLICITATION_DELAY, /* rtr solicit delay */
#ifdef CONFIG_IPV6_PRIVACY
.use_tempaddr = 0,
.temp_valid_lft = TEMP_VALID_LIFETIME,
.temp_prefered_lft = TEMP_PREFERRED_LIFETIME,
.regen_max_retry = REGEN_MAX_RETRY,
.max_desync_factor = MAX_DESYNC_FACTOR,
#endif
}; };
static struct ipv6_devconf ipv6_devconf_dflt = static struct ipv6_devconf ipv6_devconf_dflt =
...@@ -134,6 +159,13 @@ static struct ipv6_devconf ipv6_devconf_dflt = ...@@ -134,6 +159,13 @@ static struct ipv6_devconf ipv6_devconf_dflt =
MAX_RTR_SOLICITATIONS, /* router solicits */ MAX_RTR_SOLICITATIONS, /* router solicits */
RTR_SOLICITATION_INTERVAL, /* rtr solicit interval */ RTR_SOLICITATION_INTERVAL, /* rtr solicit interval */
MAX_RTR_SOLICITATION_DELAY, /* rtr solicit delay */ MAX_RTR_SOLICITATION_DELAY, /* rtr solicit delay */
#ifdef CONFIG_IPV6_PRIVACY
.use_tempaddr = 0,
.temp_valid_lft = TEMP_VALID_LIFETIME,
.temp_prefered_lft = TEMP_PREFERRED_LIFETIME,
.regen_max_retry = REGEN_MAX_RETRY,
.max_desync_factor = MAX_DESYNC_FACTOR,
#endif
}; };
/* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */ /* IPv6 Wildcard Address and Loopback Address defined by RFC2553 */
...@@ -277,6 +309,24 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev) ...@@ -277,6 +309,24 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
/* We refer to the device */ /* We refer to the device */
dev_hold(dev); dev_hold(dev);
#ifdef CONFIG_IPV6_PRIVACY
get_random_bytes(ndev->rndid, sizeof(ndev->rndid));
get_random_bytes(ndev->entropy, sizeof(ndev->entropy));
init_timer(&ndev->regen_timer);
ndev->regen_timer.function = ipv6_regen_rndid;
ndev->regen_timer.data = (unsigned long) ndev;
if ((dev->flags&IFF_LOOPBACK) ||
dev->type == ARPHRD_TUNNEL ||
dev->type == ARPHRD_SIT) {
printk(KERN_INFO
"Disabled Privacy Extensions on device %p(%s)\n",
dev, dev->name);
ndev->cnf.use_tempaddr = -1;
} else {
__ipv6_regen_rndid(ndev);
}
#endif
write_lock_bh(&addrconf_lock); write_lock_bh(&addrconf_lock);
dev->ip6_ptr = ndev; dev->ip6_ptr = ndev;
/* One reference from device */ /* One reference from device */
...@@ -401,6 +451,18 @@ ipv6_add_addr(struct inet6_dev *idev, struct in6_addr *addr, int pfxlen, ...@@ -401,6 +451,18 @@ ipv6_add_addr(struct inet6_dev *idev, struct in6_addr *addr, int pfxlen,
/* Add to inet6_dev unicast addr list. */ /* Add to inet6_dev unicast addr list. */
ifa->if_next = idev->addr_list; ifa->if_next = idev->addr_list;
idev->addr_list = ifa; idev->addr_list = ifa;
#ifdef CONFIG_IPV6_PRIVACY
ifa->regen_count = 0;
if (ifa->flags&IFA_F_TEMPORARY) {
ifa->tmp_next = idev->tempaddr_list;
idev->tempaddr_list = ifa;
in6_ifa_hold(ifa);
} else {
ifa->tmp_next = NULL;
}
#endif
in6_ifa_hold(ifa); in6_ifa_hold(ifa);
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
read_unlock(&addrconf_lock); read_unlock(&addrconf_lock);
...@@ -422,6 +484,15 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) ...@@ -422,6 +484,15 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
ifp->dead = 1; ifp->dead = 1;
#ifdef CONFIG_IPV6_PRIVACY
spin_lock_bh(&ifp->lock);
if (ifp->ifpub) {
__in6_ifa_put(ifp->ifpub);
ifp->ifpub = NULL;
}
spin_unlock_bh(&ifp->lock);
#endif
write_lock_bh(&addrconf_hash_lock); write_lock_bh(&addrconf_hash_lock);
for (ifap = &inet6_addr_lst[hash]; (ifa=*ifap) != NULL; for (ifap = &inet6_addr_lst[hash]; (ifa=*ifap) != NULL;
ifap = &ifa->lst_next) { ifap = &ifa->lst_next) {
...@@ -435,6 +506,24 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) ...@@ -435,6 +506,24 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
write_unlock_bh(&addrconf_hash_lock); write_unlock_bh(&addrconf_hash_lock);
write_lock_bh(&idev->lock); write_lock_bh(&idev->lock);
#ifdef CONFIG_IPV6_PRIVACY
if (ifp->flags&IFA_F_TEMPORARY) {
for (ifap = &idev->tempaddr_list; (ifa=*ifap) != NULL;
ifap = &ifa->tmp_next) {
if (ifa == ifp) {
*ifap = ifa->tmp_next;
if (ifp->ifpub) {
__in6_ifa_put(ifp->ifpub);
ifp->ifpub = NULL;
}
__in6_ifa_put(ifp);
ifa->tmp_next = NULL;
break;
}
}
}
#endif
for (ifap = &idev->addr_list; (ifa=*ifap) != NULL; for (ifap = &idev->addr_list; (ifa=*ifap) != NULL;
ifap = &ifa->if_next) { ifap = &ifa->if_next) {
if (ifa == ifp) { if (ifa == ifp) {
...@@ -455,6 +544,96 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) ...@@ -455,6 +544,96 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
in6_ifa_put(ifp); in6_ifa_put(ifp);
} }
#ifdef CONFIG_IPV6_PRIVACY
static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *ift)
{
struct inet6_dev *idev;
struct in6_addr addr, *tmpaddr;
unsigned long tmp_prefered_lft, tmp_valid_lft;
int tmp_plen;
int ret = 0;
if (ift) {
spin_lock_bh(&ift->lock);
memcpy(&addr.s6_addr[8], &ift->addr.s6_addr[8], 8);
spin_unlock_bh(&ift->lock);
tmpaddr = &addr;
} else {
tmpaddr = NULL;
}
retry:
spin_lock_bh(&ifp->lock);
in6_ifa_hold(ifp);
idev = ifp->idev;
in6_dev_hold(idev);
memcpy(addr.s6_addr, ifp->addr.s6_addr, 8);
write_lock(&idev->lock);
if (idev->cnf.use_tempaddr <= 0) {
write_unlock(&idev->lock);
spin_unlock_bh(&ifp->lock);
printk(KERN_INFO
"ipv6_create_tempaddr(): use_tempaddr is disabled.\n");
in6_dev_put(idev);
in6_ifa_put(ifp);
ret = -1;
goto out;
}
if (ifp->regen_count++ >= idev->cnf.regen_max_retry) {
idev->cnf.use_tempaddr = -1; /*XXX*/
write_unlock(&idev->lock);
spin_unlock_bh(&ifp->lock);
printk(KERN_WARNING
"ipv6_create_tempaddr(): regeneration time exceeded. disabled temporary address support.\n");
in6_dev_put(idev);
in6_ifa_put(ifp);
ret = -1;
goto out;
}
if (__ipv6_try_regen_rndid(idev, tmpaddr) < 0) {
write_unlock(&idev->lock);
spin_unlock_bh(&ifp->lock);
printk(KERN_WARNING
"ipv6_create_tempaddr(): regeneration of randomized interface id failed.\n");
in6_dev_put(idev);
in6_ifa_put(ifp);
ret = -1;
goto out;
}
memcpy(&addr.s6_addr[8], idev->rndid, 8);
tmp_valid_lft = min_t(__u32,
ifp->valid_lft,
idev->cnf.temp_valid_lft);
tmp_prefered_lft = min_t(__u32,
ifp->prefered_lft,
idev->cnf.temp_prefered_lft - desync_factor / HZ);
tmp_plen = ifp->prefix_len;
write_unlock(&idev->lock);
spin_unlock_bh(&ifp->lock);
ift = ipv6_count_addresses(idev) < IPV6_MAX_ADDRESSES ?
ipv6_add_addr(idev, &addr, tmp_plen,
ipv6_addr_type(&addr)&IPV6_ADDR_SCOPE_MASK, IFA_F_TEMPORARY) : 0;
if (!ift) {
in6_dev_put(idev);
in6_ifa_put(ifp);
printk(KERN_INFO
"ipv6_create_tempaddr(): retry temporary address regeneration.\n");
tmpaddr = &addr;
goto retry;
}
spin_lock_bh(&ift->lock);
ift->ifpub = ifp;
ift->valid_lft = tmp_valid_lft;
ift->prefered_lft = tmp_prefered_lft;
ift->tstamp = ifp->tstamp;
spin_unlock_bh(&ift->lock);
addrconf_dad_start(ift);
in6_ifa_put(ift);
in6_dev_put(idev);
out:
return ret;
}
#endif
/* /*
* Choose an apropriate source address * Choose an apropriate source address
* should do: * should do:
...@@ -463,6 +642,22 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp) ...@@ -463,6 +642,22 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
* an address of the attached interface * an address of the attached interface
* iii) don't use deprecated addresses * iii) don't use deprecated addresses
*/ */
static int inline ipv6_saddr_pref(const struct inet6_ifaddr *ifp, u8 invpref)
{
int pref;
pref = ifp->flags&IFA_F_DEPRECATED ? 0 : 2;
#ifdef CONFIG_IPV6_PRIVACY
pref |= (ifp->flags^invpref)&IFA_F_TEMPORARY ? 0 : 1;
#endif
return pref;
}
#ifdef CONFIG_IPV6_PRIVACY
#define IPV6_GET_SADDR_MAXSCORE(score) ((score) == 3)
#else
#define IPV6_GET_SADDR_MAXSCORE(score) (score)
#endif
int ipv6_get_saddr(struct dst_entry *dst, int ipv6_get_saddr(struct dst_entry *dst,
struct in6_addr *daddr, struct in6_addr *saddr) struct in6_addr *daddr, struct in6_addr *saddr)
{ {
...@@ -473,6 +668,7 @@ int ipv6_get_saddr(struct dst_entry *dst, ...@@ -473,6 +668,7 @@ int ipv6_get_saddr(struct dst_entry *dst,
struct inet6_dev *idev; struct inet6_dev *idev;
struct rt6_info *rt; struct rt6_info *rt;
int err; int err;
int hiscore = -1, score;
rt = (struct rt6_info *) dst; rt = (struct rt6_info *) dst;
if (rt) if (rt)
...@@ -502,17 +698,27 @@ int ipv6_get_saddr(struct dst_entry *dst, ...@@ -502,17 +698,27 @@ int ipv6_get_saddr(struct dst_entry *dst,
read_lock_bh(&idev->lock); read_lock_bh(&idev->lock);
for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
if (ifp->scope == scope) { if (ifp->scope == scope) {
if (!(ifp->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))) { if (ifp->flags&IFA_F_TENTATIVE)
in6_ifa_hold(ifp); continue;
#ifdef CONFIG_IPV6_PRIVACY
score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);
#else
score = ipv6_saddr_pref(ifp, 0);
#endif
if (score <= hiscore)
continue;
if (match)
in6_ifa_put(match);
match = ifp;
hiscore = score;
in6_ifa_hold(ifp);
if (IPV6_GET_SADDR_MAXSCORE(score)) {
read_unlock_bh(&idev->lock); read_unlock_bh(&idev->lock);
read_unlock(&addrconf_lock); read_unlock(&addrconf_lock);
goto out; goto out;
} }
if (!match && !(ifp->flags & IFA_F_TENTATIVE)) {
match = ifp;
in6_ifa_hold(ifp);
}
} }
} }
read_unlock_bh(&idev->lock); read_unlock_bh(&idev->lock);
...@@ -535,16 +741,26 @@ int ipv6_get_saddr(struct dst_entry *dst, ...@@ -535,16 +741,26 @@ int ipv6_get_saddr(struct dst_entry *dst,
read_lock_bh(&idev->lock); read_lock_bh(&idev->lock);
for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) { for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
if (ifp->scope == scope) { if (ifp->scope == scope) {
if (!(ifp->flags&(IFA_F_DEPRECATED|IFA_F_TENTATIVE))) { if (ifp->flags&IFA_F_TENTATIVE)
in6_ifa_hold(ifp); continue;
#ifdef CONFIG_IPV6_PRIVACY
score = ipv6_saddr_pref(ifp, idev->cnf.use_tempaddr > 1 ? IFA_F_TEMPORARY : 0);
#else
score = ipv6_saddr_pref(ifp, 0);
#endif
if (score <= hiscore)
continue;
if (match)
in6_ifa_put(match);
match = ifp;
hiscore = score;
in6_ifa_hold(ifp);
if (IPV6_GET_SADDR_MAXSCORE(score)) {
read_unlock_bh(&idev->lock); read_unlock_bh(&idev->lock);
goto out_unlock_base; goto out_unlock_base;
} }
if (!match && !(ifp->flags&IFA_F_TENTATIVE)) {
match = ifp;
in6_ifa_hold(ifp);
}
} }
} }
read_unlock_bh(&idev->lock); read_unlock_bh(&idev->lock);
...@@ -556,19 +772,12 @@ int ipv6_get_saddr(struct dst_entry *dst, ...@@ -556,19 +772,12 @@ int ipv6_get_saddr(struct dst_entry *dst,
read_unlock(&dev_base_lock); read_unlock(&dev_base_lock);
out: out:
if (ifp == NULL) {
ifp = match;
match = NULL;
}
err = -EADDRNOTAVAIL; err = -EADDRNOTAVAIL;
if (ifp) { if (match) {
ipv6_addr_copy(saddr, &ifp->addr); ipv6_addr_copy(saddr, &match->addr);
err = 0; err = 0;
in6_ifa_put(ifp);
}
if (match)
in6_ifa_put(match); in6_ifa_put(match);
}
return err; return err;
} }
...@@ -658,6 +867,21 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp) ...@@ -658,6 +867,21 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
ifp->flags |= IFA_F_TENTATIVE; ifp->flags |= IFA_F_TENTATIVE;
spin_unlock_bh(&ifp->lock); spin_unlock_bh(&ifp->lock);
in6_ifa_put(ifp); in6_ifa_put(ifp);
#ifdef CONFIG_IPV6_PRIVACY
} else if (ifp->flags&IFA_F_TEMPORARY) {
struct inet6_ifaddr *ifpub;
spin_lock_bh(&ifp->lock);
ifpub = ifp->ifpub;
if (ifpub) {
in6_ifa_hold(ifpub);
spin_unlock_bh(&ifp->lock);
ipv6_create_tempaddr(ifpub, ifp);
in6_ifa_put(ifpub);
} else {
spin_unlock_bh(&ifp->lock);
}
ipv6_del_addr(ifp);
#endif
} else } else
ipv6_del_addr(ifp); ipv6_del_addr(ifp);
} }
...@@ -723,6 +947,108 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev) ...@@ -723,6 +947,108 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
return err; return err;
} }
#ifdef CONFIG_IPV6_PRIVACY
/* (re)generation of randomized interface identifier (RFC 3041 3.2, 3.5) */
static int __ipv6_regen_rndid(struct inet6_dev *idev)
{
struct net_device *dev;
u8 eui64[8];
u8 digest[16];
struct crypto_tfm *tfm;
struct scatterlist sg[2];
sg[0].page = virt_to_page(idev->entropy);
sg[0].offset = ((long) idev->entropy & ~PAGE_MASK);
sg[0].length = 8;
sg[1].page = virt_to_page(eui64);
sg[1].offset = ((long) eui64 & ~PAGE_MASK);
sg[1].length = 8;
if (!del_timer(&idev->regen_timer))
in6_dev_hold(idev);
dev = idev->dev;
if (ipv6_generate_eui64(eui64, dev)) {
printk(KERN_INFO
"__ipv6_regen_rndid(idev=%p): cannot get EUI64 identifier; use random bytes.\n",
idev);
get_random_bytes(eui64, sizeof(eui64));
}
regen:
tfm = crypto_alloc_tfm("md5", 0);
if (tfm == NULL) {
if (net_ratelimit())
printk(KERN_WARNING
"failed to load transform for md5\n");
in6_dev_put(idev);
return -1;
}
crypto_digest_init(tfm);
crypto_digest_update(tfm, sg, 2);
crypto_digest_final(tfm, digest);
crypto_free_tfm(tfm);
memcpy(idev->rndid, &digest[0], 8);
idev->rndid[0] &= ~0x02;
memcpy(idev->entropy, &digest[8], 8);
/*
* <draft-ietf-ipngwg-temp-addresses-v2-00.txt>:
* check if generated address is not inappropriate
*
* - Reserved subnet anycast (RFC 2526)
* 11111101 11....11 1xxxxxxx
* - ISATAP (draft-ietf-ngtrans-isatap-01.txt) 4.3
* 00-00-5E-FE-xx-xx-xx-xx
* - value 0
* - XXX: already assigned to an address on the device
*/
if (idev->rndid[0] == 0xfd &&
(idev->rndid[1]&idev->rndid[2]&idev->rndid[3]&idev->rndid[4]&idev->rndid[5]&idev->rndid[6]) &&
(idev->rndid[7]&0x80))
goto regen;
if ((idev->rndid[0]|idev->rndid[1]) == 0) {
if (idev->rndid[2] == 0x5e && idev->rndid[3] == 0xfe)
goto regen;
if ((idev->rndid[2]|idev->rndid[3]|idev->rndid[4]|idev->rndid[5]|idev->rndid[6]|idev->rndid[7]) == 0x00)
goto regen;
}
if (time_before(idev->regen_timer.expires, jiffies)) {
idev->regen_timer.expires = 0;
printk(KERN_WARNING
"__ipv6_regen_rndid(): too short regeneration interval; timer diabled for %s.\n",
idev->dev->name);
in6_dev_put(idev);
return -1;
}
add_timer(&idev->regen_timer);
return 0;
}
static void ipv6_regen_rndid(unsigned long data)
{
struct inet6_dev *idev = (struct inet6_dev *) data;
read_lock_bh(&addrconf_lock);
write_lock_bh(&idev->lock);
if (!idev->dead)
__ipv6_regen_rndid(idev);
write_unlock_bh(&idev->lock);
read_unlock_bh(&addrconf_lock);
}
static int __ipv6_try_regen_rndid(struct inet6_dev *idev, struct in6_addr *tmpaddr) {
int ret = 0;
if (tmpaddr && memcmp(idev->rndid, &tmpaddr->s6_addr[8], 8) == 0)
ret = __ipv6_regen_rndid(idev);
return ret;
}
#endif
/* /*
* Add prefix route. * Add prefix route.
*/ */
...@@ -894,6 +1220,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) ...@@ -894,6 +1220,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
struct inet6_ifaddr * ifp; struct inet6_ifaddr * ifp;
struct in6_addr addr; struct in6_addr addr;
int plen; int plen;
int create = 0;
plen = pinfo->prefix_len >> 3; plen = pinfo->prefix_len >> 3;
...@@ -929,6 +1256,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) ...@@ -929,6 +1256,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
return; return;
} }
create = 1;
addrconf_dad_start(ifp); addrconf_dad_start(ifp);
} }
...@@ -939,6 +1267,9 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) ...@@ -939,6 +1267,9 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
if (ifp) { if (ifp) {
int flags; int flags;
#ifdef CONFIG_IPV6_PRIVACY
struct inet6_ifaddr *ift;
#endif
spin_lock(&ifp->lock); spin_lock(&ifp->lock);
ifp->valid_lft = valid_lft; ifp->valid_lft = valid_lft;
...@@ -951,6 +1282,42 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) ...@@ -951,6 +1282,42 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
if (!(flags&IFA_F_TENTATIVE)) if (!(flags&IFA_F_TENTATIVE))
ipv6_ifa_notify((flags&IFA_F_DEPRECATED) ? ipv6_ifa_notify((flags&IFA_F_DEPRECATED) ?
0 : RTM_NEWADDR, ifp); 0 : RTM_NEWADDR, ifp);
#ifdef CONFIG_IPV6_PRIVACY
read_lock_bh(&in6_dev->lock);
/* update all temporary addresses in the list */
for (ift=in6_dev->tempaddr_list; ift; ift=ift->tmp_next) {
/*
* When adjusting the lifetimes of an existing
* temporary address, only lower the lifetimes.
* Implementations must not increase the
* lifetimes of an existing temporary address
* when processing a Prefix Information Option.
*/
spin_lock(&ift->lock);
flags = ift->flags;
if (ift->valid_lft > valid_lft &&
ift->valid_lft - valid_lft > (jiffies - ift->tstamp) / HZ)
ift->valid_lft = valid_lft + (jiffies - ift->tstamp) / HZ;
if (ift->prefered_lft > prefered_lft &&
ift->prefered_lft - prefered_lft > (jiffies - ift->tstamp) / HZ)
ift->prefered_lft = prefered_lft + (jiffies - ift->tstamp) / HZ;
spin_unlock(&ift->lock);
if (!(flags&IFA_F_TENTATIVE))
ipv6_ifa_notify(0, ift);
}
if (create && in6_dev->cnf.use_tempaddr > 0) {
/*
* When a new public address is created as described in [ADDRCONF],
* also create a new temporary address.
*/
read_unlock_bh(&in6_dev->lock);
ipv6_create_tempaddr(ifp, NULL);
} else {
read_unlock_bh(&in6_dev->lock);
}
#endif
in6_ifa_put(ifp); in6_ifa_put(ifp);
addrconf_verify(0); addrconf_verify(0);
} }
...@@ -1915,7 +2282,7 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp, ...@@ -1915,7 +2282,7 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
static struct addrconf_sysctl_table static struct addrconf_sysctl_table
{ {
struct ctl_table_header *sysctl_header; struct ctl_table_header *sysctl_header;
ctl_table addrconf_vars[11]; ctl_table addrconf_vars[16];
ctl_table addrconf_dev[2]; ctl_table addrconf_dev[2];
ctl_table addrconf_conf_dir[2]; ctl_table addrconf_conf_dir[2];
ctl_table addrconf_proto_dir[2]; ctl_table addrconf_proto_dir[2];
...@@ -1962,6 +2329,28 @@ static struct addrconf_sysctl_table ...@@ -1962,6 +2329,28 @@ static struct addrconf_sysctl_table
&ipv6_devconf.rtr_solicit_delay, sizeof(int), 0644, NULL, &ipv6_devconf.rtr_solicit_delay, sizeof(int), 0644, NULL,
&proc_dointvec_jiffies}, &proc_dointvec_jiffies},
#ifdef CONFIG_IPV6_PRIVACY
{NET_IPV6_USE_TEMPADDR, "use_tempaddr",
&ipv6_devconf.use_tempaddr, sizeof(int), 0644, NULL,
&proc_dointvec},
{NET_IPV6_TEMP_VALID_LFT, "temp_valid_lft",
&ipv6_devconf.temp_valid_lft, sizeof(int), 0644, NULL,
&proc_dointvec},
{NET_IPV6_TEMP_PREFERED_LFT, "temp_prefered_lft",
&ipv6_devconf.temp_prefered_lft, sizeof(int), 0644, NULL,
&proc_dointvec},
{NET_IPV6_REGEN_MAX_RETRY, "regen_max_retry",
&ipv6_devconf.regen_max_retry, sizeof(int), 0644, NULL,
&proc_dointvec},
{NET_IPV6_MAX_DESYNC_FACTOR, "max_desync_factor",
&ipv6_devconf.max_desync_factor, sizeof(int), 0644, NULL,
&proc_dointvec},
#endif
{0}}, {0}},
{{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, addrconf_sysctl.addrconf_vars},{0}}, {{NET_PROTO_CONF_ALL, "all", NULL, 0, 0555, addrconf_sysctl.addrconf_vars},{0}},
...@@ -1980,7 +2369,7 @@ static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf ...@@ -1980,7 +2369,7 @@ static void addrconf_sysctl_register(struct inet6_dev *idev, struct ipv6_devconf
if (t == NULL) if (t == NULL)
return; return;
memcpy(t, &addrconf_sysctl, sizeof(*t)); memcpy(t, &addrconf_sysctl, sizeof(*t));
for (i=0; i<sizeof(t->addrconf_vars)/sizeof(t->addrconf_vars[0])-1; i++) { for (i=0; t->addrconf_vars[i].data; i++) {
t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf; t->addrconf_vars[i].data += (char*)p - (char*)&ipv6_devconf;
t->addrconf_vars[i].de = NULL; t->addrconf_vars[i].de = NULL;
} }
......
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
* YOSHIFUJI Hideaki @USAGI: added sysctl for icmp rate limit. * YOSHIFUJI Hideaki @USAGI: added sysctl for icmp rate limit.
*/ */
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
...@@ -68,10 +67,12 @@ ...@@ -68,10 +67,12 @@
DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics); DEFINE_SNMP_STAT(struct icmpv6_mib, icmpv6_statistics);
/* /*
* ICMP socket for flow control. * ICMP socket(s) for flow control.
*/ */
struct socket *icmpv6_socket; /* XXX We can't use per_cpu because this can be modular... */
static struct socket *__icmpv6_socket[NR_CPUS];
#define icmpv6_socket __icmpv6_socket[smp_processor_id()]
static int icmpv6_rcv(struct sk_buff *skb); static int icmpv6_rcv(struct sk_buff *skb);
...@@ -88,40 +89,16 @@ struct icmpv6_msg { ...@@ -88,40 +89,16 @@ struct icmpv6_msg {
__u32 csum; __u32 csum;
}; };
static __inline__ void icmpv6_xmit_lock(void)
static int icmpv6_xmit_holder = -1;
static int icmpv6_xmit_lock_bh(void)
{ {
if (!spin_trylock(&icmpv6_socket->sk->lock.slock)) {
if (icmpv6_xmit_holder == smp_processor_id())
return -EAGAIN;
spin_lock(&icmpv6_socket->sk->lock.slock);
}
icmpv6_xmit_holder = smp_processor_id();
return 0;
}
static __inline__ int icmpv6_xmit_lock(void)
{
int ret;
local_bh_disable(); local_bh_disable();
ret = icmpv6_xmit_lock_bh(); if (unlikely(!spin_trylock(&icmpv6_socket->sk->lock.slock)))
if (ret) BUG();
local_bh_enable();
return ret;
}
static void icmpv6_xmit_unlock_bh(void)
{
icmpv6_xmit_holder = -1;
spin_unlock(&icmpv6_socket->sk->lock.slock);
} }
static __inline__ void icmpv6_xmit_unlock(void) static __inline__ void icmpv6_xmit_unlock(void)
{ {
icmpv6_xmit_unlock_bh(); spin_unlock_bh(&icmpv6_socket->sk->lock.slock);
local_bh_enable();
} }
...@@ -342,8 +319,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info, ...@@ -342,8 +319,7 @@ void icmpv6_send(struct sk_buff *skb, int type, int code, __u32 info,
fl.uli_u.icmpt.type = type; fl.uli_u.icmpt.type = type;
fl.uli_u.icmpt.code = code; fl.uli_u.icmpt.code = code;
if (icmpv6_xmit_lock()) icmpv6_xmit_lock();
return;
if (!icmpv6_xrlim_allow(sk, type, &fl)) if (!icmpv6_xrlim_allow(sk, type, &fl))
goto out; goto out;
...@@ -416,15 +392,14 @@ static void icmpv6_echo_reply(struct sk_buff *skb) ...@@ -416,15 +392,14 @@ static void icmpv6_echo_reply(struct sk_buff *skb)
fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY; fl.uli_u.icmpt.type = ICMPV6_ECHO_REPLY;
fl.uli_u.icmpt.code = 0; fl.uli_u.icmpt.code = 0;
if (icmpv6_xmit_lock_bh()) icmpv6_xmit_lock();
return;
ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1, ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1,
MSG_DONTWAIT); MSG_DONTWAIT);
ICMP6_INC_STATS_BH(Icmp6OutEchoReplies); ICMP6_INC_STATS_BH(Icmp6OutEchoReplies);
ICMP6_INC_STATS_BH(Icmp6OutMsgs); ICMP6_INC_STATS_BH(Icmp6OutMsgs);
icmpv6_xmit_unlock_bh(); icmpv6_xmit_unlock();
} }
static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info) static void icmpv6_notify(struct sk_buff *skb, int type, int code, u32 info)
...@@ -627,26 +602,47 @@ static int icmpv6_rcv(struct sk_buff *skb) ...@@ -627,26 +602,47 @@ static int icmpv6_rcv(struct sk_buff *skb)
int __init icmpv6_init(struct net_proto_family *ops) int __init icmpv6_init(struct net_proto_family *ops)
{ {
struct sock *sk; struct sock *sk;
int err; int i;
for (i = 0; i < NR_CPUS; i++) {
int err;
if (!cpu_possible(i))
continue;
err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6,
&__icmpv6_socket[i]);
if (err < 0) {
int j;
printk(KERN_ERR
"Failed to initialize the ICMP6 control socket "
"(err %d).\n",
err);
for (j = 0; j < i; j++) {
if (!cpu_possible(j))
continue;
sock_release(__icmpv6_socket[j]);
__icmpv6_socket[j] = NULL; /* for safety */
}
return err;
}
err = sock_create(PF_INET6, SOCK_RAW, IPPROTO_ICMPV6, &icmpv6_socket); sk = __icmpv6_socket[i]->sk;
if (err < 0) { sk->allocation = GFP_ATOMIC;
printk(KERN_ERR sk->sndbuf = SK_WMEM_MAX*2;
"Failed to initialize the ICMP6 control socket (err %d).\n", sk->prot->unhash(sk);
err);
icmpv6_socket = NULL; /* for safety */
return err;
} }
sk = icmpv6_socket->sk;
sk->allocation = GFP_ATOMIC;
sk->sndbuf = SK_WMEM_MAX*2;
sk->prot->unhash(sk);
if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) { if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0) {
printk(KERN_ERR "Failed to register ICMP6 protocol\n"); printk(KERN_ERR "Failed to register ICMP6 protocol\n");
sock_release(icmpv6_socket); for (i = 0; i < NR_CPUS; i++) {
icmpv6_socket = NULL; if (!cpu_possible(i))
continue;
sock_release(__icmpv6_socket[i]);
__icmpv6_socket[i] = NULL;
}
return -EAGAIN; return -EAGAIN;
} }
...@@ -655,8 +651,14 @@ int __init icmpv6_init(struct net_proto_family *ops) ...@@ -655,8 +651,14 @@ int __init icmpv6_init(struct net_proto_family *ops)
void icmpv6_cleanup(void) void icmpv6_cleanup(void)
{ {
sock_release(icmpv6_socket); int i;
icmpv6_socket = NULL; /* For safety. */
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_possible(i))
continue;
sock_release(__icmpv6_socket[i]);
__icmpv6_socket[i] = NULL; /* For safety. */
}
inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6); inet6_del_protocol(&icmpv6_protocol, IPPROTO_ICMPV6);
} }
......
...@@ -134,7 +134,7 @@ int ip6_output(struct sk_buff *skb) ...@@ -134,7 +134,7 @@ int ip6_output(struct sk_buff *skb)
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
static int route6_me_harder(struct sk_buff *skb) int ip6_route_me_harder(struct sk_buff *skb)
{ {
struct ipv6hdr *iph = skb->nh.ipv6h; struct ipv6hdr *iph = skb->nh.ipv6h;
struct dst_entry *dst; struct dst_entry *dst;
...@@ -152,7 +152,7 @@ static int route6_me_harder(struct sk_buff *skb) ...@@ -152,7 +152,7 @@ static int route6_me_harder(struct sk_buff *skb)
if (dst->error) { if (dst->error) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_DEBUG "route6_me_harder: No more route.\n"); printk(KERN_DEBUG "ip6_route_me_harder: No more route.\n");
return -EINVAL; return -EINVAL;
} }
...@@ -168,7 +168,7 @@ static inline int ip6_maybe_reroute(struct sk_buff *skb) ...@@ -168,7 +168,7 @@ static inline int ip6_maybe_reroute(struct sk_buff *skb)
{ {
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
if (skb->nfcache & NFC_ALTERED){ if (skb->nfcache & NFC_ALTERED){
if (route6_me_harder(skb) != 0){ if (ip6_route_me_harder(skb) != 0){
kfree_skb(skb); kfree_skb(skb);
return -EINVAL; return -EINVAL;
} }
......
...@@ -21,7 +21,6 @@ ...@@ -21,7 +21,6 @@
* o Return an optlen of the truncated length if need be * o Return an optlen of the truncated length if need be
*/ */
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
......
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <net/protocol.h> #include <net/protocol.h>
#include <net/ipv6.h> #include <net/ipv6.h>
...@@ -11,6 +12,9 @@ EXPORT_SYMBOL(ndisc_mc_map); ...@@ -11,6 +12,9 @@ EXPORT_SYMBOL(ndisc_mc_map);
EXPORT_SYMBOL(register_inet6addr_notifier); EXPORT_SYMBOL(register_inet6addr_notifier);
EXPORT_SYMBOL(unregister_inet6addr_notifier); EXPORT_SYMBOL(unregister_inet6addr_notifier);
EXPORT_SYMBOL(ip6_route_output); EXPORT_SYMBOL(ip6_route_output);
#ifdef CONFIG_NETFILTER
EXPORT_SYMBOL(ip6_route_me_harder);
#endif
EXPORT_SYMBOL(addrconf_lock); EXPORT_SYMBOL(addrconf_lock);
EXPORT_SYMBOL(ipv6_setsockopt); EXPORT_SYMBOL(ipv6_setsockopt);
EXPORT_SYMBOL(ipv6_getsockopt); EXPORT_SYMBOL(ipv6_getsockopt);
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
* - MLD for link-local addresses. * - MLD for link-local addresses.
*/ */
#define __NO_VERSION__
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/errno.h> #include <linux/errno.h>
......
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
#define ND_PRINTK2 ND_PRINTK #define ND_PRINTK2 ND_PRINTK
#endif #endif
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
......
...@@ -326,45 +326,6 @@ ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data) ...@@ -326,45 +326,6 @@ ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
return status; return status;
} }
/*
* Taken from net/ipv6/ip6_output.c
*
* We should use the one there, but is defined static
* so we put this just here and let the things as
* they are now.
*
* If that one is modified, this one should be modified too.
*/
static int
route6_me_harder(struct sk_buff *skb)
{
struct ipv6hdr *iph = skb->nh.ipv6h;
struct dst_entry *dst;
struct flowi fl;
fl.proto = iph->nexthdr;
fl.fl6_dst = &iph->daddr;
fl.fl6_src = &iph->saddr;
fl.oif = skb->sk ? skb->sk->bound_dev_if : 0;
fl.fl6_flowlabel = 0;
fl.uli_u.ports.dport = 0;
fl.uli_u.ports.sport = 0;
dst = ip6_route_output(skb->sk, &fl);
if (dst->error) {
if (net_ratelimit())
printk(KERN_DEBUG "route6_me_harder: No more route.\n");
return -EINVAL;
}
/* Drop old route. */
dst_release(skb->dst);
skb->dst = dst;
return 0;
}
static int static int
ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
{ {
...@@ -410,7 +371,7 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e) ...@@ -410,7 +371,7 @@ ipq_mangle_ipv6(ipq_verdict_msg_t *v, struct ipq_queue_entry *e)
struct ipv6hdr *iph = e->skb->nh.ipv6h; struct ipv6hdr *iph = e->skb->nh.ipv6h;
if (ipv6_addr_cmp(&iph->daddr, &e->rt_info.daddr) || if (ipv6_addr_cmp(&iph->daddr, &e->rt_info.daddr) ||
ipv6_addr_cmp(&iph->saddr, &e->rt_info.saddr)) ipv6_addr_cmp(&iph->saddr, &e->rt_info.saddr))
return route6_me_harder(e->skb); return ip6_route_me_harder(e->skb);
} }
return 0; return 0;
} }
......
...@@ -574,15 +574,17 @@ static int ip6_dst_gc() ...@@ -574,15 +574,17 @@ static int ip6_dst_gc()
Remove it only when all the things will work! Remove it only when all the things will work!
*/ */
static void ipv6_wash_prefix(struct in6_addr *pfx, int plen) static void ipv6_addr_prefix(struct in6_addr *pfx,
const struct in6_addr *addr, int plen)
{ {
int b = plen&0x7; int b = plen&0x7;
int o = (plen + 7)>>3; int o = plen>>3;
memcpy(pfx->s6_addr, addr, o);
if (o < 16) if (o < 16)
memset(pfx->s6_addr + o, 0, 16 - o); memset(pfx->s6_addr + o, 0, 16 - o);
if (b != 0) if (b != 0)
pfx->s6_addr[plen>>3] &= (0xFF<<(8-b)); pfx->s6_addr[o] = addr->s6_addr[o]&(0xff00 >> b);
} }
static int ipv6_get_mtu(struct net_device *dev) static int ipv6_get_mtu(struct net_device *dev)
...@@ -655,16 +657,16 @@ int ip6_route_add(struct in6_rtmsg *rtmsg) ...@@ -655,16 +657,16 @@ int ip6_route_add(struct in6_rtmsg *rtmsg)
goto out; goto out;
} }
ipv6_addr_copy(&rt->rt6i_dst.addr, &rtmsg->rtmsg_dst); ipv6_addr_prefix(&rt->rt6i_dst.addr,
&rtmsg->rtmsg_dst, rtmsg->rtmsg_dst_len);
rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len; rt->rt6i_dst.plen = rtmsg->rtmsg_dst_len;
if (rt->rt6i_dst.plen == 128) if (rt->rt6i_dst.plen == 128)
rt->u.dst.flags = DST_HOST; rt->u.dst.flags = DST_HOST;
ipv6_wash_prefix(&rt->rt6i_dst.addr, rt->rt6i_dst.plen);
#ifdef CONFIG_IPV6_SUBTREES #ifdef CONFIG_IPV6_SUBTREES
ipv6_addr_copy(&rt->rt6i_src.addr, &rtmsg->rtmsg_src); ipv6_addr_prefix(&rt->rt6i_src.addr,
&rtmsg->rtmsg_src, rtmsg->rtmsg_src_len);
rt->rt6i_src.plen = rtmsg->rtmsg_src_len; rt->rt6i_src.plen = rtmsg->rtmsg_src_len;
ipv6_wash_prefix(&rt->rt6i_src.addr, rt->rt6i_src.plen);
#endif #endif
rt->rt6i_metric = rtmsg->rtmsg_metric; rt->rt6i_metric = rtmsg->rtmsg_metric;
......
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
* Nate Thompson <nate@thebog.net>: 6to4 support * Nate Thompson <nate@thebog.net>: 6to4 support
*/ */
#define __NO_VERSION__
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/errno.h> #include <linux/errno.h>
......
...@@ -24,7 +24,6 @@ ...@@ -24,7 +24,6 @@
* 2 of the License, or (at your option) any later version. * 2 of the License, or (at your option) any later version.
*/ */
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/config.h> #include <linux/config.h>
#include <linux/errno.h> #include <linux/errno.h>
......
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
......
...@@ -585,6 +585,16 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) ...@@ -585,6 +585,16 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
read_unlock(&nl_table_lock); read_unlock(&nl_table_lock);
} }
static inline void netlink_rcv_wake(struct sock *sk)
{
struct netlink_opt *nlk = nlk_sk(sk);
if (skb_queue_len(&sk->receive_queue) == 0)
clear_bit(0, &nlk->state);
if (!test_bit(0, &nlk->state))
wake_up_interruptible(&nlk->wait);
}
static int netlink_sendmsg(struct kiocb *iocb, struct socket *sock, static int netlink_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, int len, struct msghdr *msg, int len,
struct scm_cookie *scm) struct scm_cookie *scm)
...@@ -706,12 +716,7 @@ static int netlink_recvmsg(struct kiocb *iocb, struct socket *sock, ...@@ -706,12 +716,7 @@ static int netlink_recvmsg(struct kiocb *iocb, struct socket *sock,
netlink_dump(sk); netlink_dump(sk);
out: out:
if (skb_queue_len(&sk->receive_queue) <= sk->rcvbuf/2) { netlink_rcv_wake(sk);
if (skb_queue_len(&sk->receive_queue) == 0)
clear_bit(0, &nlk->state);
if (!test_bit(0, &nlk->state))
wake_up_interruptible(&nlk->wait);
}
return err ? : copied; return err ? : copied;
} }
...@@ -721,13 +726,7 @@ void netlink_data_ready(struct sock *sk, int len) ...@@ -721,13 +726,7 @@ void netlink_data_ready(struct sock *sk, int len)
if (nlk->data_ready) if (nlk->data_ready)
nlk->data_ready(sk, len); nlk->data_ready(sk, len);
netlink_rcv_wake(sk);
if (skb_queue_len(&sk->receive_queue) <= sk->rcvbuf/2) {
if (skb_queue_len(&sk->receive_queue) == 0)
clear_bit(0, &nlk->state);
if (!test_bit(0, &nlk->state))
wake_up_interruptible(&nlk->wait);
}
} }
/* /*
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) * Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/ */
#include <linux/config.h> #include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/kernel.h> #include <linux/kernel.h>
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk) * Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/ */
#include <linux/config.h> #include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/kernel.h> #include <linux/kernel.h>
......
...@@ -45,7 +45,6 @@ ...@@ -45,7 +45,6 @@
* be incorporated into the next SCTP release. * be incorporated into the next SCTP release.
*/ */
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/types.h> #include <linux/types.h>
......
...@@ -38,7 +38,6 @@ ...@@ -38,7 +38,6 @@
*/ */
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/types.h> #include <linux/types.h>
......
#define __NO_VERSION__
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de> * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
*/ */
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <linux/init.h> #include <linux/init.h>
......
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
* Copyright (C) 1997 Olaf Kirch <okir@monad.swb.de> * Copyright (C) 1997 Olaf Kirch <okir@monad.swb.de>
*/ */
#define __NO_VERSION__
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
......
...@@ -14,7 +14,6 @@ ...@@ -14,7 +14,6 @@
#include <linux/ctype.h> #include <linux/ctype.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/sysctl.h> #include <linux/sysctl.h>
#define __NO_VERSION__
#include <linux/module.h> #include <linux/module.h>
#include <asm/uaccess.h> #include <asm/uaccess.h>
......
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