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
0 to disable any limiting, otherwise the maximal rate in jiffies(1)
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:
Pekka Savola <pekkas@netcore.fi>
YOSHIFUJI Hideaki / USAGI Project <yoshfuji@linux-ipv6.org>
......
......@@ -1262,6 +1262,8 @@ P: Alexey Kuznetsov
M: kuznet@ms2.inr.ac.ru
P: Pekka Savola (ipv6)
M: pekkas@netcore.fi
P: James Morris
M: jmorris@intercode.com.au
L: netdev@oss.sgi.com
S: Maintained
......
......@@ -336,6 +336,7 @@ enum
/* ifa_flags */
#define IFA_F_SECONDARY 0x01
#define IFA_F_TEMPORARY IFA_F_SECONDARY
#define IFA_F_DEPRECATED 0x20
#define IFA_F_TENTATIVE 0x40
......
......@@ -777,7 +777,7 @@ static inline int skb_is_nonlinear(const struct sk_buff *skb)
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;
}
......
......@@ -388,7 +388,12 @@ enum {
NET_IPV6_DAD_TRANSMITS=7,
NET_IPV6_RTR_SOLICITS=8,
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 */
......
......@@ -6,6 +6,11 @@
#define MAX_RTR_SOLICITATIONS 3
#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)
struct prefix_info {
......
......@@ -43,6 +43,12 @@ struct inet6_ifaddr
struct inet6_ifaddr *lst_next; /* next addr in addr_lst */
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;
};
......@@ -86,7 +92,13 @@ struct ipv6_devconf
int rtr_solicits;
int rtr_solicit_interval;
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;
};
......@@ -101,6 +113,13 @@ struct inet6_dev
__u32 if_flags;
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 inet6_dev *next;
struct ipv6_devconf cnf;
......
......@@ -30,6 +30,8 @@ extern void ip6_route_input(struct sk_buff *skb);
extern struct dst_entry * ip6_route_output(struct sock *sk,
struct flowi *fl);
extern int ip6_route_me_harder(struct sk_buff *skb);
extern void ip6_route_init(void);
extern void ip6_route_cleanup(void);
......
......@@ -20,6 +20,7 @@
#include <net/arp.h>
#include <net/dst.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
/* TokenRing if needed */
#ifdef CONFIG_TR
......@@ -35,6 +36,10 @@
#include <linux/if_bridge.h>
#include "../bridge/br_private.h"
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
/* Modular too */
......@@ -51,10 +56,7 @@ static unsigned char bridge_ula_lec[] = {0x01, 0x80, 0xc2, 0x00, 0x00};
#define DPRINTK(format,args...)
#endif
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);
static spinlock_t lec_arp_spinlock = SPIN_LOCK_UNLOCKED;
#define DUMP_PACKETS 0 /* 0 = None,
* 1 = 30 first bytes
......@@ -196,6 +198,23 @@ lec_open(struct net_device *dev)
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
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",
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]);
ATM_SKB(skb2)->vcc = send_vcc;
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,
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);
}
lec_send(send_vcc, skb2, priv);
}
lec_send(send_vcc, skb, priv);
#if 0
/* Should we wait for card's device driver to notify us? */
......@@ -1044,15 +1039,15 @@ void dump_arp_table(struct lec_priv *priv);
#define HASH(ch) (ch & (LEC_ARP_TABLE_SIZE -1))
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
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)
* LANE2: Add to the end of the list to satisfy 8.1.13
*/
static __inline__ void
lec_arp_put(struct lec_arp_table **lec_arp_tables,
struct lec_arp_table *to_put)
lec_arp_add(struct lec_arp_table **lec_arp_tables,
struct lec_arp_table *to_add)
{
unsigned short place;
unsigned long flags;
unsigned short place;
struct lec_arp_table *tmp;
save_flags(flags);
cli();
spin_lock_irqsave(&lec_arp_spinlock, flags);
place = HASH(to_put->mac_addr[ETH_ALEN-1]);
place = HASH(to_add->mac_addr[ETH_ALEN-1]);
tmp = lec_arp_tables[place];
to_put->next = NULL;
to_add->next = NULL;
if (tmp == NULL)
lec_arp_tables[place] = to_put;
lec_arp_tables[place] = to_add;
else { /* add to the end */
while (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",
0xff&to_put->mac_addr[0], 0xff&to_put->mac_addr[1],
0xff&to_put->mac_addr[2], 0xff&to_put->mac_addr[3],
0xff&to_put->mac_addr[4], 0xff&to_put->mac_addr[5]);
0xff&to_add->mac_addr[0], 0xff&to_add->mac_addr[1],
0xff&to_add->mac_addr[2], 0xff&to_add->mac_addr[3],
0xff&to_add->mac_addr[4], 0xff&to_add->mac_addr[5]);
}
/*
......@@ -1139,16 +1134,15 @@ static __inline__ int
lec_arp_remove(struct lec_arp_table **lec_arp_tables,
struct lec_arp_table *to_remove)
{
unsigned long flags;
unsigned short place;
struct lec_arp_table *tmp;
unsigned long flags;
int remove_vcc=1;
save_flags(flags);
cli();
spin_lock_irqsave(&lec_arp_spinlock, flags);
if (!to_remove) {
restore_flags(flags);
spin_unlock_irqrestore(&lec_arp_spinlock, flags);
return -1;
}
place = HASH(to_remove->mac_addr[ETH_ALEN-1]);
......@@ -1160,7 +1154,7 @@ lec_arp_remove(struct lec_arp_table **lec_arp_tables,
tmp = tmp->next;
}
if (!tmp) {/* Entry was not found */
restore_flags(flags);
spin_unlock_irqrestore(&lec_arp_spinlock, flags);
return -1;
}
}
......@@ -1186,7 +1180,9 @@ lec_arp_remove(struct lec_arp_table **lec_arp_tables,
lec_arp_clear_vccs(to_remove);
}
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",
0xff&to_remove->mac_addr[0], 0xff&to_remove->mac_addr[1],
0xff&to_remove->mac_addr[2], 0xff&to_remove->mac_addr[3],
......@@ -1371,12 +1367,8 @@ void
lec_arp_destroy(struct lec_priv *priv)
{
struct lec_arp_table *entry, *next;
unsigned long flags;
int i;
save_flags(flags);
cli();
del_timer(&priv->lec_arp_timer);
/*
......@@ -1419,7 +1411,6 @@ lec_arp_destroy(struct lec_priv *priv)
priv->mcast_vcc = NULL;
memset(priv->lec_arp_tables, 0,
sizeof(struct lec_arp_table*)*LEC_ARP_TABLE_SIZE);
restore_flags(flags);
}
......@@ -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",
mac_addr[0]&0xff, mac_addr[1]&0xff, mac_addr[2]&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]);
to_return = priv->lec_arp_tables[place];
while(to_return) {
if (memcmp(mac_addr, to_return->mac_addr, ETH_ALEN) == 0) {
lec_arp_unlock(priv);
lec_arp_put(priv);
return to_return;
}
to_return = to_return->next;
}
lec_arp_unlock(priv);
lec_arp_put(priv);
return NULL;
}
......@@ -1574,11 +1565,11 @@ lec_arp_check_expire(unsigned long data)
del_timer(&priv->lec_arp_timer);
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,
priv->lec_no_forward);
if (!priv->lec_arp_lock_var.counter) {
lec_arp_lock(priv);
if (!atomic_read(&priv->lec_arp_users)) {
lec_arp_get(priv);
now = jiffies;
for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
for(entry = lec_arp_tables[i];entry != NULL;) {
......@@ -1616,6 +1607,10 @@ lec_arp_check_expire(unsigned long data)
&&
time_after_eq(now, entry->timestamp+
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->status =
ESI_FORWARD_DIRECT;
......@@ -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;
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,
if (!entry) {
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 */
entry->packets_flooded =1;
entry->status = ESI_ARP_PENDING;
......@@ -1711,7 +1706,7 @@ lec_addr_delete(struct lec_priv *priv, unsigned char *atm_addr,
struct lec_arp_table *entry, *next;
int i;
lec_arp_lock(priv);
lec_arp_get(priv);
DPRINTK("lec_addr_delete\n");
for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
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,
lec_arp_remove(priv->lec_arp_tables, entry);
kfree(entry);
}
lec_arp_unlock(priv);
lec_arp_put(priv);
return 0;
}
}
lec_arp_unlock(priv);
lec_arp_put(priv);
return -1;
}
......@@ -1751,7 +1746,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
return; /* LANE2: ignore targetless LE_ARPs for which
* we have no entry in the cache. 7.1.30
*/
lec_arp_lock(priv);
lec_arp_get(priv);
if (priv->lec_arp_empty_ones) {
entry = priv->lec_arp_empty_ones;
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,
entry->status = ESI_FORWARD_DIRECT;
memcpy(entry->mac_addr, mac_addr, ETH_ALEN);
entry->last_used = jiffies;
lec_arp_put(priv->lec_arp_tables, entry);
lec_arp_add(priv->lec_arp_tables, entry);
}
if (remoteflag)
entry->flags|=LEC_REMOTE_FLAG;
else
entry->flags&=~LEC_REMOTE_FLAG;
lec_arp_unlock(priv);
lec_arp_put(priv);
DPRINTK("After update\n");
dump_arp_table(priv);
return;
......@@ -1801,11 +1796,11 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
if (!entry) {
entry = make_entry(priv, mac_addr);
if (!entry) {
lec_arp_unlock(priv);
lec_arp_put(priv);
return;
}
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 */
}
memcpy(entry->atm_addr, atm_addr, ATM_ESA_LEN);
......@@ -1840,7 +1835,7 @@ lec_arp_update(struct lec_priv *priv, unsigned char *mac_addr,
}
DPRINTK("After update2\n");
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,
struct lec_arp_table *entry;
int i, found_entry=0;
lec_arp_lock(priv);
lec_arp_get(priv);
if (ioc_data->receive == 2) {
/* 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,
entry = lec_arp_find(priv, bus_mac);
if (!entry) {
printk("LEC_ARP: Multicast entry not found!\n");
lec_arp_unlock(priv);
lec_arp_put(priv);
return;
}
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,
#endif
entry = make_entry(priv, bus_mac);
if (entry == NULL) {
lec_arp_unlock(priv);
lec_arp_put(priv);
return;
}
del_timer(&entry->timer);
......@@ -1881,7 +1876,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
entry->old_recv_push = old_push;
entry->next = priv->mcast_fwds;
priv->mcast_fwds = entry;
lec_arp_unlock(priv);
lec_arp_put(priv);
return;
} else if (ioc_data->receive == 1) {
/* 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,
ioc_data->atm_addr[18],ioc_data->atm_addr[19]);
entry = make_entry(priv, bus_mac);
if (entry == NULL) {
lec_arp_unlock(priv);
lec_arp_put(priv);
return;
}
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,
add_timer(&entry->timer);
entry->next = priv->lec_no_forward;
priv->lec_no_forward = entry;
lec_arp_unlock(priv);
lec_arp_put(priv);
dump_arp_table(priv);
return;
}
......@@ -1971,7 +1966,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
}
}
if (found_entry) {
lec_arp_unlock(priv);
lec_arp_put(priv);
DPRINTK("After vcc was added\n");
dump_arp_table(priv);
return;
......@@ -1980,7 +1975,7 @@ lec_vcc_added(struct lec_priv *priv, struct atmlec_ioc *ioc_data,
this vcc */
entry = make_entry(priv, bus_mac);
if (!entry) {
lec_arp_unlock(priv);
lec_arp_put(priv);
return;
}
entry->vcc = vcc;
......@@ -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.function = lec_arp_expire_vcc;
add_timer(&entry->timer);
lec_arp_unlock(priv);
lec_arp_put(priv);
DPRINTK("After vcc was added\n");
dump_arp_table(priv);
}
......@@ -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) {
if (entry->flush_tran_id == tran_id &&
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;
DPRINTK("LEC_ARP: Flushed\n");
}
......@@ -2039,10 +2038,10 @@ lec_mcast_make(struct lec_priv *priv, struct atm_vcc *vcc)
0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
struct lec_arp_table *to_add;
lec_arp_lock(priv);
lec_arp_get(priv);
to_add = make_entry(priv, mac_addr);
if (!to_add) {
lec_arp_unlock(priv);
lec_arp_put(priv);
return -ENOMEM;
}
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)
to_add->old_push = vcc->push;
vcc->push = lec_push;
priv->mcast_vcc = vcc;
lec_arp_put(priv->lec_arp_tables, to_add);
lec_arp_unlock(priv);
lec_arp_add(priv->lec_arp_tables, to_add);
lec_arp_put(priv);
return 0;
}
......@@ -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);
dump_arp_table(priv);
lec_arp_lock(priv);
lec_arp_get(priv);
for(i=0;i<LEC_ARP_TABLE_SIZE;i++) {
for(entry = priv->lec_arp_tables[i];entry; entry=next) {
next = entry->next;
......@@ -2127,7 +2126,7 @@ lec_vcc_close(struct lec_priv *priv, struct atm_vcc *vcc)
entry = next;
}
lec_arp_unlock(priv);
lec_arp_put(priv);
dump_arp_table(priv);
}
......@@ -2135,9 +2134,9 @@ void
lec_arp_check_empties(struct lec_priv *priv,
struct atm_vcc *vcc, struct sk_buff *skb)
{
unsigned long flags;
struct lec_arp_table *entry, *prev;
struct lecdatahdr_8023 *hdr = (struct lecdatahdr_8023 *)skb->data;
unsigned long flags;
unsigned char *src;
#ifdef CONFIG_TR
struct lecdatahdr_8025 *tr_hdr = (struct lecdatahdr_8025 *)skb->data;
......@@ -2147,26 +2146,26 @@ lec_arp_check_empties(struct lec_priv *priv,
#endif
src = hdr->h_source;
lec_arp_lock(priv);
lec_arp_get(priv);
entry = priv->lec_arp_empty_ones;
if (vcc == entry->vcc) {
save_flags(flags);
cli();
spin_lock_irqsave(&lec_arp_spinlock, flags);
del_timer(&entry->timer);
memcpy(entry->mac_addr, src, ETH_ALEN);
entry->status = ESI_FORWARD_DIRECT;
entry->last_used = jiffies;
priv->lec_arp_empty_ones = entry->next;
restore_flags(flags);
spin_unlock_irqrestore(&lec_arp_spinlock, flags);
/* We might have got an entry */
if ((prev=lec_arp_find(priv,src))) {
lec_arp_remove(priv->lec_arp_tables, prev);
kfree(prev);
}
lec_arp_put(priv->lec_arp_tables, entry);
lec_arp_unlock(priv);
lec_arp_add(priv->lec_arp_tables, entry);
lec_arp_put(priv);
return;
}
spin_lock_irqsave(&lec_arp_spinlock, flags);
prev = entry;
entry = entry->next;
while (entry && entry->vcc != vcc) {
......@@ -2175,22 +2174,21 @@ lec_arp_check_empties(struct lec_priv *priv,
}
if (!entry) {
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;
}
save_flags(flags);
cli();
del_timer(&entry->timer);
memcpy(entry->mac_addr, src, ETH_ALEN);
entry->status = ESI_FORWARD_DIRECT;
entry->last_used = jiffies;
prev->next = entry->next;
restore_flags(flags);
spin_unlock_irqrestore(&lec_arp_spinlock, flags);
if ((prev = lec_arp_find(priv, src))) {
lec_arp_remove(priv->lec_arp_tables,prev);
kfree(prev);
}
lec_arp_put(priv->lec_arp_tables,entry);
lec_arp_unlock(priv);
lec_arp_add(priv->lec_arp_tables,entry);
lec_arp_put(priv);
}
MODULE_LICENSE("GPL");
......@@ -98,7 +98,7 @@ struct lec_priv {
establishes multiple Multicast Forward VCCs to us. This list
collects all those VCCs. LANEv1 client has only one item in this
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 *lecd;
struct timer_list lec_arp_timer;
......
......@@ -43,6 +43,7 @@
#include <linux/socket.h>
#include <linux/ioctl.h>
#include <linux/file.h>
#include <linux/init.h>
#include <net/sock.h>
#include <asm/system.h>
......
......@@ -223,57 +223,28 @@ struct icmp_control {
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
* all layers. All Socketless IP sends will soon be gone.
*
* On SMP we have one ICMP socket per-cpu.
*/
struct socket *icmp_socket;
/* 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 DEFINE_PER_CPU(struct socket *, __icmp_socket) = NULL;
#define icmp_socket per_cpu(__icmp_socket, smp_processor_id())
static __inline__ int icmp_xmit_lock(void)
static __inline__ void icmp_xmit_lock(void)
{
int ret;
local_bh_disable();
ret = icmp_xmit_lock_bh();
if (ret)
local_bh_enable();
return ret;
}
static void icmp_xmit_unlock_bh(void)
{
icmp_xmit_holder = -1;
spin_unlock(&icmp_socket->sk->lock.slock);
if (unlikely(!spin_trylock(&icmp_socket->sk->lock.slock)))
BUG();
}
static __inline__ void icmp_xmit_unlock(void)
static void icmp_xmit_unlock(void)
{
icmp_xmit_unlock_bh();
local_bh_enable();
spin_unlock_bh(&icmp_socket->sk->lock.slock);
}
/*
* Send an ICMP frame.
*/
......@@ -404,10 +375,11 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
struct rtable *rt = (struct rtable *)skb->dst;
u32 daddr;
if (ip_options_echo(&icmp_param->replyopts, skb) ||
icmp_xmit_lock_bh())
if (ip_options_echo(&icmp_param->replyopts, skb))
goto out;
icmp_xmit_lock();
icmp_param->data.icmph.checksum = 0;
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)
icmp_push_reply(icmp_param, &ipc, rt);
ip_rt_put(rt);
out_unlock:
icmp_xmit_unlock_bh();
icmp_xmit_unlock();
out:;
}
......@@ -519,8 +491,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, u32 info)
}
}
if (icmp_xmit_lock())
goto out;
icmp_xmit_lock();
/*
* Construct source address and options.
......@@ -1141,19 +1112,30 @@ static struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
void __init icmp_init(struct net_proto_family *ops)
{
struct inet_opt *inet;
int err = sock_create(PF_INET, SOCK_RAW, IPPROTO_ICMP, &icmp_socket);
if (err < 0)
panic("Failed to create the ICMP control socket.\n");
icmp_socket->sk->allocation = GFP_ATOMIC;
icmp_socket->sk->sndbuf = SK_WMEM_MAX * 2;
inet = inet_sk(icmp_socket->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.
*/
icmp_socket->sk->prot->unhash(icmp_socket->sk);
int i;
for (i = 0; i < NR_CPUS; i++) {
int err;
if (!cpu_possible(i))
continue;
err = sock_create(PF_INET, SOCK_RAW, IPPROTO_ICMP,
&per_cpu(__icmp_socket, i));
if (err < 0)
panic("Failed to create the ICMP control socket.\n");
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 @@
* - export ip_conntrack[_expect]_{find_get,put} functions
* */
#ifdef MODULE
#define __NO_VERSION__
#endif
#include <linux/version.h>
#include <linux/config.h>
#include <linux/types.h>
......
#define __NO_VERSION__
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/timer.h>
......
......@@ -2,9 +2,6 @@
/* (c) 1999 Paul `Rusty' Russell. Licenced under the GNU General
Public Licence. */
#ifdef MODULE
#define __NO_VERSION__
#endif
#include <linux/version.h>
#include <linux/module.h>
#include <linux/types.h>
......
/* Everything about the rules for NAT. */
#define __NO_VERSION__
#include <linux/types.h>
#include <linux/ip.h>
#include <linux/netfilter.h>
......
#
# 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"
......@@ -28,6 +28,8 @@
* packets.
* YOSHIFUJI Hideaki @USAGI : improved accuracy of
* address validation timer.
* YOSHIFUJI Hideaki @USAGI : Privacy Extensions (RFC3041)
* support.
*/
#include <linux/config.h>
......@@ -62,6 +64,12 @@
#include <linux/if_tunnel.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>
#define IPV6_MAX_ADDRESSES 16
......@@ -83,6 +91,16 @@ static void addrconf_sysctl_unregister(struct ipv6_devconf *p);
int inet6_dev_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
*/
......@@ -120,6 +138,13 @@ struct ipv6_devconf ipv6_devconf =
MAX_RTR_SOLICITATIONS, /* router solicits */
RTR_SOLICITATION_INTERVAL, /* rtr solicit interval */
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 =
......@@ -134,6 +159,13 @@ static struct ipv6_devconf ipv6_devconf_dflt =
MAX_RTR_SOLICITATIONS, /* router solicits */
RTR_SOLICITATION_INTERVAL, /* rtr solicit interval */
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 */
......@@ -277,6 +309,24 @@ static struct inet6_dev * ipv6_add_dev(struct net_device *dev)
/* We refer to the device */
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);
dev->ip6_ptr = ndev;
/* One reference from device */
......@@ -401,6 +451,18 @@ ipv6_add_addr(struct inet6_dev *idev, struct in6_addr *addr, int pfxlen,
/* Add to inet6_dev unicast addr list. */
ifa->if_next = idev->addr_list;
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);
write_unlock_bh(&idev->lock);
read_unlock(&addrconf_lock);
......@@ -422,6 +484,15 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
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);
for (ifap = &inet6_addr_lst[hash]; (ifa=*ifap) != NULL;
ifap = &ifa->lst_next) {
......@@ -435,6 +506,24 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
write_unlock_bh(&addrconf_hash_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;
ifap = &ifa->if_next) {
if (ifa == ifp) {
......@@ -455,6 +544,96 @@ static void ipv6_del_addr(struct inet6_ifaddr *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
* should do:
......@@ -463,6 +642,22 @@ static void ipv6_del_addr(struct inet6_ifaddr *ifp)
* an address of the attached interface
* 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,
struct in6_addr *daddr, struct in6_addr *saddr)
{
......@@ -473,6 +668,7 @@ int ipv6_get_saddr(struct dst_entry *dst,
struct inet6_dev *idev;
struct rt6_info *rt;
int err;
int hiscore = -1, score;
rt = (struct rt6_info *) dst;
if (rt)
......@@ -502,17 +698,27 @@ int ipv6_get_saddr(struct dst_entry *dst,
read_lock_bh(&idev->lock);
for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
if (ifp->scope == scope) {
if (!(ifp->flags & (IFA_F_DEPRECATED|IFA_F_TENTATIVE))) {
in6_ifa_hold(ifp);
if (ifp->flags&IFA_F_TENTATIVE)
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(&addrconf_lock);
goto out;
}
if (!match && !(ifp->flags & IFA_F_TENTATIVE)) {
match = ifp;
in6_ifa_hold(ifp);
}
}
}
read_unlock_bh(&idev->lock);
......@@ -535,16 +741,26 @@ int ipv6_get_saddr(struct dst_entry *dst,
read_lock_bh(&idev->lock);
for (ifp=idev->addr_list; ifp; ifp=ifp->if_next) {
if (ifp->scope == scope) {
if (!(ifp->flags&(IFA_F_DEPRECATED|IFA_F_TENTATIVE))) {
in6_ifa_hold(ifp);
if (ifp->flags&IFA_F_TENTATIVE)
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);
goto out_unlock_base;
}
if (!match && !(ifp->flags&IFA_F_TENTATIVE)) {
match = ifp;
in6_ifa_hold(ifp);
}
}
}
read_unlock_bh(&idev->lock);
......@@ -556,19 +772,12 @@ int ipv6_get_saddr(struct dst_entry *dst,
read_unlock(&dev_base_lock);
out:
if (ifp == NULL) {
ifp = match;
match = NULL;
}
err = -EADDRNOTAVAIL;
if (ifp) {
ipv6_addr_copy(saddr, &ifp->addr);
if (match) {
ipv6_addr_copy(saddr, &match->addr);
err = 0;
in6_ifa_put(ifp);
}
if (match)
in6_ifa_put(match);
}
return err;
}
......@@ -658,6 +867,21 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
ifp->flags |= IFA_F_TENTATIVE;
spin_unlock_bh(&ifp->lock);
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
ipv6_del_addr(ifp);
}
......@@ -723,6 +947,108 @@ static int ipv6_inherit_eui64(u8 *eui, struct inet6_dev *idev)
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.
*/
......@@ -894,6 +1220,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
struct inet6_ifaddr * ifp;
struct in6_addr addr;
int plen;
int create = 0;
plen = pinfo->prefix_len >> 3;
......@@ -929,6 +1256,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
return;
}
create = 1;
addrconf_dad_start(ifp);
}
......@@ -939,6 +1267,9 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
if (ifp) {
int flags;
#ifdef CONFIG_IPV6_PRIVACY
struct inet6_ifaddr *ift;
#endif
spin_lock(&ifp->lock);
ifp->valid_lft = valid_lft;
......@@ -951,6 +1282,42 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
if (!(flags&IFA_F_TENTATIVE))
ipv6_ifa_notify((flags&IFA_F_DEPRECATED) ?
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);
addrconf_verify(0);
}
......@@ -1915,7 +2282,7 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
static struct addrconf_sysctl_table
{
struct ctl_table_header *sysctl_header;
ctl_table addrconf_vars[11];
ctl_table addrconf_vars[16];
ctl_table addrconf_dev[2];
ctl_table addrconf_conf_dir[2];
ctl_table addrconf_proto_dir[2];
......@@ -1962,6 +2329,28 @@ static struct addrconf_sysctl_table
&ipv6_devconf.rtr_solicit_delay, sizeof(int), 0644, NULL,
&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}},
{{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
if (t == NULL)
return;
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].de = NULL;
}
......
......@@ -28,7 +28,6 @@
* YOSHIFUJI Hideaki @USAGI: added sysctl for icmp rate limit.
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
......@@ -68,10 +67,12 @@
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);
......@@ -88,40 +89,16 @@ struct icmpv6_msg {
__u32 csum;
};
static int icmpv6_xmit_holder = -1;
static int icmpv6_xmit_lock_bh(void)
static __inline__ void icmpv6_xmit_lock(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();
ret = icmpv6_xmit_lock_bh();
if (ret)
local_bh_enable();
return ret;
}
static void icmpv6_xmit_unlock_bh(void)
{
icmpv6_xmit_holder = -1;
spin_unlock(&icmpv6_socket->sk->lock.slock);
if (unlikely(!spin_trylock(&icmpv6_socket->sk->lock.slock)))
BUG();
}
static __inline__ void icmpv6_xmit_unlock(void)
{
icmpv6_xmit_unlock_bh();
local_bh_enable();
spin_unlock_bh(&icmpv6_socket->sk->lock.slock);
}
......@@ -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.code = code;
if (icmpv6_xmit_lock())
return;
icmpv6_xmit_lock();
if (!icmpv6_xrlim_allow(sk, type, &fl))
goto out;
......@@ -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.code = 0;
if (icmpv6_xmit_lock_bh())
return;
icmpv6_xmit_lock();
ip6_build_xmit(sk, icmpv6_getfrag, &msg, &fl, msg.len, NULL, -1,
MSG_DONTWAIT);
ICMP6_INC_STATS_BH(Icmp6OutEchoReplies);
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)
......@@ -627,26 +602,47 @@ static int icmpv6_rcv(struct sk_buff *skb)
int __init icmpv6_init(struct net_proto_family *ops)
{
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);
if (err < 0) {
printk(KERN_ERR
"Failed to initialize the ICMP6 control socket (err %d).\n",
err);
icmpv6_socket = NULL; /* for safety */
return err;
sk = __icmpv6_socket[i]->sk;
sk->allocation = GFP_ATOMIC;
sk->sndbuf = SK_WMEM_MAX*2;
sk->prot->unhash(sk);
}
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) {
printk(KERN_ERR "Failed to register ICMP6 protocol\n");
sock_release(icmpv6_socket);
icmpv6_socket = NULL;
for (i = 0; i < NR_CPUS; i++) {
if (!cpu_possible(i))
continue;
sock_release(__icmpv6_socket[i]);
__icmpv6_socket[i] = NULL;
}
return -EAGAIN;
}
......@@ -655,8 +651,14 @@ int __init icmpv6_init(struct net_proto_family *ops)
void icmpv6_cleanup(void)
{
sock_release(icmpv6_socket);
icmpv6_socket = NULL; /* For safety. */
int i;
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);
}
......
......@@ -134,7 +134,7 @@ int ip6_output(struct sk_buff *skb)
#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 dst_entry *dst;
......@@ -152,7 +152,7 @@ static int route6_me_harder(struct sk_buff *skb)
if (dst->error) {
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;
}
......@@ -168,7 +168,7 @@ static inline int ip6_maybe_reroute(struct sk_buff *skb)
{
#ifdef CONFIG_NETFILTER
if (skb->nfcache & NFC_ALTERED){
if (route6_me_harder(skb) != 0){
if (ip6_route_me_harder(skb) != 0){
kfree_skb(skb);
return -EINVAL;
}
......
......@@ -21,7 +21,6 @@
* o Return an optlen of the truncated length if need be
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/config.h>
#include <linux/errno.h>
......
#include <linux/config.h>
#include <linux/module.h>
#include <net/protocol.h>
#include <net/ipv6.h>
......@@ -11,6 +12,9 @@ EXPORT_SYMBOL(ndisc_mc_map);
EXPORT_SYMBOL(register_inet6addr_notifier);
EXPORT_SYMBOL(unregister_inet6addr_notifier);
EXPORT_SYMBOL(ip6_route_output);
#ifdef CONFIG_NETFILTER
EXPORT_SYMBOL(ip6_route_me_harder);
#endif
EXPORT_SYMBOL(addrconf_lock);
EXPORT_SYMBOL(ipv6_setsockopt);
EXPORT_SYMBOL(ipv6_getsockopt);
......
......@@ -26,7 +26,6 @@
* - MLD for link-local addresses.
*/
#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
......
......@@ -42,7 +42,6 @@
#define ND_PRINTK2 ND_PRINTK
#endif
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/config.h>
#include <linux/errno.h>
......
......@@ -326,45 +326,6 @@ ipq_enqueue_packet(struct sk_buff *skb, struct nf_info *info, void *data)
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
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;
if (ipv6_addr_cmp(&iph->daddr, &e->rt_info.daddr) ||
ipv6_addr_cmp(&iph->saddr, &e->rt_info.saddr))
return route6_me_harder(e->skb);
return ip6_route_me_harder(e->skb);
}
return 0;
}
......
......@@ -574,15 +574,17 @@ static int ip6_dst_gc()
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 o = (plen + 7)>>3;
int o = plen>>3;
memcpy(pfx->s6_addr, addr, o);
if (o < 16)
memset(pfx->s6_addr + o, 0, 16 - o);
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)
......@@ -655,16 +657,16 @@ int ip6_route_add(struct in6_rtmsg *rtmsg)
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;
if (rt->rt6i_dst.plen == 128)
rt->u.dst.flags = DST_HOST;
ipv6_wash_prefix(&rt->rt6i_dst.addr, rt->rt6i_dst.plen);
#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;
ipv6_wash_prefix(&rt->rt6i_src.addr, rt->rt6i_src.plen);
#endif
rt->rt6i_metric = rtmsg->rtmsg_metric;
......
......@@ -18,7 +18,6 @@
* Nate Thompson <nate@thebog.net>: 6to4 support
*/
#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
#include <linux/errno.h>
......
......@@ -24,7 +24,6 @@
* 2 of the License, or (at your option) any later version.
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/config.h>
#include <linux/errno.h>
......
......@@ -25,7 +25,6 @@
#include <linux/miscdevice.h>
#include <linux/proc_fs.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/init.h>
......
......@@ -585,6 +585,16 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
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,
struct msghdr *msg, int len,
struct scm_cookie *scm)
......@@ -706,12 +716,7 @@ static int netlink_recvmsg(struct kiocb *iocb, struct socket *sock,
netlink_dump(sk);
out:
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);
}
netlink_rcv_wake(sk);
return err ? : copied;
}
......@@ -721,13 +726,7 @@ void netlink_data_ready(struct sock *sk, int len)
if (nlk->data_ready)
nlk->data_ready(sk, len);
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);
}
netlink_rcv_wake(sk);
}
/*
......
......@@ -7,7 +7,6 @@
* Copyright Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
......
......@@ -7,7 +7,6 @@
* Copyright (C) Jonathan Naylor G4KLX (g4klx@g4klx.demon.co.uk)
*/
#include <linux/config.h>
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/kernel.h>
......
......@@ -45,7 +45,6 @@
* be incorporated into the next SCTP release.
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
......
......@@ -38,7 +38,6 @@
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
......
#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
......
......@@ -12,7 +12,6 @@
* Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
*/
#define __NO_VERSION__
#include <linux/module.h>
#include <linux/init.h>
......
......@@ -6,7 +6,6 @@
* Copyright (C) 1997 Olaf Kirch <okir@monad.swb.de>
*/
#define __NO_VERSION__
#include <linux/config.h>
#include <linux/module.h>
......
......@@ -14,7 +14,6 @@
#include <linux/ctype.h>
#include <linux/fs.h>
#include <linux/sysctl.h>
#define __NO_VERSION__
#include <linux/module.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