summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-03-07 15:45:24 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-03-07 15:45:24 +0000
commit9f9f3e6e8548a596697778337110a423c384b6f3 (patch)
tree5dd4b290ef532cf5ecb058e1a92cd3435afeac8c /net
parentd5c9a365ee7d2fded249aa5abfc5e89587583029 (diff)
Merge with Linux 2.3.49.
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_device.c3
-rw-r--r--net/core/dev.c49
-rw-r--r--net/core/netfilter.c352
-rw-r--r--net/core/rtnetlink.c2
-rw-r--r--net/core/sock.c17
-rw-r--r--net/decnet/TODO4
-rw-r--r--net/decnet/af_decnet.c53
-rw-r--r--net/decnet/dn_neigh.c6
-rw-r--r--net/decnet/dn_nsp_in.c2
-rw-r--r--net/decnet/dn_nsp_out.c5
-rw-r--r--net/decnet/dn_route.c47
-rw-r--r--net/ipv4/icmp.c6
-rw-r--r--net/ipv4/ip_input.c5
-rw-r--r--net/ipv4/protocol.c17
-rw-r--r--net/ipv4/tcp_input.c12
-rw-r--r--net/ipv4/udp.c3
-rw-r--r--net/ipv6/af_inet6.c29
-rw-r--r--net/ipv6/datagram.c14
-rw-r--r--net/ipv6/icmp.c4
-rw-r--r--net/ipv6/ip6_input.c33
-rw-r--r--net/ipv6/ip6_output.c117
-rw-r--r--net/ipv6/ipv6_sockglue.c21
-rw-r--r--net/ipv6/protocol.c17
-rw-r--r--net/ipv6/raw.c43
-rw-r--r--net/ipv6/tcp_ipv6.c39
-rw-r--r--net/ipv6/udp.c38
-rw-r--r--net/ipx/af_ipx.c13
-rw-r--r--net/irda/irda_device.c1
-rw-r--r--net/irda/iriap_event.c6
-rw-r--r--net/irda/parameters.c6
-rw-r--r--net/netsyms.c6
-rw-r--r--net/sched/sch_generic.c41
-rw-r--r--net/sched/sch_red.c79
-rw-r--r--net/unix/af_unix.c8
34 files changed, 650 insertions, 448 deletions
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index d2fac6697..5f7b12541 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -5,7 +5,7 @@
* Authors:
* Lennert Buytenhek <buytenh@gnu.org>
*
- * $Id: br_device.c,v 1.2 2000/02/24 19:48:06 davem Exp $
+ * $Id: br_device.c,v 1.3 2000/03/01 02:58:09 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -13,7 +13,6 @@
* 2 of the License, or (at your option) any later version.
*/
-#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/if_bridge.h>
diff --git a/net/core/dev.c b/net/core/dev.c
index 638ab6432..b09b3b9a4 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -76,6 +76,7 @@
#include <linux/etherdevice.h>
#include <linux/notifier.h>
#include <linux/skbuff.h>
+#include <linux/brlock.h>
#include <net/sock.h>
#include <linux/rtnetlink.h>
#include <net/slhc.h>
@@ -129,7 +130,6 @@ const char *if_port_text[] = {
static struct packet_type *ptype_base[16]; /* 16 way hashed list */
static struct packet_type *ptype_all = NULL; /* Taps */
-static rwlock_t ptype_lock = RW_LOCK_UNLOCKED;
/*
* Our notifier list
@@ -181,7 +181,7 @@ void dev_add_pack(struct packet_type *pt)
{
int hash;
- write_lock_bh(&ptype_lock);
+ br_write_lock_bh(BR_NETPROTO_LOCK);
#ifdef CONFIG_NET_FASTROUTE
/* Hack to detect packet socket */
@@ -199,7 +199,7 @@ void dev_add_pack(struct packet_type *pt)
pt->next = ptype_base[hash];
ptype_base[hash] = pt;
}
- write_unlock_bh(&ptype_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
}
@@ -211,7 +211,7 @@ void dev_remove_pack(struct packet_type *pt)
{
struct packet_type **pt1;
- write_lock_bh(&ptype_lock);
+ br_write_lock_bh(BR_NETPROTO_LOCK);
if (pt->type == htons(ETH_P_ALL)) {
netdev_nit--;
@@ -227,11 +227,11 @@ void dev_remove_pack(struct packet_type *pt)
if (pt->data)
netdev_fastroute_obstacles--;
#endif
- write_unlock_bh(&ptype_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
return;
}
}
- write_unlock_bh(&ptype_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
printk(KERN_WARNING "dev_remove_pack: %p not found.\n", pt);
}
@@ -581,7 +581,7 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
struct packet_type *ptype;
get_fast_time(&skb->stamp);
- read_lock(&ptype_lock);
+ br_read_lock(BR_NETPROTO_LOCK);
for (ptype = ptype_all; ptype!=NULL; ptype = ptype->next)
{
/* Never send packets back to the socket
@@ -615,7 +615,7 @@ void dev_queue_xmit_nit(struct sk_buff *skb, struct net_device *dev)
ptype->func(skb2, skb->dev, ptype);
}
}
- read_unlock(&ptype_lock);
+ br_read_unlock(BR_NETPROTO_LOCK);
}
/*
@@ -863,8 +863,8 @@ static void deliver_to_old_ones(struct packet_type *pt, struct sk_buff *skb, int
}
/* Reparent skb to master device. This function is called
- * only from net_rx_action under ptype_lock. It is misuse
- * of ptype_lock, but it is OK for now.
+ * only from net_rx_action under BR_NETPROTO_LOCK. It is misuse
+ * of BR_NETPROTO_LOCK, but it is OK for now.
*/
static __inline__ void skb_bond(struct sk_buff *skb)
{
@@ -924,9 +924,9 @@ static void net_tx_action(struct softirq_action *h)
void net_call_rx_atomic(void (*fn)(void))
{
- write_lock_bh(&ptype_lock);
+ br_write_lock_bh(BR_NETPROTO_LOCK);
fn();
- write_unlock_bh(&ptype_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
}
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
@@ -936,11 +936,13 @@ void (*br_handle_frame_hook)(struct sk_buff *skb) = NULL;
static void __inline__ handle_bridge(struct sk_buff *skb,
struct packet_type *pt_prev)
{
- if (pt_prev)
- deliver_to_old_ones(pt_prev, skb, 0);
- else {
- atomic_inc(&skb->users);
- pt_prev->func(skb, skb->dev, pt_prev);
+ if (pt_prev) {
+ if (!pt_prev->data)
+ deliver_to_old_ones(pt_prev, skb, 0);
+ else {
+ atomic_inc(&skb->users);
+ pt_prev->func(skb, skb->dev, pt_prev);
+ }
}
br_handle_frame_hook(skb);
@@ -954,7 +956,7 @@ static void net_rx_action(struct softirq_action *h)
unsigned long start_time = jiffies;
int bugdet = netdev_max_backlog;
- read_lock(&ptype_lock);
+ br_read_lock(BR_NETPROTO_LOCK);
for (;;) {
struct sk_buff *skb;
@@ -1034,7 +1036,7 @@ static void net_rx_action(struct softirq_action *h)
if (bugdet-- < 0 || jiffies - start_time > 1)
goto softnet_break;
}
- read_unlock(&ptype_lock);
+ br_read_unlock(BR_NETPROTO_LOCK);
local_irq_disable();
if (queue->throttle) {
@@ -1050,7 +1052,7 @@ static void net_rx_action(struct softirq_action *h)
return;
softnet_break:
- read_unlock(&ptype_lock);
+ br_read_unlock(BR_NETPROTO_LOCK);
local_irq_disable();
netdev_rx_stat[this_cpu].time_squeeze++;
@@ -1391,9 +1393,9 @@ int netdev_set_master(struct net_device *slave, struct net_device *master)
dev_hold(master);
}
- write_lock_bh(&ptype_lock);
+ br_write_lock_bh(BR_NETPROTO_LOCK);
slave->master = master;
- write_unlock_bh(&ptype_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
if (old)
dev_put(old);
@@ -1516,7 +1518,7 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
case SIOCGIFFLAGS: /* Get interface flags */
ifr->ifr_flags = (dev->flags&~(IFF_PROMISC|IFF_ALLMULTI|IFF_RUNNING))
|(dev->gflags&(IFF_PROMISC|IFF_ALLMULTI));
- if (netif_running(dev))
+ if (netif_running(dev) && netif_carrier_ok(dev))
ifr->ifr_flags |= IFF_RUNNING;
return 0;
@@ -2129,6 +2131,7 @@ int __init net_dev_init(void)
if (dev->rebuild_header == NULL)
dev->rebuild_header = default_rebuild_header;
dev_init_scheduler(dev);
+ set_bit(__LINK_STATE_PRESENT, &dev->state);
}
}
diff --git a/net/core/netfilter.c b/net/core/netfilter.c
index bf734a60e..8b04435c3 100644
--- a/net/core/netfilter.c
+++ b/net/core/netfilter.c
@@ -5,6 +5,8 @@
* way.
*
* Rusty Russell (C)1998 -- This code is GPL.
+ *
+ * February 2000: Modified by James Morris to have 1 queue per protocol.
*/
#include <linux/config.h>
#include <linux/netfilter.h>
@@ -16,7 +18,7 @@
#include <linux/interrupt.h>
#include <linux/if.h>
#include <linux/netdevice.h>
-#include <linux/spinlock.h>
+#include <linux/brlock.h>
#define __KERNEL_SYSCALLS__
#include <linux/unistd.h>
@@ -32,41 +34,31 @@
#define NFDEBUG(format, args...)
#endif
-/* Each queued (to userspace) skbuff has one of these. */
-struct nf_info
-{
- /* The ops struct which sent us to userspace. */
- struct nf_hook_ops *elem;
-
- /* If we're sent to userspace, this keeps housekeeping info */
- int pf;
- unsigned long mark;
- unsigned int hook;
- struct net_device *indev, *outdev;
- int (*okfn)(struct sk_buff *);
-};
-
-static rwlock_t nf_lock = RW_LOCK_UNLOCKED;
+/* Sockopts only registered and called from user context, so
+ BR_NETPROTO_LOCK would be overkill. Also, [gs]etsockopt calls may
+ sleep. */
static DECLARE_MUTEX(nf_sockopt_mutex);
struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS];
static LIST_HEAD(nf_sockopts);
-static LIST_HEAD(nf_interested);
+
+/*
+ * A queue handler may be registered for each protocol. Each is protected by
+ * long term mutex. The handler must provide an an outfn() to accept packets
+ * for queueing and must reinject all packets it receives, no matter what.
+ */
+static struct nf_queue_handler_t {
+ nf_queue_outfn_t outfn;
+ void *data;
+} queue_handler[NPROTO];
int nf_register_hook(struct nf_hook_ops *reg)
{
struct list_head *i;
-#ifdef CONFIG_NETFILTER_DEBUG
- if (reg->pf<0 || reg->pf>=NPROTO || reg->hooknum >= NF_MAX_HOOKS) {
- NFDEBUG("nf_register_hook: bad vals: pf=%i, hooknum=%u.\n",
- reg->pf, reg->hooknum);
- return -EINVAL;
- }
-#endif
NFDEBUG("nf_register_hook: pf=%i hook=%u.\n", reg->pf, reg->hooknum);
-
- write_lock_bh(&nf_lock);
+
+ br_write_lock_bh(BR_NETPROTO_LOCK);
for (i = nf_hooks[reg->pf][reg->hooknum].next;
i != &nf_hooks[reg->pf][reg->hooknum];
i = i->next) {
@@ -74,22 +66,15 @@ int nf_register_hook(struct nf_hook_ops *reg)
break;
}
list_add(&reg->list, i->prev);
- write_unlock_bh(&nf_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
return 0;
}
void nf_unregister_hook(struct nf_hook_ops *reg)
{
-#ifdef CONFIG_NETFILTER_DEBUG
- if (reg->pf<0 || reg->pf>=NPROTO || reg->hooknum >= NF_MAX_HOOKS) {
- NFDEBUG("nf_unregister_hook: bad vals: pf=%i, hooknum=%u.\n",
- reg->pf, reg->hooknum);
- return;
- }
-#endif
- write_lock_bh(&nf_lock);
+ br_write_lock_bh(BR_NETPROTO_LOCK);
list_del(&reg->list);
- write_unlock_bh(&nf_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
}
/* Do exclusive ranges overlap? */
@@ -105,22 +90,6 @@ int nf_register_sockopt(struct nf_sockopt_ops *reg)
struct list_head *i;
int ret = 0;
-#ifdef CONFIG_NETFILTER_DEBUG
- if (reg->pf<0 || reg->pf>=NPROTO) {
- NFDEBUG("nf_register_sockopt: bad val: pf=%i.\n", reg->pf);
- return -EINVAL;
- }
- if (reg->set_optmin > reg->set_optmax) {
- NFDEBUG("nf_register_sockopt: bad set val: min=%i max=%i.\n",
- reg->set_optmin, reg->set_optmax);
- return -EINVAL;
- }
- if (reg->get_optmin > reg->get_optmax) {
- NFDEBUG("nf_register_sockopt: bad get val: min=%i max=%i.\n",
- reg->get_optmin, reg->get_optmax);
- return -EINVAL;
- }
-#endif
if (down_interruptible(&nf_sockopt_mutex) != 0)
return -EINTR;
@@ -149,12 +118,6 @@ out:
void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
{
-#ifdef CONFIG_NETFILTER_DEBUG
- if (reg->pf<0 || reg->pf>=NPROTO) {
- NFDEBUG("nf_register_sockopt: bad val: pf=%i.\n", reg->pf);
- return;
- }
-#endif
/* No point being interruptible: we're probably in cleanup_module() */
down(&nf_sockopt_mutex);
list_del(&reg->list);
@@ -167,6 +130,33 @@ void nf_unregister_sockopt(struct nf_sockopt_ops *reg)
#include <net/tcp.h>
#include <linux/netfilter_ipv4.h>
+static void debug_print_hooks_ip(unsigned int nf_debug)
+{
+ if (nf_debug & (1 << NF_IP_PRE_ROUTING)) {
+ printk("PRE_ROUTING ");
+ nf_debug ^= (1 << NF_IP_PRE_ROUTING);
+ }
+ if (nf_debug & (1 << NF_IP_LOCAL_IN)) {
+ printk("LOCAL_IN ");
+ nf_debug ^= (1 << NF_IP_LOCAL_IN);
+ }
+ if (nf_debug & (1 << NF_IP_FORWARD)) {
+ printk("FORWARD ");
+ nf_debug ^= (1 << NF_IP_FORWARD);
+ }
+ if (nf_debug & (1 << NF_IP_LOCAL_OUT)) {
+ printk("LOCAL_OUT ");
+ nf_debug ^= (1 << NF_IP_LOCAL_OUT);
+ }
+ if (nf_debug & (1 << NF_IP_POST_ROUTING)) {
+ printk("POST_ROUTING ");
+ nf_debug ^= (1 << NF_IP_POST_ROUTING);
+ }
+ if (nf_debug)
+ printk("Crap bits: 0x%04X", nf_debug);
+ printk("\n");
+}
+
void nf_dump_skb(int pf, struct sk_buff *skb)
{
printk("skb: pf=%i %s dev=%s len=%u\n",
@@ -257,7 +247,7 @@ void nf_debug_ip_finish_output2(struct sk_buff *skb)
{
/* If it's owned, it must have gone through the
* NF_IP_LOCAL_OUT and NF_IP_POST_ROUTING.
- * Otherwise, must have gone through NF_IP_RAW_INPUT,
+ * Otherwise, must have gone through
* NF_IP_PRE_ROUTING, NF_IP_FORWARD and NF_IP_POST_ROUTING.
*/
if (skb->sk) {
@@ -269,9 +259,6 @@ void nf_debug_ip_finish_output2(struct sk_buff *skb)
}
} else {
if (skb->nf_debug != ((1 << NF_IP_PRE_ROUTING)
-#ifdef CONFIG_IP_NETFILTER_RAW_INPUT
- | (1 << NF_IP_RAW_INPUT)
-#endif
| (1 << NF_IP_FORWARD)
| (1 << NF_IP_POST_ROUTING))) {
printk("ip_finish_output: bad unowned skb = %p: ",skb);
@@ -280,29 +267,8 @@ void nf_debug_ip_finish_output2(struct sk_buff *skb)
}
}
}
-
-
#endif /*CONFIG_NETFILTER_DEBUG*/
-void nf_cacheflush(int pf, unsigned int hook, const void *packet,
- const struct net_device *indev, const struct net_device *outdev,
- __u32 packetcount, __u32 bytecount)
-{
- struct list_head *i;
-
- read_lock_bh(&nf_lock);
- for (i = nf_hooks[pf][hook].next;
- i != &nf_hooks[pf][hook];
- i = i->next) {
- if (((struct nf_hook_ops *)i)->flush)
- ((struct nf_hook_ops *)i)->flush(packet, indev,
- outdev,
- packetcount,
- bytecount);
- }
- read_unlock_bh(&nf_lock);
-}
-
/* Call get/setsockopt() */
static int nf_sockopt(struct sock *sk, int pf, int val,
char *opt, int *len, int get)
@@ -360,15 +326,12 @@ static unsigned int nf_iterate(struct list_head *head,
struct nf_hook_ops *elem = (struct nf_hook_ops *)*i;
switch (elem->hook(hook, skb, indev, outdev, okfn)) {
case NF_QUEUE:
- NFDEBUG("nf_iterate: NF_QUEUE for %p.\n", *skb);
return NF_QUEUE;
case NF_STOLEN:
- NFDEBUG("nf_iterate: NF_STOLEN for %p.\n", *skb);
return NF_STOLEN;
case NF_DROP:
- NFDEBUG("nf_iterate: NF_DROP for %p.\n", *skb);
return NF_DROP;
#ifdef CONFIG_NETFILTER_DEBUG
@@ -384,6 +347,38 @@ static unsigned int nf_iterate(struct list_head *head,
return NF_ACCEPT;
}
+int nf_register_queue_handler(int pf, nf_queue_outfn_t outfn, void *data)
+{
+ int ret;
+
+ br_write_lock_bh(BR_NETPROTO_LOCK);
+ if (queue_handler[pf].outfn)
+ ret = -EBUSY;
+ else {
+ queue_handler[pf].outfn = outfn;
+ queue_handler[pf].data = data;
+ ret = 0;
+ }
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
+
+ return ret;
+}
+
+/* The caller must flush their queue before this */
+int nf_unregister_queue_handler(int pf)
+{
+ NFDEBUG("Unregistering Netfilter queue handler for pf=%d\n", pf);
+ br_write_lock_bh(BR_NETPROTO_LOCK);
+ queue_handler[pf].outfn = NULL;
+ queue_handler[pf].data = NULL;
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
+ return 0;
+}
+
+/*
+ * Any packet that leaves via this function must come back
+ * through nf_reinject().
+ */
static void nf_queue(struct sk_buff *skb,
struct list_head *elem,
int pf, unsigned int hook,
@@ -391,61 +386,43 @@ static void nf_queue(struct sk_buff *skb,
struct net_device *outdev,
int (*okfn)(struct sk_buff *))
{
- struct list_head *i;
+ int status;
+ struct nf_info *info;
- struct nf_info *info = kmalloc(sizeof(*info), GFP_ATOMIC);
+ if (!queue_handler[pf].outfn) {
+ NFDEBUG("nf_queue: noone wants the packet, dropping it.\n");
+ kfree_skb(skb);
+ return;
+ }
+
+ info = kmalloc(sizeof(*info), GFP_ATOMIC);
if (!info) {
- NFDEBUG("nf_hook: OOM.\n");
+ if (net_ratelimit())
+ printk(KERN_ERR "OOM queueing packet %p\n",
+ skb);
kfree_skb(skb);
return;
}
- /* Can't do struct assignments with arrays in them. Damn. */
- info->elem = (struct nf_hook_ops *)elem;
- info->mark = skb->nfmark;
- info->pf = pf;
- info->hook = hook;
- info->okfn = okfn;
- info->indev = indev;
- info->outdev = outdev;
- skb->nfmark = (unsigned long)info;
+ *info = (struct nf_info) {
+ (struct nf_hook_ops *)elem, pf, hook, indev, outdev, okfn };
/* Bump dev refs so they don't vanish while packet is out */
if (indev) dev_hold(indev);
if (outdev) dev_hold(outdev);
- for (i = nf_interested.next; i != &nf_interested; i = i->next) {
- struct nf_interest *recip = (struct nf_interest *)i;
-
- if ((recip->hookmask & (1 << info->hook))
- && info->pf == recip->pf
- && (!recip->mark || info->mark == recip->mark)
- && (!recip->reason || skb->nfreason == recip->reason)) {
- /* FIXME: Andi says: use netlink. Hmmm... --RR */
- if (skb_queue_len(&recip->wake->skbq) >= 100) {
- NFDEBUG("nf_hook: queue to long.\n");
- goto free_discard;
- }
- /* Hand it to userspace for collection */
- skb_queue_tail(&recip->wake->skbq, skb);
- NFDEBUG("Waking up pf=%i hook=%u mark=%lu reason=%u\n",
- pf, hook, skb->nfmark, skb->nfreason);
- wake_up_interruptible(&recip->wake->sleep);
-
- return;
- }
+ status = queue_handler[pf].outfn(skb, info, queue_handler[pf].data);
+ if (status < 0) {
+ /* James M doesn't say fuck enough. */
+ if (indev) dev_put(indev);
+ if (outdev) dev_put(outdev);
+ kfree_s(info, sizeof(*info));
+ kfree_skb(skb);
+ return;
}
- NFDEBUG("nf_hook: noone wants the packet.\n");
-
- free_discard:
- if (indev) dev_put(indev);
- if (outdev) dev_put(outdev);
-
- kfree_s(info, sizeof(*info));
- kfree_skb(skb);
}
-/* nf_hook() doesn't have lock, so may give false positive. */
+/* We have BR_NETPROTO_LOCK here */
int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
struct net_device *indev,
struct net_device *outdev,
@@ -455,21 +432,6 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
unsigned int verdict;
int ret = 0;
-#ifdef CONFIG_NETFILTER_DEBUG
- if (pf < 0 || pf >= NPROTO || hook >= NF_MAX_HOOKS) {
- NFDEBUG("nf_hook: bad vals: pf=%i, hook=%u.\n",
- pf, hook);
- kfree_skb(skb);
- return -EINVAL; /* -ECODERFUCKEDUP ?*/
- }
-
- if (skb->nf_debug & (1 << hook)) {
- NFDEBUG("nf_hook: hook %i already set.\n", hook);
- nf_dump_skb(pf, skb);
- }
- skb->nf_debug |= (1 << hook);
-#endif
- read_lock_bh(&nf_lock);
elem = &nf_hooks[pf][hook];
verdict = nf_iterate(&nf_hooks[pf][hook], &skb, hook, indev,
outdev, &elem, okfn);
@@ -477,7 +439,6 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
NFDEBUG("nf_hook: Verdict = QUEUE.\n");
nf_queue(skb, elem, pf, hook, indev, outdev, okfn);
}
- read_unlock_bh(&nf_lock);
switch (verdict) {
case NF_ACCEPT:
@@ -493,84 +454,41 @@ int nf_hook_slow(int pf, unsigned int hook, struct sk_buff *skb,
return ret;
}
-struct nf_waitinfo {
- unsigned int verdict;
- struct task_struct *owner;
-};
-
-/* For netfilter device. */
-void nf_register_interest(struct nf_interest *interest)
+void nf_reinject(struct sk_buff *skb, struct nf_info *info,
+ unsigned int verdict)
{
- /* First in, best dressed. */
- write_lock_bh(&nf_lock);
- list_add(&interest->list, &nf_interested);
- write_unlock_bh(&nf_lock);
-}
-
-void nf_unregister_interest(struct nf_interest *interest)
-{
- struct sk_buff *skb;
-
- write_lock_bh(&nf_lock);
- list_del(&interest->list);
- write_unlock_bh(&nf_lock);
-
- /* Blow away any queued skbs; this is overzealous. */
- while ((skb = skb_dequeue(&interest->wake->skbq)) != NULL)
- nf_reinject(skb, 0, NF_DROP);
-}
-
-void nf_getinfo(const struct sk_buff *skb,
- struct net_device **indev,
- struct net_device **outdev,
- unsigned long *mark)
-{
- const struct nf_info *info = (const struct nf_info *)skb->nfmark;
-
- *indev = info->indev;
- *outdev = info->outdev;
- *mark = info->mark;
-}
-
-void nf_reinject(struct sk_buff *skb, unsigned long mark, unsigned int verdict)
-{
- struct nf_info *info = (struct nf_info *)skb->nfmark;
struct list_head *elem = &info->elem->list;
struct list_head *i;
- read_lock_bh(&nf_lock);
-
+ /* We don't have BR_NETPROTO_LOCK here */
+ br_read_lock_bh(BR_NETPROTO_LOCK);
for (i = nf_hooks[info->pf][info->hook].next; i != elem; i = i->next) {
if (i == &nf_hooks[info->pf][info->hook]) {
/* The module which sent it to userspace is gone. */
+ NFDEBUG("%s: module disappeared, dropping packet.\n",
+ __FUNCTION__);
verdict = NF_DROP;
break;
}
}
- /* Continue traversal iff userspace said ok, and devices still
- exist... */
+ /* Continue traversal iff userspace said ok... */
if (verdict == NF_ACCEPT) {
- skb->nfmark = mark;
verdict = nf_iterate(&nf_hooks[info->pf][info->hook],
&skb, info->hook,
info->indev, info->outdev, &elem,
info->okfn);
}
- if (verdict == NF_QUEUE) {
- nf_queue(skb, elem, info->pf, info->hook,
- info->indev, info->outdev, info->okfn);
- }
- read_unlock_bh(&nf_lock);
-
switch (verdict) {
case NF_ACCEPT:
- local_bh_disable();
info->okfn(skb);
- local_bh_enable();
break;
+ case NF_QUEUE:
+ nf_queue(skb, elem, info->pf, info->hook,
+ info->indev, info->outdev, info->okfn);
+
case NF_DROP:
kfree_skb(skb);
break;
@@ -579,51 +497,17 @@ void nf_reinject(struct sk_buff *skb, unsigned long mark, unsigned int verdict)
/* Release those devices we held, or Alexey will kill me. */
if (info->indev) dev_put(info->indev);
if (info->outdev) dev_put(info->outdev);
-
+
kfree_s(info, sizeof(*info));
return;
}
-/* FIXME: Before cache is ever used, this must be implemented for real. */
-void nf_invalidate_cache(int pf)
-{
-}
-
-#ifdef CONFIG_NETFILTER_DEBUG
-
-void debug_print_hooks_ip(unsigned int nf_debug)
-{
- if (nf_debug & (1 << NF_IP_PRE_ROUTING)) {
- printk("PRE_ROUTING ");
- nf_debug ^= (1 << NF_IP_PRE_ROUTING);
- }
- if (nf_debug & (1 << NF_IP_LOCAL_IN)) {
- printk("LOCAL_IN ");
- nf_debug ^= (1 << NF_IP_LOCAL_IN);
- }
- if (nf_debug & (1 << NF_IP_FORWARD)) {
- printk("FORWARD ");
- nf_debug ^= (1 << NF_IP_FORWARD);
- }
- if (nf_debug & (1 << NF_IP_LOCAL_OUT)) {
- printk("LOCAL_OUT ");
- nf_debug ^= (1 << NF_IP_LOCAL_OUT);
- }
- if (nf_debug & (1 << NF_IP_POST_ROUTING)) {
- printk("POST_ROUTING ");
- nf_debug ^= (1 << NF_IP_POST_ROUTING);
- }
- if (nf_debug)
- printk("Crap bits: 0x%04X", nf_debug);
- printk("\n");
-}
-#endif /* CONFIG_NETFILTER_DEBUG */
-
void __init netfilter_init(void)
{
int i, h;
- for (i = 0; i < NPROTO; i++)
+ for (i = 0; i < NPROTO; i++) {
for (h = 0; h < NF_MAX_HOOKS; h++)
INIT_LIST_HEAD(&nf_hooks[i][h]);
+ }
}
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index c549162a9..8749dfb0d 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -171,7 +171,7 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
r->ifi_flags = dev->flags;
r->ifi_change = change;
- if (! netif_running(dev))
+ if (!netif_running(dev) || !netif_carrier_ok(dev))
r->ifi_flags &= ~IFF_RUNNING;
else
r->ifi_flags |= IFF_RUNNING;
diff --git a/net/core/sock.c b/net/core/sock.c
index c5781c6e3..21f15b5e7 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -7,7 +7,7 @@
* handler for protocols to use and generic option handler.
*
*
- * Version: $Id: sock.c,v 1.89 2000/01/18 08:24:13 davem Exp $
+ * Version: $Id: sock.c,v 1.90 2000/02/27 19:48:11 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -526,7 +526,20 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
if(copy_to_user((void*)optval, &sk->peercred, len))
return -EFAULT;
goto lenout;
-
+
+ case SO_PEERNAME:
+ {
+ char address[128];
+
+ if (sock->ops->getname(sock, (struct sockaddr *)address, &lv, 2))
+ return -ENOTCONN;
+ if (lv < len)
+ return -EINVAL;
+ if(copy_to_user((void*)optval, address, len))
+ return -EFAULT;
+ goto lenout;
+ }
+
default:
return(-ENOPROTOOPT);
}
diff --git a/net/decnet/TODO b/net/decnet/TODO
index c5e7f5cd7..0f5c3a649 100644
--- a/net/decnet/TODO
+++ b/net/decnet/TODO
@@ -16,10 +16,6 @@ Steve's quick list of things that need finishing off:
o sendmsg() in the raw socket layer (yes, its for sending routing messages)
- o Better filtering of traffic in raw sockets. Aside from receiving routing
- messages, there really doesn't seem to be a lot else that raw sockets
- could be useful for... suggestions on a postcard please :-)
-
o Fix /proc for raw sockets
o Lots of testing with real applications
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 04728d5d8..7860597ab 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -106,6 +106,7 @@ Version 0.0.6 2.1.110 07-aug-98 Eduardo Marcelo Serrat
#include <linux/netdevice.h>
#include <linux/inet.h>
#include <linux/route.h>
+#include <linux/netfilter.h>
#include <net/sock.h>
#include <asm/segment.h>
#include <asm/system.h>
@@ -1005,6 +1006,12 @@ static int dn_accept(struct socket *sock, struct socket *newsock, int flags)
memcpy(&newsk->protinfo.dn.addr, &sk->protinfo.dn.addr, sizeof(struct sockaddr_dn));
+ /*
+ * If we are listening on a wild socket, we don't want
+ * the newly created socket on the wrong hash queue.
+ */
+ newsk->protinfo.dn.addr.sdn_flags &= ~SDF_WILD;
+
skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &newsk->protinfo.dn.addr, &type));
skb_pull(skb, dn_username2sockaddr(skb->data, skb->len, &newsk->protinfo.dn.peer, &type));
*(dn_address *)newsk->protinfo.dn.peer.sdn_add.a_addr = cb->src;
@@ -1300,9 +1307,6 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char *opt
struct dn_scp *scp = &sk->protinfo.dn;
struct optdata_dn opt;
struct accessdata_dn acc;
-#ifdef CONFIG_DECNET_FW
- char tmp_fw[MAX(sizeof(struct dn_fwtest),sizeof(struct dn_fwnew))];
-#endif
int err;
if (optlen && !optval)
@@ -1404,34 +1408,15 @@ static int __dn_setsockopt(struct socket *sock, int level,int optname, char *opt
dn_nsp_send_disc(sk, 0x38, 0, GFP_KERNEL);
break;
-#ifdef CONFIG_DECNET_FW
- case DN_FW_APPEND:
- case DN_FW_REPLACE:
- case DN_FW_DELETE:
- case DN_FW_DELETE_NUM:
- case DN_FW_INSERT:
- case DN_FW_FLUSH:
- case DN_FW_ZERO:
- case DN_FW_CHECK:
- case DN_FW_CREATECHAIN:
- case DN_FW_DELETECHAIN:
- case DN_FW_POLICY:
-
- if (!capable(CAP_NET_ADMIN))
- return -EACCES;
- if ((optlen > sizeof(tmp_fw)) || (optlen < 1))
- return -EINVAL;
- if (copy_from_user(&tmp_fw, optval, optlen))
- return -EFAULT;
- err = dn_fw_ctl(optname, &tmp_fw, optlen);
- return err;
-#endif
default:
+#ifdef CONFIG_NETFILTER
+ return nf_setsockopt(sk, PF_DECnet, optname, optval, optlen);
+#endif
case DSO_LINKINFO:
case DSO_STREAM:
case DSO_SEQPACKET:
- return -EOPNOTSUPP;
+ return -ENOPROTOOPT;
}
return 0;
@@ -1511,12 +1496,22 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char *opt
return -EFAULT;
break;
+ default:
+#ifdef CONFIG_NETFILTER
+ {
+ int val, len = *optlen;
+ val = nf_getsockopt(sk, PF_DECnet, optname,
+ optval, &len);
+ if (val >= 0)
+ val = put_user(len, optlen);
+ return val;
+ }
+#endif
case DSO_STREAM:
case DSO_SEQPACKET:
case DSO_CONACCEPT:
case DSO_CONREJECT:
- default:
- return -EOPNOTSUPP;
+ return -ENOPROTOOPT;
}
return 0;
@@ -1975,7 +1970,7 @@ static struct packet_type dn_dix_packet_type =
__constant_htons(ETH_P_DNA_RT),
NULL, /* All devices */
dn_route_rcv,
- NULL,
+ (void*)1,
NULL,
};
diff --git a/net/decnet/dn_neigh.c b/net/decnet/dn_neigh.c
index eb50c8c54..b2c6b2051 100644
--- a/net/decnet/dn_neigh.c
+++ b/net/decnet/dn_neigh.c
@@ -432,7 +432,7 @@ void dn_neigh_pointopoint_hello(struct sk_buff *skb)
/*
* Ethernet router hello message received
*/
-void dn_neigh_router_hello(struct sk_buff *skb)
+int dn_neigh_router_hello(struct sk_buff *skb)
{
struct rtnode_hello_message *msg = (struct rtnode_hello_message *)skb->data;
@@ -485,12 +485,13 @@ void dn_neigh_router_hello(struct sk_buff *skb)
}
kfree_skb(skb);
+ return 0;
}
/*
* Endnode hello message received
*/
-void dn_neigh_endnode_hello(struct sk_buff *skb)
+int dn_neigh_endnode_hello(struct sk_buff *skb)
{
struct endnode_hello_message *msg = (struct endnode_hello_message *)skb->data;
struct neighbour *neigh;
@@ -523,6 +524,7 @@ void dn_neigh_endnode_hello(struct sk_buff *skb)
}
kfree_skb(skb);
+ return 0;
}
diff --git a/net/decnet/dn_nsp_in.c b/net/decnet/dn_nsp_in.c
index 9cb0c6394..66c72b4bd 100644
--- a/net/decnet/dn_nsp_in.c
+++ b/net/decnet/dn_nsp_in.c
@@ -320,7 +320,7 @@ static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb)
struct dn_scp *scp = &sk->protinfo.dn;
unsigned short reason;
- if (skb->len != 2)
+ if (skb->len < 2)
goto out;
reason = dn_ntohs(*(__u16 *)skb->data);
diff --git a/net/decnet/dn_nsp_out.c b/net/decnet/dn_nsp_out.c
index 3b487617d..e4d0adad3 100644
--- a/net/decnet/dn_nsp_out.c
+++ b/net/decnet/dn_nsp_out.c
@@ -19,6 +19,7 @@
* Moved output state machine into one function
* Steve Whitehouse: New output state machine
* Paul Koning: Connect Confirm message fix.
+ * Eduardo Serrat: Fix to stop dn_nsp_do_disc() sending malformed packets.
*/
/******************************************************************************
@@ -510,7 +511,7 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
int ddl, unsigned char *dd, __u16 rem, __u16 loc)
{
struct sk_buff *skb = NULL;
- int size = 7 + (ddl ? (ddl + 1) : 0);
+ int size = 8 + ddl;
unsigned char *msg;
if ((dst == NULL) || (rem == 0)) {
@@ -530,9 +531,9 @@ static __inline__ void dn_nsp_do_disc(struct sock *sk, unsigned char msgflg,
msg += 2;
*(__u16 *)msg = dn_htons(reason);
msg += 2;
+ *msg++ = ddl;
if (ddl) {
- *msg++ = ddl;
memcpy(msg, dd, ddl);
}
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index cc2ffeeef..27ff3a10f 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -30,6 +30,9 @@
* my copying the IPv4 routing code. The
* hooks here are modified and will continue
* to evolve for a while.
+ * Steve Whitehouse : Real SMP at last :-) Also new netfilter
+ * stuff. Look out raw sockets your days
+ * are numbered!
*/
/******************************************************************************
@@ -359,9 +362,22 @@ drop_it:
return 0;
}
+static int dn_route_discard(struct sk_buff *skb)
+{
+ kfree_skb(skb);
+ return 0;
+}
+
+static int dn_route_ptp_hello(struct sk_buff *skb)
+{
+ dn_dev_hello(skb);
+ dn_neigh_pointopoint_hello(skb);
+ return 0;
+}
+
int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
- struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;
+ struct dn_skb_cb *cb;
unsigned char flags = 0;
int padlen = 0;
__u16 len = dn_ntohs(*(__u16 *)skb->data);
@@ -370,8 +386,8 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
if (dn == NULL)
goto dump_it;
- cb->stamp = jiffies;
- cb->iif = dev->ifindex;
+ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
+ goto out;
skb_pull(skb, 2);
@@ -382,6 +398,10 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
flags = *skb->data;
+ cb = (struct dn_skb_cb *)skb->cb;
+ cb->stamp = jiffies;
+ cb->iif = dev->ifindex;
+
/*
* If we have padding, remove it.
*/
@@ -426,24 +446,20 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
switch(flags & DN_RT_CNTL_MSK) {
case DN_RT_PKT_HELO:
- dn_dev_hello(skb);
- dn_neigh_pointopoint_hello(skb);
- return 0;
+ NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_route_ptp_hello);
+ goto out;
case DN_RT_PKT_L1RT:
case DN_RT_PKT_L2RT:
-#ifdef CONFIG_DECNET_ROUTER
- return dn_fib_rt_message(skb);
-#else
- break;
-#endif /* CONFIG_DECNET_ROUTER */
+ NF_HOOK(PF_DECnet, NF_DN_ROUTE, skb, skb->dev, NULL, dn_route_discard);
+ goto out;
case DN_RT_PKT_ERTH:
- dn_neigh_router_hello(skb);
- return 0;
+ NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_neigh_router_hello);
+ goto out;
case DN_RT_PKT_EEDH:
- dn_neigh_endnode_hello(skb);
- return 0;
+ NF_HOOK(PF_DECnet, NF_DN_HELLO, skb, skb->dev, NULL, dn_neigh_endnode_hello);
+ goto out;
}
} else {
if (dn->parms.state != DN_DEV_S_RU)
@@ -461,6 +477,7 @@ int dn_route_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type
dump_it:
kfree_skb(skb);
+out:
return 0;
}
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
index c01d447b1..d7da63f4e 100644
--- a/net/ipv4/icmp.c
+++ b/net/ipv4/icmp.c
@@ -3,7 +3,7 @@
*
* Alan Cox, <alan@redhat.com>
*
- * Version: $Id: icmp.c,v 1.64 2000/02/09 11:16:40 davem Exp $
+ * Version: $Id: icmp.c,v 1.65 2000/02/22 23:54:25 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -801,9 +801,10 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len)
/*
* This can't change while we are doing it.
+ * Callers have obtained BR_NETPROTO_LOCK so
+ * we are OK.
*/
- read_lock(&inet_protocol_lock);
ipprot = (struct inet_protocol *) inet_protos[hash];
while(ipprot != NULL) {
struct inet_protocol *nextip;
@@ -822,7 +823,6 @@ static void icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb, int len)
ipprot = nextip;
}
- read_unlock(&inet_protocol_lock);
}
diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c
index 23389d249..0c755dbcd 100644
--- a/net/ipv4/ip_input.c
+++ b/net/ipv4/ip_input.c
@@ -5,7 +5,7 @@
*
* The Internet Protocol (IP) module.
*
- * Version: $Id: ip_input.c,v 1.45 2000/01/16 05:11:22 davem Exp $
+ * Version: $Id: ip_input.c,v 1.46 2000/02/22 23:54:26 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -241,7 +241,6 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
if(raw_sk != NULL)
raw_sk = raw_v4_input(skb, iph, hash);
- read_lock(&inet_protocol_lock);
ipprot = (struct inet_protocol *) inet_protos[hash];
flag = 0;
if(ipprot != NULL) {
@@ -254,13 +253,11 @@ static inline int ip_local_deliver_finish(struct sk_buff *skb)
ret = ipprot->handler(skb, (ntohs(iph->tot_len) -
(iph->ihl * 4)));
- read_unlock(&inet_protocol_lock);
return ret;
} else {
flag = ip_run_ipprot(skb, iph, ipprot, (raw_sk != NULL));
}
}
- read_unlock(&inet_protocol_lock);
/* All protocols checked.
* If this packet was a broadcast, we may *not* reply to it, since that
diff --git a/net/ipv4/protocol.c b/net/ipv4/protocol.c
index 2b61e6466..4839764e8 100644
--- a/net/ipv4/protocol.c
+++ b/net/ipv4/protocol.c
@@ -5,7 +5,7 @@
*
* INET protocol dispatch tables.
*
- * Version: $Id: protocol.c,v 1.10 1999/08/20 11:05:55 davem Exp $
+ * Version: $Id: protocol.c,v 1.11 2000/02/22 23:54:26 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -35,6 +35,7 @@
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/timer.h>
+#include <linux/brlock.h>
#include <net/ip.h>
#include <net/protocol.h>
#include <net/tcp.h>
@@ -116,8 +117,6 @@ struct inet_protocol *inet_protos[MAX_INET_PROTOS] =
NULL
};
-rwlock_t inet_protocol_lock = RW_LOCK_UNLOCKED;
-
/*
* Add a protocol handler to the hash tables
*/
@@ -128,7 +127,7 @@ void inet_add_protocol(struct inet_protocol *prot)
struct inet_protocol *p2;
hash = prot->protocol & (MAX_INET_PROTOS - 1);
- write_lock_bh(&inet_protocol_lock);
+ br_write_lock_bh(BR_NETPROTO_LOCK);
prot ->next = inet_protos[hash];
inet_protos[hash] = prot;
prot->copy = 0;
@@ -147,7 +146,7 @@ void inet_add_protocol(struct inet_protocol *prot)
}
p2 = (struct inet_protocol *) p2->next;
}
- write_unlock_bh(&inet_protocol_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
}
/*
@@ -161,11 +160,11 @@ int inet_del_protocol(struct inet_protocol *prot)
unsigned char hash;
hash = prot->protocol & (MAX_INET_PROTOS - 1);
- write_lock_bh(&inet_protocol_lock);
+ br_write_lock_bh(BR_NETPROTO_LOCK);
if (prot == inet_protos[hash])
{
inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next;
- write_unlock_bh(&inet_protocol_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
return(0);
}
@@ -186,7 +185,7 @@ int inet_del_protocol(struct inet_protocol *prot)
if (p->copy == 0 && lp != NULL)
lp->copy = 0;
p->next = prot->next;
- write_unlock_bh(&inet_protocol_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
return(0);
}
if (p->next != NULL && p->next->protocol == prot->protocol)
@@ -194,6 +193,6 @@ int inet_del_protocol(struct inet_protocol *prot)
p = (struct inet_protocol *) p->next;
}
- write_unlock_bh(&inet_protocol_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
return(-1);
}
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 88483d516..d431c682c 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5,7 +5,7 @@
*
* Implementation of the Transmission Control Protocol(TCP).
*
- * Version: $Id: tcp_input.c,v 1.188 2000/02/08 21:27:14 davem Exp $
+ * Version: $Id: tcp_input.c,v 1.189 2000/02/27 19:52:55 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -534,6 +534,9 @@ static void tcp_reset(struct sock *sk)
sk->err = ECONNRESET;
}
+ if (!sk->dead)
+ sk->error_report(sk);
+
tcp_done(sk);
}
@@ -1660,7 +1663,12 @@ static void tcp_fin(struct sk_buff *skb, struct sock *sk, struct tcphdr *th)
if (!sk->dead) {
sk->state_change(sk);
- sock_wake_async(sk->socket, 1, POLL_HUP);
+
+ /* Do not send POLL_HUP for half duplex close. */
+ if (sk->shutdown == SHUTDOWN_MASK || sk->state == TCP_CLOSE)
+ sock_wake_async(sk->socket, 1, POLL_HUP);
+ else
+ sock_wake_async(sk->socket, 1, POLL_IN);
}
}
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index c052d2eb8..e188b4997 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -5,7 +5,7 @@
*
* The User Datagram Protocol (UDP).
*
- * Version: $Id: udp.c,v 1.79 2000/01/18 08:24:20 davem Exp $
+ * Version: $Id: udp.c,v 1.80 2000/02/27 19:51:43 davem Exp $
*
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -798,6 +798,7 @@ int udp_disconnect(struct sock *sk, int flags)
sk->rcv_saddr = 0;
sk->daddr = 0;
sk->dport = 0;
+ sk->bound_dev_if = 0;
sk_dst_reset(sk);
return 0;
}
diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c
index 09b9c1a11..919abf4f9 100644
--- a/net/ipv6/af_inet6.c
+++ b/net/ipv6/af_inet6.c
@@ -7,7 +7,10 @@
*
* Adapted from linux/net/ipv4/af_inet.c
*
- * $Id: af_inet6.c,v 1.54 2000/02/12 23:34:45 davem Exp $
+ * $Id: af_inet6.c,v 1.55 2000/02/27 19:51:47 davem Exp $
+ *
+ * Fixes:
+ * Hideaki YOSHIFUJI : sin6_scope_id support
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -220,9 +223,8 @@ static int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
if(sk->prot->bind)
return sk->prot->bind(sk, uaddr, addr_len);
- if (addr_len < sizeof(struct sockaddr_in6))
+ if (addr_len < SIN6_LEN_RFC2133)
return -EINVAL;
-
addr_type = ipv6_addr_type(&addr->sin6_addr);
if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM)
return -EINVAL;
@@ -258,6 +260,22 @@ static int inet6_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
return -EINVAL;
}
+ if (addr_type & IPV6_ADDR_LINKLOCAL) {
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ addr->sin6_scope_id) {
+ /* Override any existing binding, if another one
+ * is supplied by user.
+ */
+ sk->bound_dev_if = addr->sin6_scope_id;
+ }
+
+ /* Binding to link-local address requires an interface */
+ if (sk->bound_dev_if == 0) {
+ release_sock(sk);
+ return -EINVAL;
+ }
+ }
+
sk->rcv_saddr = v4addr;
sk->saddr = v4addr;
@@ -338,6 +356,7 @@ static int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
sin->sin6_family = AF_INET6;
sin->sin6_flowinfo = 0;
+ sin->sin6_scope_id = 0;
if (peer) {
if (!sk->dport)
return -ENOTCONN;
@@ -360,7 +379,9 @@ static int inet6_getname(struct socket *sock, struct sockaddr *uaddr,
sin->sin6_port = sk->sport;
}
- *uaddr_len = sizeof(*sin);
+ if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL)
+ sin->sin6_scope_id = sk->bound_dev_if;
+ *uaddr_len = sizeof(*sin);
return(0);
}
diff --git a/net/ipv6/datagram.c b/net/ipv6/datagram.c
index c561d318d..844ea8228 100644
--- a/net/ipv6/datagram.c
+++ b/net/ipv6/datagram.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: datagram.c,v 1.18 1999/08/20 11:06:17 davem Exp $
+ * $Id: datagram.c,v 1.19 2000/02/27 19:51:47 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -134,14 +134,20 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
sin->sin6_family = AF_INET6;
sin->sin6_flowinfo = 0;
sin->sin6_port = serr->port;
+ sin->sin6_scope_id = 0;
if (serr->ee.ee_origin == SO_EE_ORIGIN_ICMP6) {
memcpy(&sin->sin6_addr, skb->nh.raw + serr->addr_offset, 16);
if (sk->net_pinfo.af_inet6.sndflow)
sin->sin6_flowinfo = *(u32*)(skb->nh.raw + serr->addr_offset - 24) & IPV6_FLOWINFO_MASK;
- } else
+ if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
+ struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
+ sin->sin6_scope_id = opt->iif;
+ }
+ } else {
ipv6_addr_set(&sin->sin6_addr, 0, 0,
__constant_htonl(0xffff),
*(u32*)(skb->nh.raw + serr->addr_offset));
+ }
}
memcpy(&errhdr.ee, &serr->ee, sizeof(struct sock_extended_err));
@@ -154,6 +160,10 @@ int ipv6_recv_error(struct sock *sk, struct msghdr *msg, int len)
memcpy(&sin->sin6_addr, &skb->nh.ipv6h->saddr, 16);
if (sk->net_pinfo.af_inet6.rxopt.all)
datagram_recv_ctl(sk, msg, skb);
+ if (ipv6_addr_type(&sin->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
+ struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
+ sin->sin6_scope_id = opt->iif;
+ }
} else {
ipv6_addr_set(&sin->sin6_addr, 0, 0,
__constant_htonl(0xffff),
diff --git a/net/ipv6/icmp.c b/net/ipv6/icmp.c
index f1c211532..ffb0787e8 100644
--- a/net/ipv6/icmp.c
+++ b/net/ipv6/icmp.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: icmp.c,v 1.26 2000/01/19 04:06:19 davem Exp $
+ * $Id: icmp.c,v 1.27 2000/02/22 23:54:28 davem Exp $
*
* Based on net/ipv4/icmp.c
*
@@ -477,7 +477,6 @@ static void icmpv6_notify(struct sk_buff *skb,
hash = nexthdr & (MAX_INET_PROTOS - 1);
- read_lock(&inet6_protocol_lock);
for (ipprot = (struct inet6_protocol *) inet6_protos[hash];
ipprot != NULL;
ipprot=(struct inet6_protocol *)ipprot->next) {
@@ -487,7 +486,6 @@ static void icmpv6_notify(struct sk_buff *skb,
if (ipprot->err_handler)
ipprot->err_handler(skb, hdr, NULL, type, code, pb, info);
}
- read_unlock(&inet6_protocol_lock);
read_lock(&raw_v6_lock);
if ((sk = raw_v6_htable[hash]) != NULL) {
diff --git a/net/ipv6/ip6_input.c b/net/ipv6/ip6_input.c
index 709443749..6c6ae227f 100644
--- a/net/ipv6/ip6_input.c
+++ b/net/ipv6/ip6_input.c
@@ -6,7 +6,7 @@
* Pedro Roque <roque@di.fc.ul.pt>
* Ian P. Morris <I.P.Morris@soton.ac.uk>
*
- * $Id: ip6_input.c,v 1.15 2000/01/09 02:19:54 davem Exp $
+ * $Id: ip6_input.c,v 1.17 2000/02/27 19:42:53 davem Exp $
*
* Based in linux/net/ipv4/ip_input.c
*
@@ -26,6 +26,9 @@
#include <linux/in6.h>
#include <linux/icmpv6.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+
#include <net/sock.h>
#include <net/snmp.h>
@@ -38,6 +41,16 @@
#include <net/addrconf.h>
+
+static inline int ip6_rcv_finish( struct sk_buff *skb)
+{
+
+ if (skb->dst == NULL)
+ ip6_route_input(skb);
+
+ return skb->dst->input(skb);
+}
+
int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
{
struct ipv6hdr *hdr;
@@ -77,12 +90,7 @@ int ipv6_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt
return 0;
}
}
-
- if (skb->dst == NULL)
- ip6_route_input(skb);
-
- return skb->dst->input(skb);
-
+ return NF_HOOK(PF_INET6,NF_IP6_PRE_ROUTING, skb, dev, NULL, ip6_rcv_finish);
truncated:
IP6_INC_STATS_BH(Ip6InTruncatedPkts);
err:
@@ -97,7 +105,8 @@ out:
* Deliver the packet to the host
*/
-int ip6_input(struct sk_buff *skb)
+
+static inline int ip6_input_finish(struct sk_buff *skb)
{
struct ipv6hdr *hdr = skb->nh.ipv6h;
struct inet6_protocol *ipprot;
@@ -147,7 +156,6 @@ int ip6_input(struct sk_buff *skb)
raw_sk = ipv6_raw_deliver(skb, nexthdr, len);
hash = nexthdr & (MAX_INET_PROTOS - 1);
- read_lock(&inet6_protocol_lock);
for (ipprot = (struct inet6_protocol *) inet6_protos[hash];
ipprot != NULL;
ipprot = (struct inet6_protocol *) ipprot->next) {
@@ -163,7 +171,6 @@ int ip6_input(struct sk_buff *skb)
ipprot->handler(buff, len);
found = 1;
}
- read_unlock(&inet6_protocol_lock);
if (raw_sk) {
rawv6_rcv(raw_sk, skb, len);
@@ -182,6 +189,12 @@ int ip6_input(struct sk_buff *skb)
return 0;
}
+
+int ip6_input(struct sk_buff *skb)
+{
+ return NF_HOOK(PF_INET6,NF_IP6_LOCAL_IN, skb, skb->dev, NULL, ip6_input_finish);
+}
+
int ip6_mc_input(struct sk_buff *skb)
{
struct ipv6hdr *hdr;
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index d902692bd..4d124d558 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_output.c,v 1.24 2000/01/09 02:19:49 davem Exp $
+ * $Id: ip6_output.c,v 1.26 2000/03/01 02:58:12 davem Exp $
*
* Based on linux/net/ipv4/ip_output.c
*
@@ -24,6 +24,7 @@
* H. von Brand : Added missing #include <linux/string.h>
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/string.h>
@@ -34,6 +35,9 @@
#include <linux/in6.h>
#include <linux/route.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv6.h>
+
#include <net/sock.h>
#include <net/snmp.h>
@@ -57,11 +61,44 @@ static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *f
spin_unlock_bh(&ip6_id_lock);
}
+static inline int ip6_output_finish(struct sk_buff *skb)
+{
+
+ struct dst_entry *dst = skb->dst;
+ struct hh_cache *hh = dst->hh;
+
+ if (hh) {
+ read_lock_bh(&hh->hh_lock);
+ memcpy(skb->data - 16, hh->hh_data, 16);
+ read_unlock_bh(&hh->hh_lock);
+ skb_push(skb, hh->hh_len);
+ return hh->hh_output(skb);
+ } else if (dst->neighbour)
+ return dst->neighbour->output(skb);
+
+ kfree_skb(skb);
+ return -EINVAL;
+
+}
+
+/* dev_loopback_xmit for use with netfilter. */
+static int ip6_dev_loopback_xmit(struct sk_buff *newskb)
+{
+ newskb->mac.raw = newskb->data;
+ skb_pull(newskb, newskb->nh.raw - newskb->data);
+ newskb->pkt_type = PACKET_LOOPBACK;
+ newskb->ip_summed = CHECKSUM_UNNECESSARY;
+ BUG_TRAP(newskb->dst);
+
+ netif_rx(newskb);
+ return 0;
+}
+
+
int ip6_output(struct sk_buff *skb)
{
struct dst_entry *dst = skb->dst;
struct net_device *dev = dst->dev;
- struct hh_cache *hh = dst->hh;
skb->protocol = __constant_htons(ETH_P_IPV6);
skb->dev = dev;
@@ -70,10 +107,15 @@ int ip6_output(struct sk_buff *skb)
if (!(dev->flags&IFF_LOOPBACK) &&
(skb->sk == NULL || skb->sk->net_pinfo.af_inet6.mc_loop) &&
ipv6_chk_mcast_addr(dev, &skb->nh.ipv6h->daddr)) {
+ struct sk_buff *newskb = skb_clone(skb, GFP_ATOMIC);
+
/* Do not check for IFF_ALLMULTI; multicast routing
is not supported in any case.
*/
- dev_loopback_xmit(skb);
+ if (newskb)
+ NF_HOOK(PF_INET, NF_IP6_POST_ROUTING, newskb, NULL,
+ newskb->dev,
+ ip6_dev_loopback_xmit);
if (skb->nh.ipv6h->hop_limit == 0) {
kfree_skb(skb);
@@ -84,17 +126,51 @@ int ip6_output(struct sk_buff *skb)
IP6_INC_STATS(Ip6OutMcastPkts);
}
- if (hh) {
- read_lock_bh(&hh->hh_lock);
- memcpy(skb->data - 16, hh->hh_data, 16);
- read_unlock_bh(&hh->hh_lock);
- skb_push(skb, hh->hh_len);
- return hh->hh_output(skb);
- } else if (dst->neighbour)
- return dst->neighbour->output(skb);
+ return NF_HOOK(PF_INET6, NF_IP6_POST_ROUTING, skb,NULL, skb->dev,ip6_output_finish);
+}
- kfree_skb(skb);
- return -EINVAL;
+
+#ifdef CONFIG_NETFILTER
+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) {
+ printk(KERN_DEBUG "route6_me_harder: No more route.\n");
+ return -EINVAL;
+ }
+
+ /* Drop old route. */
+ dst_release(skb->dst);
+
+ skb->dst = dst;
+ return 0;
+}
+#endif
+
+static inline int ip6_maybe_reroute(struct sk_buff *skb)
+{
+#ifdef CONFIG_NETFILTER
+ if (skb->nfcache & NFC_ALTERED){
+ if (route6_me_harder(skb) != 0){
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+ }
+#endif /* CONFIG_NETFILTER */
+ return skb->dst->output(skb);
}
/*
@@ -159,7 +235,7 @@ int ip6_xmit(struct sock *sk, struct sk_buff *skb, struct flowi *fl,
if (skb->len <= dst->pmtu) {
IP6_INC_STATS(Ip6OutRequests);
- return dst->output(skb);
+ return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
}
printk(KERN_DEBUG "IPv6: sending pkt_too_big to self\n");
@@ -388,7 +464,7 @@ static int ip6_frag_xmit(struct sock *sk, inet_getfrag_t getfrag,
IP6_INC_STATS(Ip6FragCreates);
IP6_INC_STATS(Ip6OutRequests);
- err = dst->output(skb);
+ err = NF_HOOK(PF_INET6,NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
if (err) {
kfree_skb(last_skb);
return err;
@@ -414,7 +490,7 @@ static int ip6_frag_xmit(struct sock *sk, inet_getfrag_t getfrag,
IP6_INC_STATS(Ip6FragCreates);
IP6_INC_STATS(Ip6FragOKs);
IP6_INC_STATS(Ip6OutRequests);
- return dst->output(last_skb);
+ return NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, last_skb, NULL,dst->dev, ip6_maybe_reroute);
}
int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
@@ -582,7 +658,7 @@ int ip6_build_xmit(struct sock *sk, inet_getfrag_t getfrag, const void *data,
if (!err) {
IP6_INC_STATS(Ip6OutRequests);
- err = dst->output(skb);
+ err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, ip6_maybe_reroute);
} else {
err = -EFAULT;
kfree_skb(skb);
@@ -636,6 +712,11 @@ int ip6_call_ra_chain(struct sk_buff *skb, int sel)
return 0;
}
+static inline int ip6_forward_finish(struct sk_buff *skb)
+{
+ return skb->dst->output(skb);
+}
+
int ip6_forward(struct sk_buff *skb)
{
struct dst_entry *dst = skb->dst;
@@ -726,7 +807,7 @@ int ip6_forward(struct sk_buff *skb)
hdr->hop_limit--;
IP6_INC_STATS_BH(Ip6OutForwDatagrams);
- return dst->output(skb);
+ return NF_HOOK(PF_INET6,NF_IP6_FORWARD, skb, skb->dev, dst->dev, ip6_forward_finish);
drop:
IP6_INC_STATS_BH(Ip6InAddrErrors);
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index 9f13435fa..87c9f1eb4 100644
--- a/net/ipv6/ipv6_sockglue.c
+++ b/net/ipv6/ipv6_sockglue.c
@@ -7,7 +7,7 @@
*
* Based on linux/net/ipv4/ip_sockglue.c
*
- * $Id: ipv6_sockglue.c,v 1.32 2000/01/31 01:21:25 davem Exp $
+ * $Id: ipv6_sockglue.c,v 1.33 2000/02/27 19:42:54 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -35,6 +35,7 @@
#include <linux/if_arp.h>
#include <linux/init.h>
#include <linux/sysctl.h>
+#include <linux/netfilter.h>
#include <net/sock.h>
#include <net/snmp.h>
@@ -371,6 +372,14 @@ done:
case IPV6_FLOWLABEL_MGR:
retv = ipv6_flowlabel_opt(sk, optval, optlen);
break;
+
+#ifdef CONFIG_NETFILTER
+ default:
+ retv = nf_setsockopt(sk, PF_INET6, optname, optval,
+ optlen);
+ break;
+#endif
+
}
release_sock(sk);
@@ -450,7 +459,17 @@ int ipv6_getsockopt(struct sock *sk, int level, int optname, char *optval,
break;
}
default:
+#ifdef CONFIG_NETFILTER
+ lock_sock(sk);
+ val = nf_getsockopt(sk, PF_INET6, optname, optval,
+ &len);
+ release_sock(sk);
+ if (val >= 0)
+ val = put_user(len, optlen);
+ return val;
+#else
return -EINVAL;
+#endif
}
len=min(sizeof(int),len);
if(put_user(len, optlen))
diff --git a/net/ipv6/protocol.c b/net/ipv6/protocol.c
index c30e751ed..accc87cbe 100644
--- a/net/ipv6/protocol.c
+++ b/net/ipv6/protocol.c
@@ -5,7 +5,7 @@
*
* PF_INET6 protocol dispatch tables.
*
- * Version: $Id: protocol.c,v 1.7 1999/08/20 11:06:26 davem Exp $
+ * Version: $Id: protocol.c,v 1.8 2000/02/22 23:54:29 davem Exp $
*
* Authors: Pedro Roque <roque@di.fc.ul.pt>
*
@@ -24,6 +24,7 @@
#include <linux/in6.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
+#include <linux/brlock.h>
#include <net/sock.h>
#include <net/snmp.h>
@@ -37,15 +38,13 @@ struct inet6_protocol *inet6_protos[MAX_INET_PROTOS] =
NULL
};
-rwlock_t inet6_protocol_lock = RW_LOCK_UNLOCKED;
-
void inet6_add_protocol(struct inet6_protocol *prot)
{
unsigned char hash;
struct inet6_protocol *p2;
hash = prot->protocol & (MAX_INET_PROTOS - 1);
- write_lock_bh(&inet6_protocol_lock);
+ br_write_lock_bh(BR_NETPROTO_LOCK);
prot->next = inet6_protos[hash];
inet6_protos[hash] = prot;
prot->copy = 0;
@@ -62,7 +61,7 @@ void inet6_add_protocol(struct inet6_protocol *prot)
}
p2 = (struct inet6_protocol *) p2->next;
}
- write_unlock_bh(&inet6_protocol_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
}
/*
@@ -76,10 +75,10 @@ int inet6_del_protocol(struct inet6_protocol *prot)
unsigned char hash;
hash = prot->protocol & (MAX_INET_PROTOS - 1);
- write_lock_bh(&inet6_protocol_lock);
+ br_write_lock_bh(BR_NETPROTO_LOCK);
if (prot == inet6_protos[hash]) {
inet6_protos[hash] = (struct inet6_protocol *) inet6_protos[hash]->next;
- write_unlock_bh(&inet6_protocol_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
return(0);
}
@@ -98,7 +97,7 @@ int inet6_del_protocol(struct inet6_protocol *prot)
if (p->copy == 0 && lp != NULL)
lp->copy = 0;
p->next = prot->next;
- write_unlock_bh(&inet6_protocol_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
return(0);
}
if (p->next != NULL && p->next->protocol == prot->protocol)
@@ -106,6 +105,6 @@ int inet6_del_protocol(struct inet6_protocol *prot)
p = (struct inet6_protocol *) p->next;
}
- write_unlock_bh(&inet6_protocol_lock);
+ br_write_unlock_bh(BR_NETPROTO_LOCK);
return(-1);
}
diff --git a/net/ipv6/raw.c b/net/ipv6/raw.c
index 574bc165c..bb4ecb551 100644
--- a/net/ipv6/raw.c
+++ b/net/ipv6/raw.c
@@ -7,7 +7,10 @@
*
* Adapted from linux/net/ipv4/raw.c
*
- * $Id: raw.c,v 1.33 2000/01/18 08:24:22 davem Exp $
+ * $Id: raw.c,v 1.34 2000/02/27 19:51:48 davem Exp $
+ *
+ * Fixes:
+ * Hideaki YOSHIFUJI : sin6_scope_id support
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -183,9 +186,8 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
int addr_type;
int err;
- if (addr_len < sizeof(struct sockaddr_in6))
+ if (addr_len < SIN6_LEN_RFC2133)
return -EINVAL;
-
addr_type = ipv6_addr_type(&addr->sin6_addr);
/* Raw sockets are IPv6 only */
@@ -198,6 +200,20 @@ static int rawv6_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
if (sk->state != TCP_CLOSE)
goto out;
+ if (addr_type & IPV6_ADDR_LINKLOCAL) {
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ addr->sin6_scope_id) {
+ /* Override any existing binding, if another one
+ * is supplied by user.
+ */
+ sk->bound_dev_if = addr->sin6_scope_id;
+ }
+
+ /* Binding to link-local address requires an interface */
+ if (sk->bound_dev_if == 0)
+ goto out;
+ }
+
/* Check if the address belongs to the host. */
if (addr_type != IPV6_ADDR_ANY) {
/* ipv4 addr of the socket is invalid. Only the
@@ -325,6 +341,11 @@ int rawv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
memcpy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr,
sizeof(struct in6_addr));
sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
+ if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
+ struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
+ sin6->sin6_scope_id = opt->iif;
+ }
}
if (sk->net_pinfo.af_inet6.rxopt.all)
@@ -429,14 +450,15 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
*/
fl.fl6_flowlabel = 0;
+ fl.oif = 0;
if (sin6) {
- if (addr_len < sizeof(struct sockaddr_in6))
- return(-EINVAL);
+ if (addr_len < SIN6_LEN_RFC2133)
+ return -EINVAL;
if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
return(-EINVAL);
-
+
/* port is the proto value [0..255] carried in nexthdr */
proto = ntohs(sin6->sin6_port);
@@ -457,11 +479,15 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
}
}
-
/* Otherwise it will be difficult to maintain sk->dst_cache. */
if (sk->state == TCP_ESTABLISHED &&
!ipv6_addr_cmp(daddr, &sk->net_pinfo.af_inet6.daddr))
daddr = &sk->net_pinfo.af_inet6.daddr;
+
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ sin6->sin6_scope_id &&
+ ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
+ fl.oif = sin6->sin6_scope_id;
} else {
if (sk->state != TCP_ESTABLISHED)
return(-EINVAL);
@@ -479,7 +505,8 @@ static int rawv6_sendmsg(struct sock *sk, struct msghdr *msg, int len)
return(-EINVAL);
}
- fl.oif = sk->bound_dev_if;
+ if (fl.oif == 0)
+ fl.oif = sk->bound_dev_if;
fl.fl6_src = NULL;
if (msg->msg_controllen) {
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 47dcf8ce0..f47b4a103 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -5,13 +5,16 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: tcp_ipv6.c,v 1.119 2000/01/31 01:21:26 davem Exp $
+ * $Id: tcp_ipv6.c,v 1.120 2000/02/27 19:51:49 davem Exp $
*
* Based on:
* linux/net/ipv4/tcp.c
* linux/net/ipv4/tcp_input.c
* linux/net/ipv4/tcp_output.c
*
+ * Fixes:
+ * Hideaki YOSHIFUJI : sin6_scope_id support
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -509,8 +512,8 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
int addr_type;
int err;
- if (addr_len < sizeof(struct sockaddr_in6))
- return(-EINVAL);
+ if (addr_len < SIN6_LEN_RFC2133)
+ return -EINVAL;
if (usin->sin6_family != AF_INET6)
return(-EAFNOSUPPORT);
@@ -540,6 +543,24 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
if(addr_type & IPV6_ADDR_MULTICAST)
return -ENETUNREACH;
+ if (addr_type&IPV6_ADDR_LINKLOCAL) {
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ usin->sin6_scope_id) {
+ /* If interface is set while binding, indices
+ * must coincide.
+ */
+ if (sk->bound_dev_if &&
+ sk->bound_dev_if != usin->sin6_scope_id)
+ return -EINVAL;
+
+ sk->bound_dev_if = usin->sin6_scope_id;
+ }
+
+ /* Connect to link-local address requires an interface */
+ if (sk->bound_dev_if == 0)
+ return -EINVAL;
+ }
+
if (tp->ts_recent_stamp && ipv6_addr_cmp(&np->daddr, &usin->sin6_addr)) {
tp->ts_recent = 0;
tp->ts_recent_stamp = 0;
@@ -605,15 +626,6 @@ static int tcp_v6_connect(struct sock *sk, struct sockaddr *uaddr,
goto failure;
}
- if (fl.oif == 0 && addr_type&IPV6_ADDR_LINKLOCAL) {
- /* Ough! This guy tries to connect to link local
- * address and did not specify interface.
- * Actually we should kick him out, but
- * we will be patient :) --ANK
- */
- sk->bound_dev_if = dst->dev->ifindex;
- }
-
ip6_dst_store(sk, dst, NULL);
if (saddr == NULL) {
@@ -1723,6 +1735,9 @@ static void v6_addr2sockaddr(struct sock *sk, struct sockaddr * uaddr)
sin6->sin6_port = sk->dport;
/* We do not store received flowlabel for TCP */
sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
+ if (sk->bound_dev_if && ipv6_addr_type(&sin6->sin6_addr)&IPV6_ADDR_LINKLOCAL)
+ sin6->sin6_scope_id = sk->bound_dev_if;
}
static int tcp_v6_remember_stamp(struct sock *sk)
diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c
index a5984354b..fed8e3aa2 100644
--- a/net/ipv6/udp.c
+++ b/net/ipv6/udp.c
@@ -7,7 +7,10 @@
*
* Based on linux/ipv4/udp.c
*
- * $Id: udp.c,v 1.50 2000/01/18 08:24:24 davem Exp $
+ * $Id: udp.c,v 1.51 2000/02/27 19:51:51 davem Exp $
+ *
+ * Fixes:
+ * Hideaki YOSHIFUJI : sin6_scope_id support
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -218,7 +221,7 @@ int udpv6_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
goto ipv4_connected;
}
- if (addr_len < sizeof(*usin))
+ if (addr_len < SIN6_LEN_RFC2133)
return -EINVAL;
if (usin->sin6_family != AF_INET6)
@@ -278,6 +281,21 @@ ipv4_connected:
return 0;
}
+ if (addr_type&IPV6_ADDR_LINKLOCAL) {
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ usin->sin6_scope_id) {
+ if (sk->bound_dev_if && sk->bound_dev_if != usin->sin6_scope_id) {
+ fl6_sock_release(flowlabel);
+ return -EINVAL;
+ }
+ sk->bound_dev_if = usin->sin6_scope_id;
+ }
+
+ /* Connect to link-local address requires an interface */
+ if (sk->bound_dev_if == 0)
+ return -EINVAL;
+ }
+
ipv6_addr_copy(&np->daddr, daddr);
np->flow_label = fl.fl6_flowlabel;
@@ -392,6 +410,7 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
sin6->sin6_family = AF_INET6;
sin6->sin6_port = skb->h.uh->source;
sin6->sin6_flowinfo = 0;
+ sin6->sin6_scope_id = 0;
if (skb->protocol == __constant_htons(ETH_P_IP)) {
ipv6_addr_set(&sin6->sin6_addr, 0, 0,
@@ -404,6 +423,10 @@ int udpv6_recvmsg(struct sock *sk, struct msghdr *msg, int len,
if (sk->net_pinfo.af_inet6.rxopt.all)
datagram_recv_ctl(sk, msg, skb);
+ if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
+ struct inet6_skb_parm *opt = (struct inet6_skb_parm *) skb->cb;
+ sin6->sin6_scope_id = opt->iif;
+ }
}
}
err = copied;
@@ -746,12 +769,13 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
return -EMSGSIZE;
fl.fl6_flowlabel = 0;
+ fl.oif = 0;
if (sin6) {
if (sin6->sin6_family == AF_INET)
return udp_sendmsg(sk, msg, ulen);
- if (addr_len < sizeof(*sin6))
+ if (addr_len < SIN6_LEN_RFC2133)
return -EINVAL;
if (sin6->sin6_family && sin6->sin6_family != AF_INET6)
@@ -777,6 +801,11 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
if (sk->state == TCP_ESTABLISHED &&
!ipv6_addr_cmp(daddr, &sk->net_pinfo.af_inet6.daddr))
daddr = &sk->net_pinfo.af_inet6.daddr;
+
+ if (addr_len >= sizeof(struct sockaddr_in6) &&
+ sin6->sin6_scope_id &&
+ ipv6_addr_type(daddr)&IPV6_ADDR_LINKLOCAL)
+ fl.oif = sin6->sin6_scope_id;
} else {
if (sk->state != TCP_ESTABLISHED)
return -ENOTCONN;
@@ -802,7 +831,8 @@ static int udpv6_sendmsg(struct sock *sk, struct msghdr *msg, int ulen)
}
udh.daddr = NULL;
- fl.oif = sk->bound_dev_if;
+ if (!fl.oif)
+ fl.oif = sk->bound_dev_if;
fl.fl6_src = NULL;
if (msg->msg_controllen) {
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index 60427ef6e..9db90b0b8 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -2352,13 +2352,10 @@ static struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
#include <linux/smp_lock.h>
SOCKOPS_WRAP(ipx_dgram, PF_IPX);
-
-/* Called by protocol.c on kernel start up */
-
static struct packet_type ipx_8023_packet_type =
{
- 0, /* MUTTER ntohs(ETH_P_802_3),*/
+ __constant_htons(ETH_P_802_3),
NULL, /* All devices */
ipx_rcv,
NULL,
@@ -2367,7 +2364,7 @@ static struct packet_type ipx_8023_packet_type =
static struct packet_type ipx_dix_packet_type =
{
- 0, /* MUTTER ntohs(ETH_P_IPX),*/
+ __constant_htons(ETH_P_IPX),
NULL, /* All devices */
ipx_rcv,
NULL,
@@ -2389,16 +2386,18 @@ extern void destroy_8023_client(struct datalink_proto *);
static unsigned char ipx_8022_type = 0xE0;
static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
+
+
+/* Called by protocols.c on kernel start up */
+
void ipx_proto_init(struct net_proto *pro)
{
(void) sock_register(&ipx_family_ops);
pEII_datalink = make_EII_client();
- ipx_dix_packet_type.type = htons(ETH_P_IPX);
dev_add_pack(&ipx_dix_packet_type);
p8023_datalink = make_8023_client();
- ipx_8023_packet_type.type = htons(ETH_P_802_3);
dev_add_pack(&ipx_8023_packet_type);
if((p8022_datalink = register_8022_client(ipx_8022_type,ipx_rcv)) == NULL)
diff --git a/net/irda/irda_device.c b/net/irda/irda_device.c
index 94345259d..9968e0e95 100644
--- a/net/irda/irda_device.c
+++ b/net/irda/irda_device.c
@@ -46,6 +46,7 @@
#include <asm/segment.h>
#include <asm/uaccess.h>
#include <asm/dma.h>
+#include <asm/io.h>
#include <net/pkt_sched.h>
diff --git a/net/irda/iriap_event.c b/net/irda/iriap_event.c
index eb8463b73..c073f5baf 100644
--- a/net/irda/iriap_event.c
+++ b/net/irda/iriap_event.c
@@ -6,10 +6,10 @@
* Status: Experimental.
* Author: Dag Brattli <dagb@cs.uit.no>
* Created at: Thu Aug 21 00:02:07 1997
- * Modified at: Sat Dec 25 21:09:47 1999
+ * Modified at: Wed Mar 1 11:28:34 2000
* Modified by: Dag Brattli <dagb@cs.uit.no>
*
- * Copyright (c) 1997, 1999 Dag Brattli <dagb@cs.uit.no>,
+ * Copyright (c) 1997, 1999-2000 Dag Brattli <dagb@cs.uit.no>,
* All Rights Reserved.
*
* This program is free software; you can redistribute it and/or
@@ -294,7 +294,7 @@ static void state_s_outstanding(struct iriap_cb *self, IRIAP_EVENT event,
switch (event) {
case IAP_RECV_F_LST:
- iriap_send_ack(self);
+ /*iriap_send_ack(self);*/
/*LM_Idle_request(idle); */
iriap_next_call_state(self, S_WAIT_FOR_CALL);
diff --git a/net/irda/parameters.c b/net/irda/parameters.c
index 19f76eae4..263c2e2a4 100644
--- a/net/irda/parameters.c
+++ b/net/irda/parameters.c
@@ -356,21 +356,23 @@ int irda_param_pack(__u8 *buf, char *fmt, ...)
for (p = fmt; *p != '\0'; p++) {
switch (*p) {
case 'b': /* 8 bits unsigned byte */
- buf[n++] = va_arg(args, __u8);
+ buf[n++] = (__u8)va_arg(args, int);
break;
case 's': /* 16 bits unsigned short */
- arg.s = va_arg(args, __u16);
+ arg.s = (__u16)va_arg(args, int);
put_unaligned(arg.s, (__u16 *)(buf+n)); n+=2;
break;
case 'i': /* 32 bits unsigned integer */
arg.i = va_arg(args, __u32);
put_unaligned(arg.i, (__u32 *)(buf+n)); n+=4;
break;
+#if 0
case 'c': /* \0 terminated string */
arg.c = va_arg(args, char *);
strcpy(buf+n, arg.c);
n += strlen(arg.c) + 1;
break;
+#endif
default:
va_end(args);
return -1;
diff --git a/net/netsyms.c b/net/netsyms.c
index d03c0a1b1..16ff31dd0 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -502,6 +502,7 @@ EXPORT_SYMBOL(dev_remove_pack);
EXPORT_SYMBOL(dev_get);
EXPORT_SYMBOL(dev_alloc);
EXPORT_SYMBOL(dev_alloc_name);
+EXPORT_SYMBOL(__netdev_watchdog_up);
#ifdef CONFIG_KMOD
EXPORT_SYMBOL(dev_load);
#endif
@@ -580,10 +581,9 @@ EXPORT_SYMBOL(nf_register_hook);
EXPORT_SYMBOL(nf_unregister_hook);
EXPORT_SYMBOL(nf_register_sockopt);
EXPORT_SYMBOL(nf_unregister_sockopt);
-EXPORT_SYMBOL(nf_getinfo);
EXPORT_SYMBOL(nf_reinject);
-EXPORT_SYMBOL(nf_register_interest);
-EXPORT_SYMBOL(nf_unregister_interest);
+EXPORT_SYMBOL(nf_register_queue_handler);
+EXPORT_SYMBOL(nf_unregister_queue_handler);
EXPORT_SYMBOL(nf_hook_slow);
EXPORT_SYMBOL(nf_hooks);
#endif
diff --git a/net/sched/sch_generic.c b/net/sched/sch_generic.c
index 8ee8ab54f..d0c0539aa 100644
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -146,16 +146,17 @@ static void dev_watchdog(unsigned long arg)
spin_lock(&dev->xmit_lock);
if (dev->qdisc != &noop_qdisc) {
- if (netif_queue_stopped(dev) &&
- (jiffies - dev->trans_start) > dev->watchdog_timeo) {
- printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", dev->name);
- dev->tx_timeout(dev);
+ if (netif_device_present(dev) &&
+ netif_running(dev) &&
+ netif_carrier_ok(dev)) {
+ if (netif_queue_stopped(dev) &&
+ (jiffies - dev->trans_start) > dev->watchdog_timeo) {
+ printk(KERN_INFO "NETDEV WATCHDOG: %s: transmit timed out\n", dev->name);
+ dev->tx_timeout(dev);
+ }
+ if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
+ dev_hold(dev);
}
- if (!del_timer(&dev->watchdog_timer))
- dev_hold(dev);
-
- dev->watchdog_timer.expires = jiffies + dev->watchdog_timeo;
- add_timer(&dev->watchdog_timer);
}
spin_unlock(&dev->xmit_lock);
@@ -169,33 +170,31 @@ static void dev_watchdog_init(struct net_device *dev)
dev->watchdog_timer.function = dev_watchdog;
}
-static void dev_watchdog_up(struct net_device *dev)
+void __netdev_watchdog_up(struct net_device *dev)
{
- spin_lock_bh(&dev->xmit_lock);
-
if (dev->tx_timeout) {
if (dev->watchdog_timeo <= 0)
dev->watchdog_timeo = 5*HZ;
- if (!del_timer(&dev->watchdog_timer))
+ if (!mod_timer(&dev->watchdog_timer, jiffies + dev->watchdog_timeo))
dev_hold(dev);
- dev->watchdog_timer.expires = jiffies + dev->watchdog_timeo;
- add_timer(&dev->watchdog_timer);
}
+}
+
+static void dev_watchdog_up(struct net_device *dev)
+{
+ spin_lock_bh(&dev->xmit_lock);
+ __netdev_watchdog_up(dev);
spin_unlock_bh(&dev->xmit_lock);
}
static void dev_watchdog_down(struct net_device *dev)
{
spin_lock_bh(&dev->xmit_lock);
-
- if (dev->tx_timeout) {
- if (del_timer(&dev->watchdog_timer))
- __dev_put(dev);
- }
+ if (del_timer(&dev->watchdog_timer))
+ __dev_put(dev);
spin_unlock_bh(&dev->xmit_lock);
}
-
/* "NOOP" scheduler: the best scheduler, recommended for all interfaces
under all circumstances. It is difficult to invent anything faster or
cheaper.
diff --git a/net/sched/sch_red.c b/net/sched/sch_red.c
index 84deb1ce4..d8c117247 100644
--- a/net/sched/sch_red.c
+++ b/net/sched/sch_red.c
@@ -11,6 +11,7 @@
* Changes:
* J Hadi Salim <hadi@nortel.com> 980914: computation fixes
* Alexey Makarenko <makar@phoenix.kharkov.ua> 990814: qave on idle link was calculated incorrectly.
+ * J Hadi Salim <hadi@nortelnetworks.com> 980816: ECN support
*/
#include <linux/config.h>
@@ -39,6 +40,9 @@
#include <net/sock.h>
#include <net/pkt_sched.h>
+#define RED_ECN_ECT 0x02
+#define RED_ECN_CE 0x01
+
/* Random Early Detection (RED) algorithm.
=======================================
@@ -138,6 +142,7 @@ struct red_sched_data
u32 qth_max; /* Max average length threshold: A scaled */
u32 Rmask;
u32 Scell_max;
+ unsigned char flags;
char Wlog; /* log(W) */
char Plog; /* random number bits */
char Scell_log;
@@ -149,8 +154,48 @@ struct red_sched_data
u32 qR; /* Cached random number */
psched_time_t qidlestart; /* Start of idle period */
+ struct tc_red_xstats st;
};
+static int red_ecn_mark(struct sk_buff *skb)
+{
+ if (skb->nh.raw + 20 < skb->tail)
+ return 0;
+
+ switch (skb->protocol) {
+ case __constant_htons(ETH_P_IP):
+ {
+ u8 tos = skb->nh.iph->tos;
+
+ if (!(tos & RED_ECN_ECT))
+ return 0;
+
+ if (!(tos & RED_ECN_CE)) {
+ u32 check = skb->nh.iph->check;
+
+ check += __constant_htons(0xFFFE);
+ skb->nh.iph->check = check + (check>>16);
+
+ skb->nh.iph->tos = tos | RED_ECN_CE;
+ }
+ return 1;
+ }
+
+ case __constant_htons(ETH_P_IPV6):
+ {
+ u32 label = *(u32*)skb->nh.raw;
+
+ if (!(label & __constant_htonl(RED_ECN_ECT<<20)))
+ return 0;
+ label |= __constant_htonl(RED_ECN_CE<<20);
+ return 1;
+ }
+
+ default:
+ return 0;
+ }
+}
+
static int
red_enqueue(struct sk_buff *skb, struct Qdisc* sch)
{
@@ -221,7 +266,9 @@ enqueue:
sch->stats.backlog += skb->len;
sch->stats.bytes += skb->len;
sch->stats.packets++;
- return 0;
+ return NET_XMIT_SUCCESS;
+ } else {
+ q->st.pdrop++;
}
kfree_skb(skb);
sch->stats.drops++;
@@ -231,10 +278,14 @@ enqueue:
q->qcount = -1;
sch->stats.overlimits++;
mark:
- kfree_skb(skb);
- sch->stats.drops++;
- return NET_XMIT_CN;
+ if (!(q->flags&TC_RED_ECN) || !red_ecn_mark(skb)) {
+ q->st.early++;
+ goto drop;
+ }
+ q->st.marked++;
+ goto enqueue;
}
+
if (++q->qcount) {
/* The formula used below causes questions.
@@ -261,6 +312,11 @@ mark:
}
q->qR = net_random()&q->Rmask;
goto enqueue;
+
+drop:
+ kfree_skb(skb);
+ sch->stats.drops++;
+ return NET_XMIT_CN;
}
static int
@@ -300,6 +356,7 @@ red_drop(struct Qdisc* sch)
if (skb) {
sch->stats.backlog -= skb->len;
sch->stats.drops++;
+ q->st.other++;
kfree_skb(skb);
return 1;
}
@@ -336,6 +393,7 @@ static int red_change(struct Qdisc *sch, struct rtattr *opt)
ctl = RTA_DATA(tb[TCA_RED_PARMS-1]);
sch_tree_lock(sch);
+ q->flags = ctl->flags;
q->Wlog = ctl->Wlog;
q->Plog = ctl->Plog;
q->Rmask = ctl->Plog < 32 ? ((1<<ctl->Plog) - 1) : ~0UL;
@@ -367,6 +425,15 @@ static int red_init(struct Qdisc* sch, struct rtattr *opt)
#ifdef CONFIG_RTNETLINK
+int red_copy_xstats(struct sk_buff *skb, struct tc_red_xstats *st)
+{
+ RTA_PUT(skb, TCA_XSTATS, sizeof(*st), st);
+ return 0;
+
+rtattr_failure:
+ return 1;
+}
+
static int red_dump(struct Qdisc *sch, struct sk_buff *skb)
{
struct red_sched_data *q = (struct red_sched_data *)sch->data;
@@ -382,9 +449,13 @@ static int red_dump(struct Qdisc *sch, struct sk_buff *skb)
opt.Wlog = q->Wlog;
opt.Plog = q->Plog;
opt.Scell_log = q->Scell_log;
+ opt.flags = q->flags;
RTA_PUT(skb, TCA_RED_PARMS, sizeof(opt), &opt);
rta->rta_len = skb->tail - b;
+ if (red_copy_xstats(skb, &q->st))
+ goto rtattr_failure;
+
return skb->len;
rtattr_failure:
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c
index 7b3c63e87..a57c2a06d 100644
--- a/net/unix/af_unix.c
+++ b/net/unix/af_unix.c
@@ -8,7 +8,7 @@
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version: $Id: af_unix.c,v 1.88 2000/01/18 08:24:28 davem Exp $
+ * Version: $Id: af_unix.c,v 1.89 2000/02/27 19:52:50 davem Exp $
*
* Fixes:
* Linus Torvalds : Assorted bug cures.
@@ -1556,8 +1556,10 @@ static int unix_shutdown(struct socket *sock, int mode)
other->shutdown |= peer_mode;
unix_state_wunlock(other);
other->state_change(other);
- if (peer_mode&RCV_SHUTDOWN)
- sock_wake_async(sk->socket,1,POLL_HUP);
+ if (peer_mode == SHUTDOWN_MASK)
+ sock_wake_async(other->socket,1,POLL_HUP);
+ else if (peer_mode & RCV_SHUTDOWN)
+ sock_wake_async(other->socket,1,POLL_IN);
}
if (other)
sock_put(other);