Commit 39c09b95 authored by David S. Miller's avatar David S. Miller

Merge davem@nuts.davemloft.net:/disk1/BK/net-2.6

into kernel.bkbits.net:/home/davem/net-2.6
parents d925eab6 7a984805
...@@ -407,7 +407,7 @@ o <http://www.iptables.org/downloads.html> ...@@ -407,7 +407,7 @@ o <http://www.iptables.org/downloads.html>
Ip-route2 Ip-route2
--------- ---------
o <ftp://ftp.inr.ac.ru/ip-routing/iproute2-2.2.4-now-ss991023.tar.gz> o <ftp://ftp.tux.org/pub/net/ip-routing/iproute2-2.2.4-now-ss991023.tar.gz>
OProfile OProfile
-------- --------
......
...@@ -47,7 +47,7 @@ This allows the kernel to exchange data with userspace applications. There ...@@ -47,7 +47,7 @@ This allows the kernel to exchange data with userspace applications. There
are two ways of doing this, the new way works with netlink sockets and I are two ways of doing this, the new way works with netlink sockets and I
have no experience with that yet. ANK uses it in his excellent iproute2 have no experience with that yet. ANK uses it in his excellent iproute2
package, see for example rtmon.c. iproute2 can be found on package, see for example rtmon.c. iproute2 can be found on
ftp://ftp.inr.ac.ru/ip-routing/iproute2* ftp://ftp.tux.org/pub/net/ip-routing/iproute2*
The new way is described, partly in netlink(7), available on The new way is described, partly in netlink(7), available on
http://www.europe.redhat.com/documentation/man-pages/man7/netlink.7.php3 http://www.europe.redhat.com/documentation/man-pages/man7/netlink.7.php3
......
...@@ -430,28 +430,3 @@ static int __init net_olddevs_init(void) ...@@ -430,28 +430,3 @@ static int __init net_olddevs_init(void)
} }
device_initcall(net_olddevs_init); device_initcall(net_olddevs_init);
/*
* The @dev_base list is protected by @dev_base_lock and the rtln
* semaphore.
*
* Pure readers hold dev_base_lock for reading.
*
* Writers must hold the rtnl semaphore while they loop through the
* dev_base list, and hold dev_base_lock for writing when they do the
* actual updates. This allows pure readers to access the list even
* while a writer is preparing to update it.
*
* To put it another way, dev_base_lock is held for writing only to
* protect against pure readers; the rtnl semaphore provides the
* protection against other writers.
*
* See, for example usages, register_netdevice() and
* unregister_netdevice(), which must be called with the rtnl
* semaphore held.
*/
struct net_device *dev_base;
rwlock_t dev_base_lock = RW_LOCK_UNLOCKED;
EXPORT_SYMBOL(dev_base);
EXPORT_SYMBOL(dev_base_lock);
...@@ -517,7 +517,7 @@ static int pppoe_create(struct socket *sock) ...@@ -517,7 +517,7 @@ static int pppoe_create(struct socket *sock)
sk->sk_protocol = PX_PROTO_OE; sk->sk_protocol = PX_PROTO_OE;
sk->sk_destruct = pppoe_sk_free; sk->sk_destruct = pppoe_sk_free;
po = pppox_sk(sk) = kmalloc(sizeof(*po), GFP_KERNEL); po = sk->sk_protinfo = kmalloc(sizeof(*po), GFP_KERNEL);
if (!po) if (!po)
goto frees; goto frees;
memset(po, 0, sizeof(*po)); memset(po, 0, sizeof(*po));
......
...@@ -200,6 +200,152 @@ static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb, ...@@ -200,6 +200,152 @@ static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb,
{ {
return __vlan_hwaccel_rx(skb, grp, vlan_tag, 1); return __vlan_hwaccel_rx(skb, grp, vlan_tag, 1);
} }
/**
* __vlan_put_tag - regular VLAN tag inserting
* @skb: skbuff to tag
* @tag: VLAN tag to insert
*
* Inserts the VLAN tag into @skb as part of the payload
* Returns a VLAN tagged skb. If a new skb is created, @skb is freed.
*
* Following the skb_unshare() example, in case of error, the calling function
* doesn't have to worry about freeing the original skb.
*/
static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, unsigned short tag)
{
struct vlan_ethhdr *veth;
if (skb_headroom(skb) < VLAN_HLEN) {
struct sk_buff *sk_tmp = skb;
skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN);
kfree_skb(sk_tmp);
if (!skb) {
printk(KERN_ERR "vlan: failed to realloc headroom\n");
return NULL;
}
} else {
skb = skb_unshare(skb, GFP_ATOMIC);
if (!skb) {
printk(KERN_ERR "vlan: failed to unshare skbuff\n");
return NULL;
}
}
veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
/* Move the mac addresses to the beginning of the new header. */
memmove(skb->data, skb->data + VLAN_HLEN, 2 * VLAN_ETH_ALEN);
/* first, the ethernet type */
veth->h_vlan_proto = __constant_htons(ETH_P_8021Q);
/* now, the tag */
veth->h_vlan_TCI = htons(tag);
skb->protocol = __constant_htons(ETH_P_8021Q);
skb->mac.raw -= VLAN_HLEN;
skb->nh.raw -= VLAN_HLEN;
return skb;
}
/**
* __vlan_hwaccel_put_tag - hardware accelerated VLAN inserting
* @skb: skbuff to tag
* @tag: VLAN tag to insert
*
* Puts the VLAN tag in @skb->cb[] and lets the device do the rest
*/
static inline struct sk_buff *__vlan_hwaccel_put_tag(struct sk_buff *skb, unsigned short tag)
{
struct vlan_skb_tx_cookie *cookie;
cookie = VLAN_TX_SKB_CB(skb);
cookie->magic = VLAN_TX_COOKIE_MAGIC;
cookie->vlan_tag = tag;
return skb;
}
#define HAVE_VLAN_PUT_TAG
/**
* vlan_put_tag - inserts VLAN tag according to device features
* @skb: skbuff to tag
* @tag: VLAN tag to insert
*
* Assumes skb->dev is the target that will xmit this frame.
* Returns a VLAN tagged skb.
*/
static inline struct sk_buff *vlan_put_tag(struct sk_buff *skb, unsigned short tag)
{
if (skb->dev->features & NETIF_F_HW_VLAN_TX) {
return __vlan_hwaccel_put_tag(skb, tag);
} else {
return __vlan_put_tag(skb, tag);
}
}
/**
* __vlan_get_tag - get the VLAN ID that is part of the payload
* @skb: skbuff to query
* @tag: buffer to store vlaue
*
* Returns error if the skb is not of VLAN type
*/
static inline int __vlan_get_tag(struct sk_buff *skb, unsigned short *tag)
{
struct vlan_ethhdr *veth = (struct vlan_ethhdr *)skb->data;
if (veth->h_vlan_proto != __constant_htons(ETH_P_8021Q)) {
return -EINVAL;
}
*tag = ntohs(veth->h_vlan_TCI);
return 0;
}
/**
* __vlan_hwaccel_get_tag - get the VLAN ID that is in @skb->cb[]
* @skb: skbuff to query
* @tag: buffer to store vlaue
*
* Returns error if @skb->cb[] is not set correctly
*/
static inline int __vlan_hwaccel_get_tag(struct sk_buff *skb, unsigned short *tag)
{
struct vlan_skb_tx_cookie *cookie;
cookie = VLAN_TX_SKB_CB(skb);
if (cookie->magic == VLAN_TX_COOKIE_MAGIC) {
*tag = cookie->vlan_tag;
return 0;
} else {
*tag = 0;
return -EINVAL;
}
}
#define HAVE_VLAN_GET_TAG
/**
* vlan_get_tag - get the VLAN ID from the skb
* @skb: skbuff to query
* @tag: buffer to store vlaue
*
* Returns error if the skb is not VLAN tagged
*/
static inline int vlan_get_tag(struct sk_buff *skb, unsigned short *tag)
{
if (skb->dev->features & NETIF_F_HW_VLAN_TX) {
return __vlan_hwaccel_get_tag(skb, tag);
} else {
return __vlan_get_tag(skb, tag);
}
}
#endif /* __KERNEL__ */ #endif /* __KERNEL__ */
/* VLAN IOCTLs are found in sockios.h */ /* VLAN IOCTLs are found in sockios.h */
......
...@@ -90,6 +90,7 @@ asmlinkage int printk(const char * fmt, ...) ...@@ -90,6 +90,7 @@ asmlinkage int printk(const char * fmt, ...)
unsigned long int_sqrt(unsigned long); unsigned long int_sqrt(unsigned long);
extern int printk_ratelimit(void); extern int printk_ratelimit(void);
extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst);
static inline void console_silent(void) static inline void console_silent(void)
{ {
......
...@@ -375,6 +375,10 @@ struct net_device ...@@ -375,6 +375,10 @@ struct net_device
atomic_t refcnt; atomic_t refcnt;
/* delayed register/unregister */ /* delayed register/unregister */
struct list_head todo_list; struct list_head todo_list;
/* device name hash chain */
struct hlist_node name_hlist;
/* device index hash chain */
struct hlist_node index_hlist;
/* register/unregister state machine */ /* register/unregister state machine */
enum { NETREG_UNINITIALIZED=0, enum { NETREG_UNINITIALIZED=0,
......
...@@ -52,6 +52,9 @@ extern int strnicmp(const char *, const char *, __kernel_size_t); ...@@ -52,6 +52,9 @@ extern int strnicmp(const char *, const char *, __kernel_size_t);
#ifndef __HAVE_ARCH_STRCHR #ifndef __HAVE_ARCH_STRCHR
extern char * strchr(const char *,int); extern char * strchr(const char *,int);
#endif #endif
#ifndef __HAVE_ARCH_STRNCHR
extern char * strnchr(const char *, size_t, int);
#endif
#ifndef __HAVE_ARCH_STRRCHR #ifndef __HAVE_ARCH_STRRCHR
extern char * strrchr(const char *,int); extern char * strrchr(const char *,int);
#endif #endif
......
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <net/neighbour.h> #include <net/neighbour.h>
#define HAVE_ARP_CREATE
extern struct neigh_table arp_tbl; extern struct neigh_table arp_tbl;
extern void arp_init(void); extern void arp_init(void);
...@@ -19,6 +21,12 @@ extern int arp_bind_neighbour(struct dst_entry *dst); ...@@ -19,6 +21,12 @@ extern int arp_bind_neighbour(struct dst_entry *dst);
extern int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir); extern int arp_mc_map(u32 addr, u8 *haddr, struct net_device *dev, int dir);
extern void arp_ifdown(struct net_device *dev); extern void arp_ifdown(struct net_device *dev);
extern struct sk_buff *arp_create(int type, int ptype, u32 dest_ip,
struct net_device *dev, u32 src_ip,
unsigned char *dest_hw, unsigned char *src_hw,
unsigned char *target_hw);
extern void arp_xmit(struct sk_buff *skb);
extern struct neigh_ops arp_broken_ops; extern struct neigh_ops arp_broken_ops;
#endif /* _ARP_H */ #endif /* _ARP_H */
...@@ -784,12 +784,6 @@ void tty_write_message(struct tty_struct *tty, char *msg) ...@@ -784,12 +784,6 @@ void tty_write_message(struct tty_struct *tty, char *msg)
return; return;
} }
/* minimum time in jiffies between messages */
int printk_ratelimit_jiffies = 5*HZ;
/* number of messages we send before ratelimiting */
int printk_ratelimit_burst = 10;
/* /*
* printk rate limiting, lifted from the networking subsystem. * printk rate limiting, lifted from the networking subsystem.
* *
...@@ -797,7 +791,7 @@ int printk_ratelimit_burst = 10; ...@@ -797,7 +791,7 @@ int printk_ratelimit_burst = 10;
* every printk_ratelimit_jiffies to make a denial-of-service * every printk_ratelimit_jiffies to make a denial-of-service
* attack impossible. * attack impossible.
*/ */
int printk_ratelimit(void) int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
{ {
static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED; static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED;
static unsigned long toks = 10*5*HZ; static unsigned long toks = 10*5*HZ;
...@@ -809,12 +803,12 @@ int printk_ratelimit(void) ...@@ -809,12 +803,12 @@ int printk_ratelimit(void)
spin_lock_irqsave(&ratelimit_lock, flags); spin_lock_irqsave(&ratelimit_lock, flags);
toks += now - last_msg; toks += now - last_msg;
last_msg = now; last_msg = now;
if (toks > (printk_ratelimit_burst * printk_ratelimit_jiffies)) if (toks > (ratelimit_burst * ratelimit_jiffies))
toks = printk_ratelimit_burst * printk_ratelimit_jiffies; toks = ratelimit_burst * ratelimit_jiffies;
if (toks >= printk_ratelimit_jiffies) { if (toks >= ratelimit_jiffies) {
int lost = missed; int lost = missed;
missed = 0; missed = 0;
toks -= printk_ratelimit_jiffies; toks -= ratelimit_jiffies;
spin_unlock_irqrestore(&ratelimit_lock, flags); spin_unlock_irqrestore(&ratelimit_lock, flags);
if (lost) if (lost)
printk(KERN_WARNING "printk: %d messages suppressed.\n", lost); printk(KERN_WARNING "printk: %d messages suppressed.\n", lost);
...@@ -824,4 +818,17 @@ int printk_ratelimit(void) ...@@ -824,4 +818,17 @@ int printk_ratelimit(void)
spin_unlock_irqrestore(&ratelimit_lock, flags); spin_unlock_irqrestore(&ratelimit_lock, flags);
return 0; return 0;
} }
EXPORT_SYMBOL(__printk_ratelimit);
/* minimum time in jiffies between messages */
int printk_ratelimit_jiffies = 5*HZ;
/* number of messages we send before ratelimiting */
int printk_ratelimit_burst = 10;
int printk_ratelimit(void)
{
return __printk_ratelimit(printk_ratelimit_jiffies,
printk_ratelimit_burst);
}
EXPORT_SYMBOL(printk_ratelimit); EXPORT_SYMBOL(printk_ratelimit);
...@@ -273,6 +273,22 @@ char * strrchr(const char * s, int c) ...@@ -273,6 +273,22 @@ char * strrchr(const char * s, int c)
} }
#endif #endif
#ifndef __HAVE_ARCH_STRNCHR
/**
* strnchr - Find a character in a length limited string
* @s: The string to be searched
* @count: The number of characters to be searched
* @c: The character to search for
*/
char *strnchr(const char *s, size_t count, int c)
{
for (; count-- && *s != '\0'; ++s)
if (*s == (char) c)
return (char *) s;
return NULL;
}
#endif
#ifndef __HAVE_ARCH_STRLEN #ifndef __HAVE_ARCH_STRLEN
/** /**
* strlen - Find the length of a string * strlen - Find the length of a string
......
...@@ -445,6 +445,7 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -445,6 +445,7 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/ */
if (veth->h_vlan_proto != __constant_htons(ETH_P_8021Q)) { if (veth->h_vlan_proto != __constant_htons(ETH_P_8021Q)) {
int orig_headroom = skb_headroom(skb);
unsigned short veth_TCI; unsigned short veth_TCI;
/* This is not a VLAN frame...but we can fix that! */ /* This is not a VLAN frame...but we can fix that! */
...@@ -454,33 +455,7 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -454,33 +455,7 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(VLAN_DBG "%s: proto to encap: 0x%hx (hbo)\n", printk(VLAN_DBG "%s: proto to encap: 0x%hx (hbo)\n",
__FUNCTION__, htons(veth->h_vlan_proto)); __FUNCTION__, htons(veth->h_vlan_proto));
#endif #endif
/* Construct the second two bytes. This field looks something
if (skb_headroom(skb) < VLAN_HLEN) {
struct sk_buff *sk_tmp = skb;
skb = skb_realloc_headroom(sk_tmp, VLAN_HLEN);
kfree_skb(sk_tmp);
if (skb == NULL) {
stats->tx_dropped++;
return 0;
}
VLAN_DEV_INFO(dev)->cnt_inc_headroom_on_tx++;
} else {
if (!(skb = skb_unshare(skb, GFP_ATOMIC))) {
printk(KERN_ERR "vlan: failed to unshare skbuff\n");
stats->tx_dropped++;
return 0;
}
}
veth = (struct vlan_ethhdr *)skb_push(skb, VLAN_HLEN);
/* Move the mac addresses to the beginning of the new header. */
memmove(skb->data, skb->data + VLAN_HLEN, 12);
/* first, the ethernet type */
/* put_unaligned(__constant_htons(ETH_P_8021Q), &veth->h_vlan_proto); */
veth->h_vlan_proto = __constant_htons(ETH_P_8021Q);
/* Now, construct the second two bytes. This field looks something
* like: * like:
* usr_priority: 3 bits (high bits) * usr_priority: 3 bits (high bits)
* CFI 1 bit * CFI 1 bit
...@@ -489,10 +464,16 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -489,10 +464,16 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
veth_TCI = VLAN_DEV_INFO(dev)->vlan_id; veth_TCI = VLAN_DEV_INFO(dev)->vlan_id;
veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb); veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb);
veth->h_vlan_TCI = htons(veth_TCI); skb = __vlan_put_tag(skb, veth_TCI);
} if (!skb) {
stats->tx_dropped++;
return 0;
}
skb->dev = VLAN_DEV_INFO(dev)->real_dev; if (orig_headroom < VLAN_HLEN) {
VLAN_DEV_INFO(dev)->cnt_inc_headroom_on_tx++;
}
}
#ifdef VLAN_DEBUG #ifdef VLAN_DEBUG
printk(VLAN_DBG "%s: about to send skb: %p to dev: %s\n", printk(VLAN_DBG "%s: about to send skb: %p to dev: %s\n",
...@@ -506,10 +487,7 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -506,10 +487,7 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
stats->tx_packets++; /* for statics only */ stats->tx_packets++; /* for statics only */
stats->tx_bytes += skb->len; stats->tx_bytes += skb->len;
skb->protocol = __constant_htons(ETH_P_8021Q); skb->dev = VLAN_DEV_INFO(dev)->real_dev;
skb->mac.raw -= VLAN_HLEN;
skb->nh.raw -= VLAN_HLEN;
dev_queue_xmit(skb); dev_queue_xmit(skb);
return 0; return 0;
...@@ -518,17 +496,22 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) ...@@ -518,17 +496,22 @@ int vlan_dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev) int vlan_dev_hwaccel_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
struct net_device_stats *stats = vlan_dev_get_stats(dev); struct net_device_stats *stats = vlan_dev_get_stats(dev);
struct vlan_skb_tx_cookie *cookie; unsigned short veth_TCI;
/* Construct the second two bytes. This field looks something
* like:
* usr_priority: 3 bits (high bits)
* CFI 1 bit
* VLAN ID 12 bits (low bits)
*/
veth_TCI = VLAN_DEV_INFO(dev)->vlan_id;
veth_TCI |= vlan_dev_get_egress_qos_mask(dev, skb);
skb = __vlan_hwaccel_put_tag(skb, veth_TCI);
stats->tx_packets++; stats->tx_packets++;
stats->tx_bytes += skb->len; stats->tx_bytes += skb->len;
skb->dev = VLAN_DEV_INFO(dev)->real_dev; skb->dev = VLAN_DEV_INFO(dev)->real_dev;
cookie = VLAN_TX_SKB_CB(skb);
cookie->magic = VLAN_TX_COOKIE_MAGIC;
cookie->vlan_tag = (VLAN_DEV_INFO(dev)->vlan_id |
vlan_dev_get_egress_qos_mask(dev, skb));
dev_queue_xmit(skb); dev_queue_xmit(skb);
return 0; return 0;
......
...@@ -145,7 +145,7 @@ config DECNET ...@@ -145,7 +145,7 @@ config DECNET
To find some tools to use with the kernel layer support, please To find some tools to use with the kernel layer support, please
look at Patrick Caulfield's web site: look at Patrick Caulfield's web site:
<http://linux.dreamtime.org/decnet/>. <http://linux-decnet.sourceforge.net/>.
More detailed documentation is available in More detailed documentation is available in
<file:Documentation/networking/decnet.txt>. <file:Documentation/networking/decnet.txt>.
...@@ -436,7 +436,7 @@ config X25 ...@@ -436,7 +436,7 @@ config X25
(say Y to "LAPB Data Link Driver" below if you want that). (say Y to "LAPB Data Link Driver" below if you want that).
You can read more about X.25 at <http://www.sangoma.com/x25.htm> and You can read more about X.25 at <http://www.sangoma.com/x25.htm> and
<http://www.cisco.com/univercd/data/doc/software/11_0/rpcg/cx25.htm>. <http://www.cisco.com/univercd/cc/td/doc/product/software/ios11/cbook/cx25.htm>.
Information about X.25 for Linux is contained in the files Information about X.25 for Linux is contained in the files
<file:Documentation/networking/x25.txt> and <file:Documentation/networking/x25.txt> and
<file:Documentation/networking/x25-iface.txt>. <file:Documentation/networking/x25-iface.txt>.
...@@ -571,7 +571,7 @@ config NET_FASTROUTE ...@@ -571,7 +571,7 @@ config NET_FASTROUTE
At the moment, few devices support fast switching (tulip is one of At the moment, few devices support fast switching (tulip is one of
them, a modified 8390 driver can be found at them, a modified 8390 driver can be found at
<ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz>). <ftp://ftp.tux.org/pub/net/ip-routing/fastroute/fastroute-8390.tar.gz>).
If unsure, say N. If unsure, say N.
...@@ -583,7 +583,7 @@ config NET_HW_FLOWCONTROL ...@@ -583,7 +583,7 @@ config NET_HW_FLOWCONTROL
during periods of extreme congestion. At the moment only a couple during periods of extreme congestion. At the moment only a couple
of device drivers support it (really only one -- tulip, a modified of device drivers support it (really only one -- tulip, a modified
8390 driver can be found at 8390 driver can be found at
<ftp://ftp.inr.ac.ru/ip-routing/fastroute/fastroute-8390.tar.gz>). <ftp://ftp.tux.org/pub/net/ip-routing/fastroute/fastroute-8390.tar.gz>).
Really, this option is applicable to any machine attached to a fast Really, this option is applicable to any machine attached to a fast
enough network, and even a 10 Mb NIC is able to kill a not very slow enough network, and even a 10 Mb NIC is able to kill a not very slow
...@@ -614,7 +614,7 @@ config NET_SCHED ...@@ -614,7 +614,7 @@ config NET_SCHED
This code is considered to be experimental. This code is considered to be experimental.
To administer these schedulers, you'll need the user-level utilities To administer these schedulers, you'll need the user-level utilities
from the package iproute2+tc at <ftp://ftp.inr.ac.ru/ip-routing/>. from the package iproute2+tc at <ftp://ftp.tux.org/pub/net/ip-routing/>.
That package also contains some documentation; for more, check out That package also contains some documentation; for more, check out
<http://snafu.freedom.org/linux2.2/iproute-notes.html>. <http://snafu.freedom.org/linux2.2/iproute-notes.html>.
......
...@@ -160,6 +160,47 @@ static void sample_queue(unsigned long dummy); ...@@ -160,6 +160,47 @@ static void sample_queue(unsigned long dummy);
static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0); static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0);
#endif #endif
/*
* The @dev_base list is protected by @dev_base_lock and the rtln
* semaphore.
*
* Pure readers hold dev_base_lock for reading.
*
* Writers must hold the rtnl semaphore while they loop through the
* dev_base list, and hold dev_base_lock for writing when they do the
* actual updates. This allows pure readers to access the list even
* while a writer is preparing to update it.
*
* To put it another way, dev_base_lock is held for writing only to
* protect against pure readers; the rtnl semaphore provides the
* protection against other writers.
*
* See, for example usages, register_netdevice() and
* unregister_netdevice(), which must be called with the rtnl
* semaphore held.
*/
struct net_device *dev_base;
struct net_device **dev_tail = &dev_base;
rwlock_t dev_base_lock = RW_LOCK_UNLOCKED;
EXPORT_SYMBOL(dev_base);
EXPORT_SYMBOL(dev_base_lock);
#define NETDEV_HASHBITS 8
static struct hlist_head dev_name_head[1<<NETDEV_HASHBITS];
static struct hlist_head dev_index_head[1<<NETDEV_HASHBITS];
static inline struct hlist_head *dev_name_hash(const char *name)
{
unsigned hash = full_name_hash(name, strnlen(name, IFNAMSIZ));
return &dev_name_head[hash & ((1<<NETDEV_HASHBITS)-1)];
}
static inline struct hlist_head *dev_index_hash(int ifindex)
{
return &dev_index_head[ifindex & ((1<<NETDEV_HASHBITS)-1)];
}
/* /*
* Our notifier list * Our notifier list
*/ */
...@@ -443,12 +484,15 @@ __setup("netdev=", netdev_boot_setup); ...@@ -443,12 +484,15 @@ __setup("netdev=", netdev_boot_setup);
struct net_device *__dev_get_by_name(const char *name) struct net_device *__dev_get_by_name(const char *name)
{ {
struct net_device *dev; struct hlist_node *p;
for (dev = dev_base; dev; dev = dev->next) hlist_for_each(p, dev_name_hash(name)) {
struct net_device *dev
= hlist_entry(p, struct net_device, name_hlist);
if (!strncmp(dev->name, name, IFNAMSIZ)) if (!strncmp(dev->name, name, IFNAMSIZ))
break; return dev;
return dev; }
return NULL;
} }
/** /**
...@@ -516,12 +560,15 @@ int __dev_get(const char *name) ...@@ -516,12 +560,15 @@ int __dev_get(const char *name)
struct net_device *__dev_get_by_index(int ifindex) struct net_device *__dev_get_by_index(int ifindex)
{ {
struct net_device *dev; struct hlist_node *p;
for (dev = dev_base; dev; dev = dev->next) hlist_for_each(p, dev_index_hash(ifindex)) {
struct net_device *dev
= hlist_entry(p, struct net_device, index_hlist);
if (dev->ifindex == ifindex) if (dev->ifindex == ifindex)
break; return dev;
return dev; }
return NULL;
} }
...@@ -673,30 +720,55 @@ int dev_valid_name(const char *name) ...@@ -673,30 +720,55 @@ int dev_valid_name(const char *name)
int dev_alloc_name(struct net_device *dev, const char *name) int dev_alloc_name(struct net_device *dev, const char *name)
{ {
int i; int i = 0;
char buf[32]; char buf[IFNAMSIZ];
char *p; const char *p;
const int max_netdevices = 8*PAGE_SIZE;
long *inuse;
struct net_device *d;
/* p = strnchr(name, IFNAMSIZ-1, '%');
* Verify the string as this thing may have come from if (p) {
* the user. There must be either one "%d" and no other "%" /*
* characters, or no "%" characters at all. * Verify the string as this thing may have come from
*/ * the user. There must be either one "%d" and no other "%"
p = strchr(name, '%'); * characters.
if (p && (p[1] != 'd' || strchr(p + 2, '%'))) */
return -EINVAL; if (p[1] != 'd' || strchr(p + 2, '%'))
return -EINVAL;
/* /* Use one page as a bit array of possible slots */
* If you need over 100 please also fix the algorithm... inuse = (long *) get_zeroed_page(GFP_ATOMIC);
*/ if (!inuse)
for (i = 0; i < 100; i++) { return -ENOMEM;
snprintf(buf, sizeof(buf), name, i);
if (!__dev_get_by_name(buf)) { for (d = dev_base; d; d = d->next) {
strcpy(dev->name, buf); if (!sscanf(d->name, name, &i))
return i; continue;
if (i < 0 || i >= max_netdevices)
continue;
/* avoid cases where sscanf is not exact inverse of printf */
snprintf(buf, sizeof(buf), name, i);
if (!strncmp(buf, d->name, IFNAMSIZ))
set_bit(i, inuse);
} }
i = find_first_zero_bit(inuse, max_netdevices);
free_page((unsigned long) inuse);
} }
return -ENFILE; /* Over 100 of the things .. bail out! */
snprintf(buf, sizeof(buf), name, i);
if (!__dev_get_by_name(buf)) {
strlcpy(dev->name, buf, IFNAMSIZ);
return i;
}
/* It is possible to run out of possible slots
* when the name is long and there isn't enough space left
* for the digits, or if all bits are used.
*/
return -ENFILE;
} }
...@@ -729,6 +801,9 @@ int dev_change_name(struct net_device *dev, char *newname) ...@@ -729,6 +801,9 @@ int dev_change_name(struct net_device *dev, char *newname)
else else
strlcpy(dev->name, newname, IFNAMSIZ); strlcpy(dev->name, newname, IFNAMSIZ);
hlist_del(&dev->name_hlist);
hlist_add_head(&dev->name_hlist, dev_name_hash(dev->name));
class_device_rename(&dev->class_dev, dev->name); class_device_rename(&dev->class_dev, dev->name);
notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev); notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
return 0; return 0;
...@@ -2717,7 +2792,8 @@ static inline void net_set_todo(struct net_device *dev) ...@@ -2717,7 +2792,8 @@ static inline void net_set_todo(struct net_device *dev)
int register_netdevice(struct net_device *dev) int register_netdevice(struct net_device *dev)
{ {
struct net_device *d, **dp; struct hlist_head *head;
struct hlist_node *p;
int ret; int ret;
BUG_ON(dev_boot_phase); BUG_ON(dev_boot_phase);
...@@ -2758,13 +2834,17 @@ int register_netdevice(struct net_device *dev) ...@@ -2758,13 +2834,17 @@ int register_netdevice(struct net_device *dev)
if (dev->iflink == -1) if (dev->iflink == -1)
dev->iflink = dev->ifindex; dev->iflink = dev->ifindex;
/* Check for existence, and append to tail of chain */ /* Check for existence of name */
ret = -EEXIST; head = dev_name_hash(dev->name);
for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) { hlist_for_each(p, head) {
if (d == dev || !strcmp(d->name, dev->name)) struct net_device *d
goto out_err; = hlist_entry(p, struct net_device, name_hlist);
} if (!strncmp(d->name, dev->name, IFNAMSIZ)) {
ret = -EEXIST;
goto out_err;
}
}
/* Fix illegal SG+CSUM combinations. */ /* Fix illegal SG+CSUM combinations. */
if ((dev->features & NETIF_F_SG) && if ((dev->features & NETIF_F_SG) &&
!(dev->features & (NETIF_F_IP_CSUM | !(dev->features & (NETIF_F_IP_CSUM |
...@@ -2793,7 +2873,10 @@ int register_netdevice(struct net_device *dev) ...@@ -2793,7 +2873,10 @@ int register_netdevice(struct net_device *dev)
dev->next = NULL; dev->next = NULL;
dev_init_scheduler(dev); dev_init_scheduler(dev);
write_lock_bh(&dev_base_lock); write_lock_bh(&dev_base_lock);
*dp = dev; *dev_tail = dev;
dev_tail = &dev->next;
hlist_add_head(&dev->name_hlist, head);
hlist_add_head(&dev->index_hlist, dev_index_hash(dev->ifindex));
dev_hold(dev); dev_hold(dev);
dev->reg_state = NETREG_REGISTERING; dev->reg_state = NETREG_REGISTERING;
write_unlock_bh(&dev_base_lock); write_unlock_bh(&dev_base_lock);
...@@ -3015,6 +3098,10 @@ int unregister_netdevice(struct net_device *dev) ...@@ -3015,6 +3098,10 @@ int unregister_netdevice(struct net_device *dev)
for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) { for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) {
if (d == dev) { if (d == dev) {
write_lock_bh(&dev_base_lock); write_lock_bh(&dev_base_lock);
hlist_del(&dev->name_hlist);
hlist_del(&dev->index_hlist);
if (dev_tail == &dev->next)
dev_tail = dp;
*dp = d->next; *dp = d->next;
write_unlock_bh(&dev_base_lock); write_unlock_bh(&dev_base_lock);
break; break;
...@@ -3091,6 +3178,12 @@ static int __init net_dev_init(void) ...@@ -3091,6 +3178,12 @@ static int __init net_dev_init(void)
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
INIT_LIST_HEAD(&ptype_base[i]); INIT_LIST_HEAD(&ptype_base[i]);
for (i = 0; i < ARRAY_SIZE(dev_name_head); i++)
INIT_HLIST_HEAD(&dev_name_head[i]);
for (i = 0; i < ARRAY_SIZE(dev_index_head); i++)
INIT_HLIST_HEAD(&dev_index_head[i]);
/* /*
* Initialise the packet receive queues. * Initialise the packet receive queues.
*/ */
......
...@@ -41,37 +41,11 @@ int net_msg_cost = 5*HZ; ...@@ -41,37 +41,11 @@ int net_msg_cost = 5*HZ;
int net_msg_burst = 10; int net_msg_burst = 10;
/* /*
* This enforces a rate limit: not more than one kernel message * All net warning printk()s should be guarded by this function.
* every 5secs to make a denial-of-service attack impossible.
*
* All warning printk()s should be guarded by this function.
*/ */
int net_ratelimit(void) int net_ratelimit(void)
{ {
static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED; return __printk_ratelimit(net_msg_cost, net_msg_burst);
static unsigned long toks = 10*5*HZ;
static unsigned long last_msg;
static int missed;
unsigned long flags;
unsigned long now = jiffies;
spin_lock_irqsave(&ratelimit_lock, flags);
toks += now - last_msg;
last_msg = now;
if (toks > net_msg_burst)
toks = net_msg_burst;
if (toks >= net_msg_cost) {
int lost = missed;
missed = 0;
toks -= net_msg_cost;
spin_unlock_irqrestore(&ratelimit_lock, flags);
if (lost)
printk(KERN_WARNING "NET: %d messages suppressed.\n", lost);
return 1;
}
missed++;
spin_unlock_irqrestore(&ratelimit_lock, flags);
return 0;
} }
EXPORT_SYMBOL(net_random); EXPORT_SYMBOL(net_random);
......
...@@ -22,8 +22,9 @@ config DECNET_ROUTER ...@@ -22,8 +22,9 @@ config DECNET_ROUTER
network link driver", "Routing messages" and "Network packet network link driver", "Routing messages" and "Network packet
filtering". The first two are required to allow configuration via filtering". The first two are required to allow configuration via
rtnetlink (you will need Alexey Kuznetsov's iproute2 package rtnetlink (you will need Alexey Kuznetsov's iproute2 package
from <ftp://ftp.inr.ac.ru/>). The "Network packet filtering" option from <ftp://ftp.tux.org/pub/net/ip-routing/>). The "Network packet
will be required for the forthcoming routing daemon to work. filtering" option will be required for the forthcoming routing daemon
to work.
See <file:Documentation/networking/decnet.txt> for more information. See <file:Documentation/networking/decnet.txt> for more information.
......
...@@ -71,7 +71,7 @@ config IP_MULTIPLE_TABLES ...@@ -71,7 +71,7 @@ config IP_MULTIPLE_TABLES
documentation at <http://www.compendium.com.ar/policy-routing.txt> documentation at <http://www.compendium.com.ar/policy-routing.txt>
and <ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex>. and <ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex>.
You will need supporting software from You will need supporting software from
<ftp://ftp.inr.ac.ru/ip-routing/>. <ftp://ftp.tux.org/pub/net/ip-routing/>.
If unsure, say N. If unsure, say N.
......
...@@ -67,6 +67,10 @@ ...@@ -67,6 +67,10 @@
* now it is in net/core/neighbour.c. * now it is in net/core/neighbour.c.
* Krzysztof Halasa: Added Frame Relay ARP support. * Krzysztof Halasa: Added Frame Relay ARP support.
* Arnaldo C. Melo : convert /proc/net/arp to seq_file * Arnaldo C. Melo : convert /proc/net/arp to seq_file
* Shmulik Hen: Split arp_send to arp_create and
* arp_xmit so intermediate drivers like
* bonding can change the skb before
* sending (e.g. insert 8021q tag).
*/ */
#include <linux/module.h> #include <linux/module.h>
...@@ -487,26 +491,18 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt) ...@@ -487,26 +491,18 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt)
*/ */
/* /*
* Create and send an arp packet. If (dest_hw == NULL), we create a broadcast * Create an arp packet. If (dest_hw == NULL), we create a broadcast
* message. * message.
*/ */
struct sk_buff *arp_create(int type, int ptype, u32 dest_ip,
void arp_send(int type, int ptype, u32 dest_ip, struct net_device *dev, u32 src_ip,
struct net_device *dev, u32 src_ip, unsigned char *dest_hw, unsigned char *src_hw,
unsigned char *dest_hw, unsigned char *src_hw, unsigned char *target_hw)
unsigned char *target_hw)
{ {
struct sk_buff *skb; struct sk_buff *skb;
struct arphdr *arp; struct arphdr *arp;
unsigned char *arp_ptr; unsigned char *arp_ptr;
/*
* No arp on this interface.
*/
if (dev->flags&IFF_NOARP)
return;
/* /*
* Allocate a buffer * Allocate a buffer
*/ */
...@@ -514,7 +510,7 @@ void arp_send(int type, int ptype, u32 dest_ip, ...@@ -514,7 +510,7 @@ void arp_send(int type, int ptype, u32 dest_ip,
skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4) skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
+ LL_RESERVED_SPACE(dev), GFP_ATOMIC); + LL_RESERVED_SPACE(dev), GFP_ATOMIC);
if (skb == NULL) if (skb == NULL)
return; return NULL;
skb_reserve(skb, LL_RESERVED_SPACE(dev)); skb_reserve(skb, LL_RESERVED_SPACE(dev));
skb->nh.raw = skb->data; skb->nh.raw = skb->data;
...@@ -594,12 +590,46 @@ void arp_send(int type, int ptype, u32 dest_ip, ...@@ -594,12 +590,46 @@ void arp_send(int type, int ptype, u32 dest_ip,
arp_ptr+=dev->addr_len; arp_ptr+=dev->addr_len;
memcpy(arp_ptr, &dest_ip, 4); memcpy(arp_ptr, &dest_ip, 4);
/* Send it off, maybe filter it using firewalling first. */ return skb;
NF_HOOK(NF_ARP, NF_ARP_OUT, skb, NULL, dev, dev_queue_xmit);
return;
out: out:
kfree_skb(skb); kfree_skb(skb);
return NULL;
}
/*
* Send an arp packet.
*/
void arp_xmit(struct sk_buff *skb)
{
/* Send it off, maybe filter it using firewalling first. */
NF_HOOK(NF_ARP, NF_ARP_OUT, skb, NULL, skb->dev, dev_queue_xmit);
}
/*
* Create and send an arp packet.
*/
void arp_send(int type, int ptype, u32 dest_ip,
struct net_device *dev, u32 src_ip,
unsigned char *dest_hw, unsigned char *src_hw,
unsigned char *target_hw)
{
struct sk_buff *skb;
/*
* No arp on this interface.
*/
if (dev->flags&IFF_NOARP)
return;
skb = arp_create(type, ptype, dest_ip, dev, src_ip,
dest_hw, src_hw, target_hw);
if (skb == NULL) {
return;
}
arp_xmit(skb);
} }
static void parp_redo(struct sk_buff *skb) static void parp_redo(struct sk_buff *skb)
...@@ -1437,6 +1467,8 @@ static int __init arp_proc_init(void) ...@@ -1437,6 +1467,8 @@ static int __init arp_proc_init(void)
EXPORT_SYMBOL(arp_broken_ops); EXPORT_SYMBOL(arp_broken_ops);
EXPORT_SYMBOL(arp_find); EXPORT_SYMBOL(arp_find);
EXPORT_SYMBOL(arp_rcv); EXPORT_SYMBOL(arp_rcv);
EXPORT_SYMBOL(arp_create);
EXPORT_SYMBOL(arp_xmit);
EXPORT_SYMBOL(arp_send); EXPORT_SYMBOL(arp_send);
EXPORT_SYMBOL(arp_tbl); EXPORT_SYMBOL(arp_tbl);
......
...@@ -707,8 +707,10 @@ static void ndisc_recv_ns(struct sk_buff *skb) ...@@ -707,8 +707,10 @@ static void ndisc_recv_ns(struct sk_buff *skb)
struct ndisc_options ndopts; struct ndisc_options ndopts;
struct net_device *dev = skb->dev; struct net_device *dev = skb->dev;
struct inet6_ifaddr *ifp; struct inet6_ifaddr *ifp;
struct inet6_dev *idev = NULL;
struct neighbour *neigh; struct neighbour *neigh;
int addr_type = ipv6_addr_type(saddr); int dad = ipv6_addr_any(saddr);
int inc;
if (ipv6_addr_is_multicast(&msg->target)) { if (ipv6_addr_is_multicast(&msg->target)) {
if (net_ratelimit()) if (net_ratelimit())
...@@ -720,7 +722,7 @@ static void ndisc_recv_ns(struct sk_buff *skb) ...@@ -720,7 +722,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
* RFC2461 7.1.1: * RFC2461 7.1.1:
* DAD has to be destined for solicited node multicast address. * DAD has to be destined for solicited node multicast address.
*/ */
if (addr_type == IPV6_ADDR_ANY && if (dad &&
!(daddr->s6_addr32[0] == htonl(0xff020000) && !(daddr->s6_addr32[0] == htonl(0xff020000) &&
daddr->s6_addr32[1] == htonl(0x00000000) && daddr->s6_addr32[1] == htonl(0x00000000) &&
daddr->s6_addr32[2] == htonl(0x00000001) && daddr->s6_addr32[2] == htonl(0x00000001) &&
...@@ -750,13 +752,15 @@ static void ndisc_recv_ns(struct sk_buff *skb) ...@@ -750,13 +752,15 @@ static void ndisc_recv_ns(struct sk_buff *skb)
* there MUST NOT be source link-layer address option * there MUST NOT be source link-layer address option
* in the message. * in the message.
*/ */
if (addr_type == IPV6_ADDR_ANY) { if (dad) {
if (net_ratelimit()) if (net_ratelimit())
printk(KERN_WARNING "ICMP6 NS: bad DAD packet (link-layer address option)\n"); printk(KERN_WARNING "ICMP6 NS: bad DAD packet (link-layer address option)\n");
return; return;
} }
} }
inc = ipv6_addr_is_multicast(daddr);
if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) { if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) {
if (ifp->flags & IFA_F_TENTATIVE) { if (ifp->flags & IFA_F_TENTATIVE) {
/* Address is tentative. If the source /* Address is tentative. If the source
...@@ -764,146 +768,89 @@ static void ndisc_recv_ns(struct sk_buff *skb) ...@@ -764,146 +768,89 @@ static void ndisc_recv_ns(struct sk_buff *skb)
does DAD, otherwise we ignore solicitations does DAD, otherwise we ignore solicitations
until DAD timer expires. until DAD timer expires.
*/ */
if (addr_type == IPV6_ADDR_ANY) { if (!dad)
if (dev->type == ARPHRD_IEEE802_TR) { goto out;
unsigned char *sadr = skb->mac.raw ; if (dev->type == ARPHRD_IEEE802_TR) {
if (((sadr[8] &0x7f) != (dev->dev_addr[0] & 0x7f)) || unsigned char *sadr = skb->mac.raw;
(sadr[9] != dev->dev_addr[1]) || if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 &&
(sadr[10] != dev->dev_addr[2]) || sadr[9] == dev->dev_addr[1] &&
(sadr[11] != dev->dev_addr[3]) || sadr[10] == dev->dev_addr[2] &&
(sadr[12] != dev->dev_addr[4]) || sadr[11] == dev->dev_addr[3] &&
(sadr[13] != dev->dev_addr[5])) sadr[12] == dev->dev_addr[4] &&
{ sadr[13] == dev->dev_addr[5]) {
addrconf_dad_failure(ifp) ; /* looped-back to us */
} goto out;
} else {
addrconf_dad_failure(ifp);
} }
} else }
in6_ifa_put(ifp); addrconf_dad_failure(ifp);
return;
}
if (addr_type == IPV6_ADDR_ANY) {
struct in6_addr maddr;
ipv6_addr_all_nodes(&maddr);
ndisc_send_na(dev, NULL, &maddr, &ifp->addr,
ifp->idev->cnf.forwarding, 0,
1, 1);
in6_ifa_put(ifp);
return; return;
} }
if (addr_type & IPV6_ADDR_UNICAST) { idev = ifp->idev;
if (ipv6_addr_is_multicast(daddr)) } else {
nd_tbl.stats.rcv_probes_mcast++; idev = in6_dev_get(dev);
else
nd_tbl.stats.rcv_probes_ucast++;
/*
* update / create cache entry
* for the source address
*/
neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
if (neigh || !dev->hard_header) {
ndisc_send_na(dev, neigh, saddr, &ifp->addr,
ifp->idev->cnf.forwarding, 1,
1, 1);
if (neigh)
neigh_release(neigh);
}
}
in6_ifa_put(ifp);
} else if (ipv6_chk_acast_addr(dev, &msg->target)) {
struct inet6_dev *idev = in6_dev_get(dev);
/* anycast */
if (!idev) { if (!idev) {
/* XXX: count this drop? */ /* XXX: count this drop? */
return; return;
} }
if (addr_type == IPV6_ADDR_ANY) {
struct in6_addr maddr;
ipv6_addr_all_nodes(&maddr);
ndisc_send_na(dev, NULL, &maddr, &msg->target,
idev->cnf.forwarding, 0, 0, 1);
in6_dev_put(idev);
return;
}
if (addr_type & IPV6_ADDR_UNICAST) {
int inc = ipv6_addr_is_multicast(daddr);
if (inc)
nd_tbl.stats.rcv_probes_mcast++;
else
nd_tbl.stats.rcv_probes_ucast++;
/*
* update / create cache entry
* for the source address
*/
neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, skb->dev); if (ipv6_chk_acast_addr(dev, &msg->target) ||
(idev->cnf.forwarding &&
if (neigh || !dev->hard_header) { pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) {
ndisc_send_na(dev, neigh, saddr, if (skb->stamp.tv_sec != 0 &&
&msg->target, skb->pkt_type != PACKET_HOST &&
idev->cnf.forwarding, 1, 0, inc); inc != 0 &&
if (neigh) idev->nd_parms->proxy_delay != 0) {
neigh_release(neigh); /*
} * for anycast or proxy,
} * sender should delay its response
in6_dev_put(idev); * by a random time between 0 and
} else { * MAX_ANYCAST_DELAY_TIME seconds.
struct inet6_dev *in6_dev = in6_dev_get(dev); * (RFC2461) -- yoshfuji
*/
if (in6_dev && in6_dev->cnf.forwarding &&
(addr_type & IPV6_ADDR_UNICAST ||
addr_type == IPV6_ADDR_ANY) &&
pneigh_lookup(&nd_tbl, &msg->target, dev, 0)) {
int inc = ipv6_addr_is_multicast(daddr);
if (skb->stamp.tv_sec == 0 ||
skb->pkt_type == PACKET_HOST ||
inc == 0 ||
in6_dev->nd_parms->proxy_delay == 0) {
if (inc)
nd_tbl.stats.rcv_probes_mcast++;
else
nd_tbl.stats.rcv_probes_ucast++;
if (addr_type & IPV6_ADDR_UNICAST) {
neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
if (neigh) {
ndisc_send_na(dev, neigh, saddr, &msg->target,
0, 1, 0, 1);
neigh_release(neigh);
}
} else {
/* proxy should also protect against DAD */
struct in6_addr maddr;
ipv6_addr_all_nodes(&maddr);
ndisc_send_na(dev, NULL, &maddr, &msg->target,
0, 0, 0, 1);
}
} else {
struct sk_buff *n = skb_clone(skb, GFP_ATOMIC); struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
if (n) if (n)
pneigh_enqueue(&nd_tbl, in6_dev->nd_parms, n); pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
in6_dev_put(in6_dev); goto out;
return;
} }
} } else
if (in6_dev) goto out;
in6_dev_put(in6_dev);
} }
if (dad) {
struct in6_addr maddr;
ipv6_addr_all_nodes(&maddr);
ndisc_send_na(dev, NULL, &maddr, &msg->target,
idev->cnf.forwarding, 0, (ifp != NULL), 1);
goto out;
}
if (inc)
nd_tbl.stats.rcv_probes_mcast++;
else
nd_tbl.stats.rcv_probes_ucast++;
/*
* update / create cache entry
* for the source address
*/
neigh = neigh_event_ns(&nd_tbl, lladdr, saddr, dev);
if (neigh || !dev->hard_header) {
ndisc_send_na(dev, neigh, saddr, &msg->target,
idev->cnf.forwarding,
1, (ifp != NULL && inc), inc);
if (neigh)
neigh_release(neigh);
}
out:
if (ifp)
in6_ifa_put(ifp);
else
in6_dev_put(idev);
return; return;
} }
......
...@@ -230,7 +230,7 @@ static int netlink_create(struct socket *sock, int protocol) ...@@ -230,7 +230,7 @@ static int netlink_create(struct socket *sock, int protocol)
sock_init_data(sock,sk); sock_init_data(sock,sk);
sk_set_owner(sk, THIS_MODULE); sk_set_owner(sk, THIS_MODULE);
nlk = nlk_sk(sk) = kmalloc(sizeof(*nlk), GFP_KERNEL); nlk = sk->sk_protinfo = kmalloc(sizeof(*nlk), GFP_KERNEL);
if (!nlk) { if (!nlk) {
sk_free(sk); sk_free(sk);
return -ENOMEM; return -ENOMEM;
......
...@@ -961,7 +961,7 @@ static int packet_create(struct socket *sock, int protocol) ...@@ -961,7 +961,7 @@ static int packet_create(struct socket *sock, int protocol)
sock_init_data(sock,sk); sock_init_data(sock,sk);
sk_set_owner(sk, THIS_MODULE); sk_set_owner(sk, THIS_MODULE);
po = pkt_sk(sk) = kmalloc(sizeof(*po), GFP_KERNEL); po = sk->sk_protinfo = kmalloc(sizeof(*po), GFP_KERNEL);
if (!po) if (!po)
goto out_free; goto out_free;
memset(po, 0, sizeof(*po)); memset(po, 0, sizeof(*po));
......
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