summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@kernel.bkbits.net>2004-02-06 00:57:55 -0800
committerDavid S. Miller <davem@kernel.bkbits.net>2004-02-06 00:57:55 -0800
commit39c09b95dabcbdbb7c2e35ad5a9fbf6aaac202a9 (patch)
tree128ce6c648fbd3269d0889a7f532c5526f34b646
parentd925eab60387b18a46b036d8812c0b2166a70332 (diff)
parent7a98480512254fa9e9f029aaeca21be1aeb5fc28 (diff)
Merge davem@nuts.davemloft.net:/disk1/BK/net-2.6
into kernel.bkbits.net:/home/davem/net-2.6
-rw-r--r--Documentation/Changes2
-rw-r--r--Documentation/networking/ethertap.txt2
-rw-r--r--drivers/net/Space.c25
-rw-r--r--drivers/net/pppoe.c2
-rw-r--r--include/linux/if_vlan.h146
-rw-r--r--include/linux/kernel.h1
-rw-r--r--include/linux/netdevice.h4
-rw-r--r--include/linux/string.h3
-rw-r--r--include/net/arp.h8
-rw-r--r--kernel/printk.c29
-rw-r--r--lib/string.c16
-rw-r--r--net/8021q/vlan_dev.c63
-rw-r--r--net/Kconfig10
-rw-r--r--net/core/dev.c167
-rw-r--r--net/core/utils.c30
-rw-r--r--net/decnet/Kconfig5
-rw-r--r--net/ipv4/Kconfig2
-rw-r--r--net/ipv4/arp.c66
-rw-r--r--net/ipv6/ndisc.c207
-rw-r--r--net/netlink/af_netlink.c2
-rw-r--r--net/packet/af_packet.c2
21 files changed, 491 insertions, 301 deletions
diff --git a/Documentation/Changes b/Documentation/Changes
index e0288627d64a..fe1bf8b9445f 100644
--- a/Documentation/Changes
+++ b/Documentation/Changes
@@ -407,7 +407,7 @@ o <http://www.iptables.org/downloads.html>
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
--------
diff --git a/Documentation/networking/ethertap.txt b/Documentation/networking/ethertap.txt
index 7f3b52955a0b..337f650d7678 100644
--- a/Documentation/networking/ethertap.txt
+++ b/Documentation/networking/ethertap.txt
@@ -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
have no experience with that yet. ANK uses it in his excellent iproute2
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
http://www.europe.redhat.com/documentation/man-pages/man7/netlink.7.php3
diff --git a/drivers/net/Space.c b/drivers/net/Space.c
index 51ed68f486b8..4da8f077de9a 100644
--- a/drivers/net/Space.c
+++ b/drivers/net/Space.c
@@ -430,28 +430,3 @@ static int __init net_olddevs_init(void)
}
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);
diff --git a/drivers/net/pppoe.c b/drivers/net/pppoe.c
index 011eaf26e9f6..733c72960d3c 100644
--- a/drivers/net/pppoe.c
+++ b/drivers/net/pppoe.c
@@ -517,7 +517,7 @@ static int pppoe_create(struct socket *sock)
sk->sk_protocol = PX_PROTO_OE;
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)
goto frees;
memset(po, 0, sizeof(*po));
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 6cb10ed07188..104df1877778 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -200,6 +200,152 @@ static inline int vlan_hwaccel_receive_skb(struct sk_buff *skb,
{
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__ */
/* VLAN IOCTLs are found in sockios.h */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 6365a4159514..228182715b1d 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -90,6 +90,7 @@ asmlinkage int printk(const char * fmt, ...)
unsigned long int_sqrt(unsigned long);
extern int printk_ratelimit(void);
+extern int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst);
static inline void console_silent(void)
{
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 84b6fd41e2d2..1a77c3caf115 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -375,6 +375,10 @@ struct net_device
atomic_t refcnt;
/* delayed register/unregister */
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 */
enum { NETREG_UNINITIALIZED=0,
diff --git a/include/linux/string.h b/include/linux/string.h
index f37b7a6813d3..6ad4e5c32f22 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -52,6 +52,9 @@ extern int strnicmp(const char *, const char *, __kernel_size_t);
#ifndef __HAVE_ARCH_STRCHR
extern char * strchr(const char *,int);
#endif
+#ifndef __HAVE_ARCH_STRNCHR
+extern char * strnchr(const char *, size_t, int);
+#endif
#ifndef __HAVE_ARCH_STRRCHR
extern char * strrchr(const char *,int);
#endif
diff --git a/include/net/arp.h b/include/net/arp.h
index f65d245f42cc..61fd735c7017 100644
--- a/include/net/arp.h
+++ b/include/net/arp.h
@@ -5,6 +5,8 @@
#include <linux/if_arp.h>
#include <net/neighbour.h>
+#define HAVE_ARP_CREATE
+
extern struct neigh_table arp_tbl;
extern void arp_init(void);
@@ -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 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;
#endif /* _ARP_H */
diff --git a/kernel/printk.c b/kernel/printk.c
index 90be371e4842..8f2905cfa0a6 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -784,12 +784,6 @@ void tty_write_message(struct tty_struct *tty, char *msg)
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.
*
@@ -797,7 +791,7 @@ int printk_ratelimit_burst = 10;
* every printk_ratelimit_jiffies to make a denial-of-service
* attack impossible.
*/
-int printk_ratelimit(void)
+int __printk_ratelimit(int ratelimit_jiffies, int ratelimit_burst)
{
static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED;
static unsigned long toks = 10*5*HZ;
@@ -809,12 +803,12 @@ int printk_ratelimit(void)
spin_lock_irqsave(&ratelimit_lock, flags);
toks += now - last_msg;
last_msg = now;
- if (toks > (printk_ratelimit_burst * printk_ratelimit_jiffies))
- toks = printk_ratelimit_burst * printk_ratelimit_jiffies;
- if (toks >= printk_ratelimit_jiffies) {
+ if (toks > (ratelimit_burst * ratelimit_jiffies))
+ toks = ratelimit_burst * ratelimit_jiffies;
+ if (toks >= ratelimit_jiffies) {
int lost = missed;
missed = 0;
- toks -= printk_ratelimit_jiffies;
+ toks -= ratelimit_jiffies;
spin_unlock_irqrestore(&ratelimit_lock, flags);
if (lost)
printk(KERN_WARNING "printk: %d messages suppressed.\n", lost);
@@ -824,4 +818,17 @@ int printk_ratelimit(void)
spin_unlock_irqrestore(&ratelimit_lock, flags);
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);
diff --git a/lib/string.c b/lib/string.c
index e660de079a57..d2f23f2c1e69 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -273,6 +273,22 @@ char * strrchr(const char * s, int c)
}
#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
/**
* strlen - Find the length of a string
diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c
index 47131d2b27a3..b91d251f3fed 100644
--- a/net/8021q/vlan_dev.c
+++ b/net/8021q/vlan_dev.c
@@ -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)) {
+ int orig_headroom = skb_headroom(skb);
unsigned short veth_TCI;
/* 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)
printk(VLAN_DBG "%s: proto to encap: 0x%hx (hbo)\n",
__FUNCTION__, htons(veth->h_vlan_proto));
#endif
-
- 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
+ /* Construct the second two bytes. This field looks something
* like:
* usr_priority: 3 bits (high bits)
* CFI 1 bit
@@ -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_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
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)
stats->tx_packets++; /* for statics only */
stats->tx_bytes += skb->len;
- skb->protocol = __constant_htons(ETH_P_8021Q);
- skb->mac.raw -= VLAN_HLEN;
- skb->nh.raw -= VLAN_HLEN;
-
+ skb->dev = VLAN_DEV_INFO(dev)->real_dev;
dev_queue_xmit(skb);
return 0;
@@ -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)
{
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_bytes += skb->len;
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);
return 0;
diff --git a/net/Kconfig b/net/Kconfig
index 3dcc4c31eb0a..d20ba708570c 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -145,7 +145,7 @@ config DECNET
To find some tools to use with the kernel layer support, please
look at Patrick Caulfield's web site:
- <http://linux.dreamtime.org/decnet/>.
+ <http://linux-decnet.sourceforge.net/>.
More detailed documentation is available in
<file:Documentation/networking/decnet.txt>.
@@ -436,7 +436,7 @@ config X25
(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
- <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
<file:Documentation/networking/x25.txt> and
<file:Documentation/networking/x25-iface.txt>.
@@ -571,7 +571,7 @@ config NET_FASTROUTE
At the moment, few devices support fast switching (tulip is one of
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.
@@ -583,7 +583,7 @@ config NET_HW_FLOWCONTROL
during periods of extreme congestion. At the moment only a couple
of device drivers support it (really only one -- tulip, 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>).
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
@@ -614,7 +614,7 @@ config NET_SCHED
This code is considered to be experimental.
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
<http://snafu.freedom.org/linux2.2/iproute-notes.html>.
diff --git a/net/core/dev.c b/net/core/dev.c
index 55fbdfa556c1..d1dfcef63c5a 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -161,6 +161,47 @@ static struct timer_list samp_timer = TIMER_INITIALIZER(sample_queue, 0, 0);
#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
*/
@@ -443,12 +484,15 @@ __setup("netdev=", netdev_boot_setup);
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))
- break;
- return dev;
+ return dev;
+ }
+ return NULL;
}
/**
@@ -516,12 +560,15 @@ int __dev_get(const char *name)
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)
- break;
- return dev;
+ return dev;
+ }
+ return NULL;
}
@@ -673,30 +720,55 @@ int dev_valid_name(const char *name)
int dev_alloc_name(struct net_device *dev, const char *name)
{
- int i;
- char buf[32];
- char *p;
+ int i = 0;
+ char buf[IFNAMSIZ];
+ const char *p;
+ const int max_netdevices = 8*PAGE_SIZE;
+ long *inuse;
+ struct net_device *d;
- /*
- * Verify the string as this thing may have come from
- * the user. There must be either one "%d" and no other "%"
- * characters, or no "%" characters at all.
- */
- p = strchr(name, '%');
- if (p && (p[1] != 'd' || strchr(p + 2, '%')))
- return -EINVAL;
+ p = strnchr(name, IFNAMSIZ-1, '%');
+ if (p) {
+ /*
+ * Verify the string as this thing may have come from
+ * the user. There must be either one "%d" and no other "%"
+ * characters.
+ */
+ if (p[1] != 'd' || strchr(p + 2, '%'))
+ return -EINVAL;
- /*
- * If you need over 100 please also fix the algorithm...
- */
- for (i = 0; i < 100; i++) {
- snprintf(buf, sizeof(buf), name, i);
- if (!__dev_get_by_name(buf)) {
- strcpy(dev->name, buf);
- return i;
+ /* Use one page as a bit array of possible slots */
+ inuse = (long *) get_zeroed_page(GFP_ATOMIC);
+ if (!inuse)
+ return -ENOMEM;
+
+ for (d = dev_base; d; d = d->next) {
+ if (!sscanf(d->name, name, &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)
else
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);
notifier_call_chain(&netdev_chain, NETDEV_CHANGENAME, dev);
return 0;
@@ -2717,7 +2792,8 @@ static inline void net_set_todo(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;
BUG_ON(dev_boot_phase);
@@ -2758,13 +2834,17 @@ int register_netdevice(struct net_device *dev)
if (dev->iflink == -1)
dev->iflink = dev->ifindex;
- /* Check for existence, and append to tail of chain */
- ret = -EEXIST;
- for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) {
- if (d == dev || !strcmp(d->name, dev->name))
- goto out_err;
- }
-
+ /* Check for existence of name */
+ head = dev_name_hash(dev->name);
+ hlist_for_each(p, head) {
+ struct net_device *d
+ = 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. */
if ((dev->features & NETIF_F_SG) &&
!(dev->features & (NETIF_F_IP_CSUM |
@@ -2793,7 +2873,10 @@ int register_netdevice(struct net_device *dev)
dev->next = NULL;
dev_init_scheduler(dev);
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->reg_state = NETREG_REGISTERING;
write_unlock_bh(&dev_base_lock);
@@ -3015,6 +3098,10 @@ int unregister_netdevice(struct net_device *dev)
for (dp = &dev_base; (d = *dp) != NULL; dp = &d->next) {
if (d == dev) {
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;
write_unlock_bh(&dev_base_lock);
break;
@@ -3091,6 +3178,12 @@ static int __init net_dev_init(void)
for (i = 0; i < 16; 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.
*/
diff --git a/net/core/utils.c b/net/core/utils.c
index 995f2b5168c2..8058d9c5e236 100644
--- a/net/core/utils.c
+++ b/net/core/utils.c
@@ -41,37 +41,11 @@ int net_msg_cost = 5*HZ;
int net_msg_burst = 10;
/*
- * This enforces a rate limit: not more than one kernel message
- * every 5secs to make a denial-of-service attack impossible.
- *
- * All warning printk()s should be guarded by this function.
+ * All net warning printk()s should be guarded by this function.
*/
int net_ratelimit(void)
{
- static spinlock_t ratelimit_lock = SPIN_LOCK_UNLOCKED;
- 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;
+ return __printk_ratelimit(net_msg_cost, net_msg_burst);
}
EXPORT_SYMBOL(net_random);
diff --git a/net/decnet/Kconfig b/net/decnet/Kconfig
index 74f1f2db6618..74d6aaceeaed 100644
--- a/net/decnet/Kconfig
+++ b/net/decnet/Kconfig
@@ -22,8 +22,9 @@ config DECNET_ROUTER
network link driver", "Routing messages" and "Network packet
filtering". The first two are required to allow configuration via
rtnetlink (you will need Alexey Kuznetsov's iproute2 package
- from <ftp://ftp.inr.ac.ru/>). The "Network packet filtering" option
- will be required for the forthcoming routing daemon to work.
+ from <ftp://ftp.tux.org/pub/net/ip-routing/>). The "Network packet
+ filtering" option will be required for the forthcoming routing daemon
+ to work.
See <file:Documentation/networking/decnet.txt> for more information.
diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
index 6ee8011d0bc3..0791bd025704 100644
--- a/net/ipv4/Kconfig
+++ b/net/ipv4/Kconfig
@@ -71,7 +71,7 @@ config IP_MULTIPLE_TABLES
documentation at <http://www.compendium.com.ar/policy-routing.txt>
and <ftp://post.tepkom.ru/pub/vol2/Linux/docs/advanced-routing.tex>.
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.
diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c
index 5c03f63502bc..0de93f953ef9 100644
--- a/net/ipv4/arp.c
+++ b/net/ipv4/arp.c
@@ -67,6 +67,10 @@
* now it is in net/core/neighbour.c.
* Krzysztof Halasa: Added Frame Relay ARP support.
* 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>
@@ -487,34 +491,26 @@ 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.
*/
-
-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 *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)
{
struct sk_buff *skb;
struct arphdr *arp;
unsigned char *arp_ptr;
/*
- * No arp on this interface.
- */
-
- if (dev->flags&IFF_NOARP)
- return;
-
- /*
* Allocate a buffer
*/
skb = alloc_skb(sizeof(struct arphdr)+ 2*(dev->addr_len+4)
+ LL_RESERVED_SPACE(dev), GFP_ATOMIC);
if (skb == NULL)
- return;
+ return NULL;
skb_reserve(skb, LL_RESERVED_SPACE(dev));
skb->nh.raw = skb->data;
@@ -594,12 +590,46 @@ void arp_send(int type, int ptype, u32 dest_ip,
arp_ptr+=dev->addr_len;
memcpy(arp_ptr, &dest_ip, 4);
- /* Send it off, maybe filter it using firewalling first. */
- NF_HOOK(NF_ARP, NF_ARP_OUT, skb, NULL, dev, dev_queue_xmit);
- return;
+ return skb;
out:
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)
@@ -1437,6 +1467,8 @@ static int __init arp_proc_init(void)
EXPORT_SYMBOL(arp_broken_ops);
EXPORT_SYMBOL(arp_find);
EXPORT_SYMBOL(arp_rcv);
+EXPORT_SYMBOL(arp_create);
+EXPORT_SYMBOL(arp_xmit);
EXPORT_SYMBOL(arp_send);
EXPORT_SYMBOL(arp_tbl);
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 79b1dbf6692c..5c2c1f6aafd5 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -707,8 +707,10 @@ static void ndisc_recv_ns(struct sk_buff *skb)
struct ndisc_options ndopts;
struct net_device *dev = skb->dev;
struct inet6_ifaddr *ifp;
+ struct inet6_dev *idev = NULL;
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 (net_ratelimit())
@@ -720,7 +722,7 @@ static void ndisc_recv_ns(struct sk_buff *skb)
* RFC2461 7.1.1:
* 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[1] == htonl(0x00000000) &&
daddr->s6_addr32[2] == htonl(0x00000001) &&
@@ -750,13 +752,15 @@ static void ndisc_recv_ns(struct sk_buff *skb)
* there MUST NOT be source link-layer address option
* in the message.
*/
- if (addr_type == IPV6_ADDR_ANY) {
+ if (dad) {
if (net_ratelimit())
printk(KERN_WARNING "ICMP6 NS: bad DAD packet (link-layer address option)\n");
return;
}
}
+ inc = ipv6_addr_is_multicast(daddr);
+
if ((ifp = ipv6_get_ifaddr(&msg->target, dev, 1)) != NULL) {
if (ifp->flags & IFA_F_TENTATIVE) {
/* Address is tentative. If the source
@@ -764,146 +768,89 @@ static void ndisc_recv_ns(struct sk_buff *skb)
does DAD, otherwise we ignore solicitations
until DAD timer expires.
*/
- if (addr_type == IPV6_ADDR_ANY) {
- if (dev->type == ARPHRD_IEEE802_TR) {
- unsigned char *sadr = skb->mac.raw ;
- if (((sadr[8] &0x7f) != (dev->dev_addr[0] & 0x7f)) ||
- (sadr[9] != dev->dev_addr[1]) ||
- (sadr[10] != dev->dev_addr[2]) ||
- (sadr[11] != dev->dev_addr[3]) ||
- (sadr[12] != dev->dev_addr[4]) ||
- (sadr[13] != dev->dev_addr[5]))
- {
- addrconf_dad_failure(ifp) ;
- }
- } else {
- addrconf_dad_failure(ifp);
+ if (!dad)
+ goto out;
+ if (dev->type == ARPHRD_IEEE802_TR) {
+ unsigned char *sadr = skb->mac.raw;
+ if (((sadr[8] ^ dev->dev_addr[0]) & 0x7f) == 0 &&
+ sadr[9] == dev->dev_addr[1] &&
+ sadr[10] == dev->dev_addr[2] &&
+ sadr[11] == dev->dev_addr[3] &&
+ sadr[12] == dev->dev_addr[4] &&
+ sadr[13] == dev->dev_addr[5]) {
+ /* looped-back to us */
+ goto out;
}
- } else
- in6_ifa_put(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);
+ }
+ addrconf_dad_failure(ifp);
return;
}
- if (addr_type & IPV6_ADDR_UNICAST) {
- if (ipv6_addr_is_multicast(daddr))
- 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, &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 */
-
+ idev = ifp->idev;
+ } else {
+ idev = in6_dev_get(dev);
if (!idev) {
/* XXX: count this drop? */
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 (neigh || !dev->hard_header) {
- ndisc_send_na(dev, neigh, saddr,
- &msg->target,
- idev->cnf.forwarding, 1, 0, inc);
- if (neigh)
- neigh_release(neigh);
- }
- }
- in6_dev_put(idev);
- } else {
- struct inet6_dev *in6_dev = in6_dev_get(dev);
-
- 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 {
+ if (ipv6_chk_acast_addr(dev, &msg->target) ||
+ (idev->cnf.forwarding &&
+ pneigh_lookup(&nd_tbl, &msg->target, dev, 0))) {
+ if (skb->stamp.tv_sec != 0 &&
+ skb->pkt_type != PACKET_HOST &&
+ inc != 0 &&
+ idev->nd_parms->proxy_delay != 0) {
+ /*
+ * for anycast or proxy,
+ * sender should delay its response
+ * by a random time between 0 and
+ * MAX_ANYCAST_DELAY_TIME seconds.
+ * (RFC2461) -- yoshfuji
+ */
struct sk_buff *n = skb_clone(skb, GFP_ATOMIC);
if (n)
- pneigh_enqueue(&nd_tbl, in6_dev->nd_parms, n);
- in6_dev_put(in6_dev);
- return;
+ pneigh_enqueue(&nd_tbl, idev->nd_parms, n);
+ goto out;
}
- }
- if (in6_dev)
- in6_dev_put(in6_dev);
+ } else
+ goto out;
}
+
+ 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;
}
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index b0e410d1a88c..38c27b9bb70a 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -230,7 +230,7 @@ static int netlink_create(struct socket *sock, int protocol)
sock_init_data(sock,sk);
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) {
sk_free(sk);
return -ENOMEM;
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index 3b01f540b652..7b4a14aac955 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -961,7 +961,7 @@ static int packet_create(struct socket *sock, int protocol)
sock_init_data(sock,sk);
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)
goto out_free;
memset(po, 0, sizeof(*po));