summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@athlon.transmeta.com>2002-02-04 18:06:16 -0800
committerLinus Torvalds <torvalds@athlon.transmeta.com>2002-02-04 18:06:16 -0800
commit8b11a705bdc5fd9f39b113f7d1dc9c8eeabe301b (patch)
treef00c6c3accce342c055af338eaa88583e5fe3552 /net
parent90a880a460aeb2374d6c766c08fa7786fb982aae (diff)
v2.4.2.7 -> v2.4.2.8
- Paul Mackerras: PPC update for thread-safe page table handling - Ingo Molnar: x86 PAE update for thread-safe page table handling - Jeff Garzik: network driver updates, i810 rng driver, and "alloc_etherdev()" network driver insert race condition fix. - David Miller: UltraSparcIII update, network locking fixes - Al Viro: fix fs counts on mount failure
Diffstat (limited to 'net')
-rw-r--r--net/atm/proc.c1
-rw-r--r--net/core/dv.c2
-rw-r--r--net/decnet/af_decnet.c7
-rw-r--r--net/ipv4/devinet.c8
-rw-r--r--net/ipv4/ip_fragment.c13
-rw-r--r--net/ipv4/sysctl_net_ipv4.c5
-rw-r--r--net/ipv6/ip6_fib.c31
-rw-r--r--net/ipv6/ipv6_sockglue.c9
-rw-r--r--net/ipv6/reassembly.c13
-rw-r--r--net/ipv6/tcp_ipv6.c2
-rw-r--r--net/ipx/af_ipx.c474
-rw-r--r--net/ipx/sysctl_net_ipx.c42
-rw-r--r--net/khttpd/main.c2
-rw-r--r--net/khttpd/rfc.c2
-rw-r--r--net/netsyms.c24
-rw-r--r--net/sched/cls_tcindex.c68
-rw-r--r--net/sched/sch_cbq.c6
-rw-r--r--net/sched/sch_dsmark.c8
-rw-r--r--net/sched/sch_tbf.c21
-rw-r--r--net/sysctl_net.c7
-rw-r--r--net/wanrouter/wanmain.c2
21 files changed, 454 insertions, 293 deletions
diff --git a/net/atm/proc.c b/net/atm/proc.c
index ef0091735aa7..8c3dc562ff5c 100644
--- a/net/atm/proc.c
+++ b/net/atm/proc.c
@@ -561,7 +561,6 @@ int atm_proc_dev_register(struct atm_dev *dev)
dev->proc_entry->proc_fops = &proc_dev_atm_operations;
dev->proc_entry->owner = THIS_MODULE;
return 0;
- kfree(dev->proc_entry);
fail0:
kfree(dev->proc_name);
fail1:
diff --git a/net/core/dv.c b/net/core/dv.c
index 0e5b3e671620..1a31310ca730 100644
--- a/net/core/dv.c
+++ b/net/core/dv.c
@@ -172,7 +172,7 @@ int check_args(struct divert_cf *div_cf, struct net_device **dev)
return -EINVAL;
/* user issuing the ioctl must be a super one :) */
- if (!suser())
+ if (!capable(CAP_SYS_ADMIN))
return -EPERM;
/* Device must have a divert_blk member NOT null */
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 6cca075c00bb..f5e94de8f2f8 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -1431,10 +1431,13 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char *opt
struct sock *sk = sock->sk;
struct dn_scp *scp = DN_SK(sk);
struct linkinfo_dn link;
- int r_len = *optlen;
+ int r_len;
void *r_data = NULL;
- int val;
+ unsigned int val;
+ if(get_user(r_len , optlen))
+ return -EFAULT;
+
switch(optname) {
case DSO_CONDATA:
if (r_len > sizeof(struct optdata_dn))
diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c
index 8d668ff41839..e35e0d6cbbf3 100644
--- a/net/ipv4/devinet.c
+++ b/net/ipv4/devinet.c
@@ -1,7 +1,7 @@
/*
* NET3 IP device support routines.
*
- * Version: $Id: devinet.c,v 1.40 2001/02/05 06:03:47 davem Exp $
+ * Version: $Id: devinet.c,v 1.41 2001/02/18 09:26:26 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -827,10 +827,8 @@ static int inetdev_event(struct notifier_block *this, unsigned long event, void
return NOTIFY_DONE;
}
-struct notifier_block ip_netdev_notifier={
- inetdev_event,
- NULL,
- 0
+struct notifier_block ip_netdev_notifier = {
+ notifier_call: inetdev_event,
};
#ifdef CONFIG_RTNETLINK
diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c
index afed5862ea48..5cd316a26ebc 100644
--- a/net/ipv4/ip_fragment.c
+++ b/net/ipv4/ip_fragment.c
@@ -213,18 +213,17 @@ static void ip_evictor(void)
if (ipq_hash[i] == NULL)
continue;
- write_lock(&ipfrag_lock);
+ read_lock(&ipfrag_lock);
if ((qp = ipq_hash[i]) != NULL) {
/* find the oldest queue for this hash bucket */
while (qp->next)
qp = qp->next;
- __ipq_unlink(qp);
- write_unlock(&ipfrag_lock);
+ atomic_inc(&qp->refcnt);
+ read_unlock(&ipfrag_lock);
spin_lock(&qp->lock);
- if (del_timer(&qp->timer))
- atomic_dec(&qp->refcnt);
- qp->last_in |= COMPLETE;
+ if (!(qp->last_in&COMPLETE))
+ ipq_kill(qp);
spin_unlock(&qp->lock);
ipq_put(qp);
@@ -232,7 +231,7 @@ static void ip_evictor(void)
progress = 1;
continue;
}
- write_unlock(&ipfrag_lock);
+ read_unlock(&ipfrag_lock);
}
} while (progress);
}
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 68d536e108bf..25f0b0c1edee 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -1,7 +1,7 @@
/*
* sysctl_net_ipv4.c: sysctl interface to net IPV4 subsystem.
*
- * $Id: sysctl_net_ipv4.c,v 1.47 2000/10/19 15:51:02 davem Exp $
+ * $Id: sysctl_net_ipv4.c,v 1.48 2001/02/23 01:39:05 davem Exp $
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/ipv4 directory entry (empty =) ). [MS]
@@ -47,10 +47,11 @@ extern int inet_peer_maxttl;
extern int inet_peer_gc_mintime;
extern int inet_peer_gc_maxtime;
+#ifdef CONFIG_SYSCTL
static int tcp_retr1_max = 255;
-
static int ip_local_port_range_min[] = { 1, 1 };
static int ip_local_port_range_max[] = { 65535, 65535 };
+#endif
struct ipv4_config ipv4_config;
diff --git a/net/ipv6/ip6_fib.c b/net/ipv6/ip6_fib.c
index 49fc32f59961..28180240bcaa 100644
--- a/net/ipv6/ip6_fib.c
+++ b/net/ipv6/ip6_fib.c
@@ -5,7 +5,7 @@
* Authors:
* Pedro Roque <roque@di.fc.ul.pt>
*
- * $Id: ip6_fib.c,v 1.22 2000/09/12 00:38:34 davem Exp $
+ * $Id: ip6_fib.c,v 1.23 2001/03/19 20:31:17 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -76,7 +76,7 @@ rwlock_t fib6_walker_lock = RW_LOCK_UNLOCKED;
#endif
static void fib6_prune_clones(struct fib6_node *fn, struct rt6_info *rt);
-static void fib6_repair_tree(struct fib6_node *fn);
+static struct fib6_node * fib6_repair_tree(struct fib6_node *fn);
/*
* A routing update causes an increase of the serial number on the
@@ -774,7 +774,7 @@ static struct rt6_info * fib6_find_prefix(struct fib6_node *fn)
* is the node we want to try and remove.
*/
-static void fib6_repair_tree(struct fib6_node *fn)
+static struct fib6_node * fib6_repair_tree(struct fib6_node *fn)
{
int children;
int nstate;
@@ -809,7 +809,7 @@ static void fib6_repair_tree(struct fib6_node *fn)
}
#endif
atomic_inc(&fn->leaf->rt6i_ref);
- return;
+ return fn->parent;
}
pn = fn->parent;
@@ -865,7 +865,7 @@ static void fib6_repair_tree(struct fib6_node *fn)
node_free(fn);
if (pn->fn_flags&RTN_RTINFO || SUBTREE(pn))
- return;
+ return pn;
rt6_release(pn->leaf);
pn->leaf = NULL;
@@ -903,7 +903,26 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp)
if (fn->leaf == NULL) {
fn->fn_flags &= ~RTN_RTINFO;
rt6_stats.fib_route_nodes--;
- fib6_repair_tree(fn);
+ fn = fib6_repair_tree(fn);
+ }
+
+ if (atomic_read(&rt->rt6i_ref) != 1) {
+ /* This route is used as dummy address holder in some split
+ * nodes. It is not leaked, but it still holds other resources,
+ * which must be released in time. So, scan ascendant nodes
+ * and replace dummy references to this route with references
+ * to still alive ones.
+ */
+ while (fn) {
+ if (!(fn->fn_flags&RTN_RTINFO) && fn->leaf == rt) {
+ fn->leaf = fib6_find_prefix(fn);
+ atomic_inc(&fn->leaf->rt6i_ref);
+ rt6_release(rt);
+ }
+ fn = fn->parent;
+ }
+ /* No more references are possiible at this point. */
+ if (atomic_read(&rt->rt6i_ref) != 1) BUG();
}
#ifdef CONFIG_RTNETLINK
diff --git a/net/ipv6/ipv6_sockglue.c b/net/ipv6/ipv6_sockglue.c
index e93799a37ef3..2332f754928a 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.34 2000/11/28 13:44:28 davem Exp $
+ * $Id: ipv6_sockglue.c,v 1.36 2001/02/26 05:59:07 davem Exp $
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -253,6 +253,13 @@ int ipv6_setsockopt(struct sock *sk, int level, int optname, char *optval,
if (optlen == 0)
goto update;
+ /* 1K is probably excessive
+ * 1K is surely not enough, 2K per standard header is 16K.
+ */
+ retv = -EINVAL;
+ if (optlen > 64*1024)
+ break;
+
opt = sock_kmalloc(sk, sizeof(*opt) + optlen, GFP_KERNEL);
retv = -ENOBUFS;
if (opt == NULL)
diff --git a/net/ipv6/reassembly.c b/net/ipv6/reassembly.c
index 0529aa480ef7..10ab39e044d9 100644
--- a/net/ipv6/reassembly.c
+++ b/net/ipv6/reassembly.c
@@ -203,18 +203,17 @@ static void ip6_evictor(void)
if (ip6_frag_hash[i] == NULL)
continue;
- write_lock(&ip6_frag_lock);
+ read_lock(&ip6_frag_lock);
if ((fq = ip6_frag_hash[i]) != NULL) {
/* find the oldest queue for this hash bucket */
while (fq->next)
fq = fq->next;
- __fq_unlink(fq);
- write_unlock(&ip6_frag_lock);
+ atomic_inc(&fq->refcnt);
+ read_unlock(&ip6_frag_lock);
spin_lock(&fq->lock);
- if (del_timer(&fq->timer))
- atomic_dec(&fq->refcnt);
- fq->last_in |= COMPLETE;
+ if (!(fq->last_in&COMPLETE))
+ fq_kill(fq);
spin_unlock(&fq->lock);
fq_put(fq);
@@ -222,7 +221,7 @@ static void ip6_evictor(void)
progress = 1;
continue;
}
- write_unlock(&ip6_frag_lock);
+ read_unlock(&ip6_frag_lock);
}
} while (progress);
}
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index 8f452acc1402..3bbfcca17c0a 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -421,7 +421,7 @@ static int tcp_v6_check_established(struct sock *sk)
struct sock *sk2, **skp;
struct tcp_tw_bucket *tw;
- write_lock(&head->lock);
+ write_lock_bh(&head->lock);
for(skp = &(head + tcp_ehash_size)->chain; (sk2=*skp)!=NULL; skp = &sk2->next) {
tw = (struct tcp_tw_bucket*)sk2;
diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c
index b34f9bcaa25a..f58ae816bd1c 100644
--- a/net/ipx/af_ipx.c
+++ b/net/ipx/af_ipx.c
@@ -65,6 +65,12 @@
* Arnaldo Carvalho de Melo <acme@conectiva.com.br>,
* December, 2000
* Revision 044: Call ipxitf_hold on NETDEV_UP (acme)
+ * Revision 045: fix PPROP routing bug (acme)
+ * Revision 046: Further fixes to PPROP, ipxitf_create_internal was
+ * doing an unneeded MOD_INC_USE_COUNT, implement
+ * sysctl for ipx_pprop_broacasting, fix the ipx sysctl
+ * handling, making it dynamic, some cleanups, thanks to
+ * Petr Vandrovec for review and good suggestions. (acme)
*
* Protect the module by a MOD_INC_USE_COUNT/MOD_DEC_USE_COUNT
* pair. Also, now usage count is managed this way
@@ -81,7 +87,6 @@
*/
#include <linux/config.h>
-#if defined (CONFIG_IPX) || defined (CONFIG_IPX_MODULE)
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/types.h>
@@ -111,14 +116,14 @@
#include <linux/init.h>
#include <linux/if_arp.h>
-#ifdef MODULE
-static void ipx_proto_finito(void);
-#endif /* def MODULE */
+extern void ipx_register_sysctl(void);
+extern void ipx_unregister_sysctl(void);
/* Configuration Variables */
static unsigned char ipxcfg_max_hops = 16;
static char ipxcfg_auto_select_primary;
static char ipxcfg_auto_create_interfaces;
+static int sysctl_ipx_pprop_broadcasting = 1;
/* Global Variables */
static struct datalink_proto *p8022_datalink;
@@ -139,6 +144,8 @@ static spinlock_t ipx_interfaces_lock = SPIN_LOCK_UNLOCKED;
static ipx_interface *ipx_primary_net;
static ipx_interface *ipx_internal_net;
+#define IPX_SKB_CB(__skb) ((struct ipx_cb *)&((__skb)->cb[0]))
+
#undef IPX_REFCNT_DEBUG
#ifdef IPX_REFCNT_DEBUG
atomic_t ipx_sock_nr;
@@ -675,17 +682,30 @@ static struct sk_buff *ipxitf_adjust_skbuff(ipx_interface *intrfc,
return skb2;
}
-/* caller must hold a reference to intrfc */
+/* caller must hold a reference to intrfc and the skb has to be unshared */
static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
{
struct ipxhdr *ipx = skb->nh.ipxh;
- struct ipx_cb *cb = (struct ipx_cb *) skb->cb;
struct net_device *dev = intrfc->if_dev;
struct datalink_proto *dl = intrfc->if_dlink;
char dest_node[IPX_NODE_LEN];
int send_to_wire = 1;
int addr_len;
+
+ ipx->ipx_tctrl = IPX_SKB_CB(skb)->ipx_tctrl;
+ ipx->ipx_dest.net = IPX_SKB_CB(skb)->ipx_dest_net;
+ ipx->ipx_source.net = IPX_SKB_CB(skb)->ipx_source_net;
+
+ /* see if we need to include the netnum in the route list */
+ if (IPX_SKB_CB(skb)->last_hop.index >= 0) {
+ u32 *last_hop = (u32 *)(((u8 *) skb->data) +
+ sizeof(struct ipxhdr) +
+ IPX_SKB_CB(skb)->last_hop.index *
+ sizeof(u32));
+ *last_hop = IPX_SKB_CB(skb)->last_hop.netnum;
+ IPX_SKB_CB(skb)->last_hop.index = -1;
+ }
/*
* We need to know how many skbuffs it will take to send out this
@@ -702,7 +722,7 @@ static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
* up clones.
*/
- if (cb->ipx_dest_net == intrfc->if_netnum) {
+ if (ipx->ipx_dest.net == intrfc->if_netnum) {
/*
* To our own node, loop and free the original.
* The internal net will receive on all node address.
@@ -731,7 +751,7 @@ static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
* We are still charging the sender. Which is right - the driver
* free will handle this fairly.
*/
- if (cb->ipx_source_net != intrfc->if_netnum) {
+ if (ipx->ipx_source.net != intrfc->if_netnum) {
/*
* Unshare the buffer before modifying the count in
* case its a flood or tcpdump
@@ -739,7 +759,7 @@ static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
skb = skb_unshare(skb, GFP_ATOMIC);
if (!skb)
return 0;
- if (++(cb->ipx_tctrl) > ipxcfg_max_hops)
+ if (++ipx->ipx_tctrl > ipxcfg_max_hops)
send_to_wire = 0;
}
@@ -760,17 +780,6 @@ static int ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
if (!skb)
return 0;
- ipx->ipx_tctrl = cb->ipx_tctrl;
- ipx->ipx_dest.net = cb->ipx_dest_net;
- ipx->ipx_source.net = cb->ipx_source_net;
- /* see if we need to include the netnum in the route list */
- if (cb->last_hop_index >= 0) {
- u32 *last_hop = (u32 *)(((u8 *) skb->data) +
- sizeof(struct ipxhdr) + cb->last_hop_index *
- sizeof(u32));
- *last_hop = intrfc->if_netnum;
- }
-
/* set up data link and physical headers */
skb->dev = dev;
skb->protocol = htons(ETH_P_IPX);
@@ -790,93 +799,40 @@ static int ipxitf_add_local_route(ipx_interface *intrfc)
static const char * ipx_frame_name(unsigned short);
static const char * ipx_device_name(ipx_interface *);
+static void ipxitf_discover_netnum(ipx_interface *intrfc, struct sk_buff *skb);
+static int ipxitf_pprop(ipx_interface *intrfc, struct sk_buff *skb);
static int ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
{
struct ipxhdr *ipx = skb->nh.ipxh;
- struct ipx_cb *cb = (struct ipx_cb *) skb->cb;
int ret = 0;
ipxitf_hold(intrfc);
/* See if we should update our network number */
- if (!intrfc->if_netnum && /* net number of intrfc not known yet */
- cb->ipx_source_net == cb->ipx_dest_net && /* intra packet */
- cb->ipx_source_net) {
- ipx_interface *i = ipxitf_find_using_net(cb->ipx_source_net);
- /* NB: NetWare servers lie about their hop count so we
- * dropped the test based on it. This is the best way
- * to determine this is a 0 hop count packet.
- */
- if (!i) {
- intrfc->if_netnum = cb->ipx_source_net;
- ipxitf_add_local_route(intrfc);
- } else {
- printk(KERN_WARNING "IPX: Network number collision %lx\n %s %s and %s %s\n",
- (long unsigned int) htonl(cb->ipx_source_net),
- ipx_device_name(i),
- ipx_frame_name(i->if_dlink_type),
- ipx_device_name(intrfc),
- ipx_frame_name(intrfc->if_dlink_type));
- ipxitf_put(i);
- }
- }
+ if (!intrfc->if_netnum) /* net number of intrfc not known yet */
+ ipxitf_discover_netnum(intrfc, skb);
- cb->last_hop_index = -1;
-
- if (ipx->ipx_type == IPX_TYPE_PPROP && cb->ipx_tctrl < 8 &&
- skb->pkt_type != PACKET_OTHERHOST &&
- /* header + 8 network numbers */
- ntohs(ipx->ipx_pktsize) >= sizeof(struct ipxhdr) + 8 * 4) {
- int i;
- ipx_interface *ifcs;
- struct sk_buff *skb2;
- char *c = ((char *) skb->data) + sizeof(struct ipxhdr);
- u32 *l = (u32 *) c;
-
- /* Dump packet if already seen this net */
- for (i = 0; i < cb->ipx_tctrl; i++)
- if (*l++ == intrfc->if_netnum)
- break;
-
- if (i == cb->ipx_tctrl) {
- /* < 8 hops && input itfc not in list */
- /* insert recvd netnum into list */
- cb->last_hop_index = i;
- cb->ipx_tctrl++;
- /* xmit on all other interfaces... */
- spin_lock_bh(&ipx_interfaces_lock);
- for (ifcs = ipx_interfaces; ifcs;
- ifcs = ifcs->if_next) {
- /* Except unconfigured interfaces */
- if (!ifcs->if_netnum)
- continue;
-
- /* That aren't in the list */
- l = (__u32 *) c;
- for (i = 0; i <= cb->ipx_tctrl; i++)
- if (ifcs->if_netnum == *l++)
- break;
- if (i - 1 == cb->ipx_tctrl) {
- cb->ipx_dest_net = ifcs->if_netnum;
- skb2=skb_clone(skb, GFP_ATOMIC);
- if (skb2)
- ipxrtr_route_skb(skb2);
- }
- }
- spin_unlock_bh(&ipx_interfaces_lock);
- }
+ IPX_SKB_CB(skb)->last_hop.index = -1;
+ if (ipx->ipx_type == IPX_TYPE_PPROP) {
+ ret = ipxitf_pprop(intrfc, skb);
+ if (ret)
+ goto out_free_skb;
}
- if (!cb->ipx_dest_net)
- cb->ipx_dest_net = intrfc->if_netnum;
- if (!cb->ipx_source_net)
- cb->ipx_source_net = intrfc->if_netnum;
+ /* local processing follows */
+ if (!IPX_SKB_CB(skb)->ipx_dest_net)
+ IPX_SKB_CB(skb)->ipx_dest_net = intrfc->if_netnum;
+ if (!IPX_SKB_CB(skb)->ipx_source_net)
+ IPX_SKB_CB(skb)->ipx_source_net = intrfc->if_netnum;
- if (intrfc->if_netnum != cb->ipx_dest_net) {
+ /* it doesn't make sense to route a pprop packet, there's no meaning
+ * in the ipx_dest_net for such packets */
+ if (ipx->ipx_type != IPX_TYPE_PPROP &&
+ intrfc->if_netnum != IPX_SKB_CB(skb)->ipx_dest_net) {
/* We only route point-to-point packets. */
if (skb->pkt_type == PACKET_HOST) {
- skb=skb_unshare(skb, GFP_ATOMIC);
+ skb = skb_unshare(skb, GFP_ATOMIC);
if (skb)
ret = ipxrtr_route_skb(skb);
goto out_intrfc;
@@ -900,6 +856,124 @@ out_intrfc:
return ret;
}
+static void ipxitf_discover_netnum(ipx_interface *intrfc, struct sk_buff *skb)
+{
+ const struct ipx_cb *cb = IPX_SKB_CB(skb);
+
+ /* see if this is an intra packet: source_net == dest_net */
+ if (cb->ipx_source_net == cb->ipx_dest_net && cb->ipx_source_net) {
+ ipx_interface *i = ipxitf_find_using_net(cb->ipx_source_net);
+ /* NB: NetWare servers lie about their hop count so we
+ * dropped the test based on it. This is the best way
+ * to determine this is a 0 hop count packet. */
+ if (!i) {
+ intrfc->if_netnum = cb->ipx_source_net;
+ ipxitf_add_local_route(intrfc);
+ } else {
+ printk(KERN_WARNING "IPX: Network number collision "
+ "%lx\n %s %s and %s %s\n",
+ (unsigned long) htonl(cb->ipx_source_net),
+ ipx_device_name(i),
+ ipx_frame_name(i->if_dlink_type),
+ ipx_device_name(intrfc),
+ ipx_frame_name(intrfc->if_dlink_type));
+ ipxitf_put(i);
+ }
+ }
+}
+
+/**
+ * ipxitf_pprop - Process packet propagation IPX packet type 0x14, used for
+ * NetBIOS broadcasts
+ * @intrfc: IPX interface receiving this packet
+ * @skb: Received packet
+ *
+ * Checks if packet is valid: if its more than %IPX_MAX_PPROP_HOPS hops or if it
+ * is smaller than a IPX header + the room for %IPX_MAX_PPROP_HOPS hops we drop
+ * it, not even processing it locally, if it has exact %IPX_MAX_PPROP_HOPS we
+ * don't broadcast it, but process it locally. See chapter 5 of Novell's "IPX
+ * RIP and SAP Router Specification", Part Number 107-000029-001.
+ *
+ * If it is valid, check if we have pprop broadcasting enabled by the user,
+ * if not, just return zero for local processing.
+ *
+ * If it is enabled check the packet and don't broadcast it if we have already
+ * seen this packet.
+ *
+ * Broadcast: send it to the interfaces that aren't on the packet visited nets
+ * array, just after the IPX header.
+ *
+ * Returns -EINVAL for invalid packets, so that the calling function drops
+ * the packet without local processing. 0 if packet is to be locally processed.
+ */
+static int ipxitf_pprop(ipx_interface *intrfc, struct sk_buff *skb)
+{
+ struct ipxhdr *ipx = skb->nh.ipxh;
+ int i, ret = -EINVAL;
+ ipx_interface *ifcs;
+ char *c;
+ u32 *l;
+
+ /* Illegal packet - too many hops or too short */
+ /* We decide to throw it away: no broadcasting, no local processing.
+ * NetBIOS unaware implementations route them as normal packets -
+ * tctrl <= 15, any data payload... */
+ if (IPX_SKB_CB(skb)->ipx_tctrl > IPX_MAX_PPROP_HOPS ||
+ ntohs(ipx->ipx_pktsize) < sizeof(struct ipxhdr) +
+ IPX_MAX_PPROP_HOPS * sizeof(u32))
+ goto out;
+ /* are we broadcasting this damn thing? */
+ ret = 0;
+ if (!sysctl_ipx_pprop_broadcasting)
+ goto out;
+ /* We do broadcast packet on the IPX_MAX_PPROP_HOPS hop, but we
+ * process it locally. All previous hops broadcasted it, and process it
+ * locally. */
+ if (IPX_SKB_CB(skb)->ipx_tctrl == IPX_MAX_PPROP_HOPS)
+ goto out;
+
+ c = ((u8 *) ipx) + sizeof(struct ipxhdr);
+ l = (u32 *) c;
+
+ /* Don't broadcast packet if already seen this net */
+ for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++)
+ if (*l++ == intrfc->if_netnum)
+ goto out;
+
+ /* < IPX_MAX_PPROP_HOPS hops && input interface not in list. Save the
+ * position where we will insert recvd netnum into list, later on,
+ * in ipxitf_send */
+ IPX_SKB_CB(skb)->last_hop.index = i;
+ IPX_SKB_CB(skb)->last_hop.netnum = intrfc->if_netnum;
+ /* xmit on all other interfaces... */
+ spin_lock_bh(&ipx_interfaces_lock);
+ for (ifcs = ipx_interfaces; ifcs; ifcs = ifcs->if_next) {
+ /* Except unconfigured interfaces */
+ if (!ifcs->if_netnum)
+ continue;
+
+ /* That aren't in the list */
+ if (ifcs == intrfc)
+ continue;
+ l = (__u32 *) c;
+ /* don't consider the last entry in the packet list,
+ * it is our netnum, and it is not there yet */
+ for (i = 0; i < IPX_SKB_CB(skb)->ipx_tctrl; i++)
+ if (ifcs->if_netnum == *l++)
+ break;
+ if (i == IPX_SKB_CB(skb)->ipx_tctrl) {
+ struct sk_buff *s = skb_copy(skb, GFP_ATOMIC);
+
+ if (s) {
+ IPX_SKB_CB(s)->ipx_dest_net = ifcs->if_netnum;
+ ipxrtr_route_skb(s);
+ }
+ }
+ }
+ spin_unlock_bh(&ipx_interfaces_lock);
+out: return ret;
+}
+
static void ipxitf_insert(ipx_interface *intrfc)
{
ipx_interface *i;
@@ -919,6 +993,30 @@ static void ipxitf_insert(ipx_interface *intrfc)
ipx_primary_net = intrfc;
}
+static ipx_interface *ipxitf_alloc(struct net_device *dev, __u32 netnum,
+ unsigned short dlink_type,
+ struct datalink_proto *dlink,
+ unsigned char internal, int ipx_offset)
+{
+ ipx_interface *intrfc = kmalloc(sizeof(ipx_interface), GFP_ATOMIC);
+
+ if (intrfc) {
+ intrfc->if_dev = dev;
+ intrfc->if_netnum = netnum;
+ intrfc->if_dlink_type = dlink_type;
+ intrfc->if_dlink = dlink;
+ intrfc->if_internal = internal;
+ intrfc->if_ipx_offset = ipx_offset;
+ intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET;
+ intrfc->if_sklist = NULL;
+ atomic_set(&intrfc->refcnt, 1);
+ spin_lock_init(&intrfc->if_sklist_lock);
+ MOD_INC_USE_COUNT;
+ }
+
+ return intrfc;
+}
+
static int ipxitf_create_internal(ipx_interface_definition *idef)
{
ipx_interface *intrfc;
@@ -936,23 +1034,11 @@ static int ipxitf_create_internal(ipx_interface_definition *idef)
ipxitf_put(intrfc);
return -EADDRINUSE;
}
-
- intrfc = kmalloc(sizeof(ipx_interface),GFP_ATOMIC);
+ intrfc = ipxitf_alloc(NULL, idef->ipx_network, 0, NULL, 1, 0);
if (!intrfc)
return -EAGAIN;
- intrfc->if_dev = NULL;
- intrfc->if_netnum = idef->ipx_network;
- intrfc->if_dlink_type = 0;
- intrfc->if_dlink = NULL;
- intrfc->if_sklist = NULL;
- intrfc->if_internal = 1;
- intrfc->if_ipx_offset = 0;
- intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET;
memcpy((char *)&(intrfc->if_node), idef->ipx_node, IPX_NODE_LEN);
ipx_internal_net = ipx_primary_net = intrfc;
- spin_lock_init(&intrfc->if_sklist_lock);
- atomic_set(&intrfc->refcnt, 1);
- MOD_INC_USE_COUNT;
ipxitf_hold(intrfc);
ipxitf_insert(intrfc);
@@ -1041,7 +1127,8 @@ static int ipxitf_create(ipx_interface_definition *idef)
case IPX_FRAME_NONE:
default:
- break;
+ err = -EPROTONOSUPPORT;
+ goto out_dev;
}
err = -ENETDOWN;
@@ -1053,28 +1140,18 @@ static int ipxitf_create(ipx_interface_definition *idef)
if (dev->addr_len > IPX_NODE_LEN)
goto out_dev;
- err = -EPROTONOSUPPORT;
- if (!datalink)
- goto out_dev;
-
intrfc = ipxitf_find_using_phys(dev, dlink_type);
if (!intrfc) {
/* Ok now create */
- intrfc = kmalloc(sizeof(ipx_interface), GFP_ATOMIC);
+ intrfc = ipxitf_alloc(dev, idef->ipx_network, dlink_type,
+ datalink, 0, dev->hard_header_len +
+ datalink->header_length);
err = -EAGAIN;
if (!intrfc)
goto out_dev;
- intrfc->if_dev = dev;
- intrfc->if_netnum = idef->ipx_network;
- intrfc->if_dlink_type = dlink_type;
- intrfc->if_dlink = datalink;
- intrfc->if_sklist = NULL;
- intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET;
/* Setup primary if necessary */
if (idef->ipx_special == IPX_PRIMARY)
ipx_primary_net = intrfc;
- intrfc->if_internal = 0;
- intrfc->if_ipx_offset = dev->hard_header_len + datalink->header_length;
if (!memcmp(idef->ipx_node, "\000\000\000\000\000\000",
IPX_NODE_LEN)) {
memset(intrfc->if_node, 0, IPX_NODE_LEN);
@@ -1082,9 +1159,6 @@ static int ipxitf_create(ipx_interface_definition *idef)
dev->dev_addr, dev->addr_len);
} else
memcpy(intrfc->if_node, idef->ipx_node, IPX_NODE_LEN);
- spin_lock_init(&intrfc->if_sklist_lock);
- atomic_set(&intrfc->refcnt, 1);
- MOD_INC_USE_COUNT;
ipxitf_hold(intrfc);
ipxitf_insert(intrfc);
}
@@ -1146,8 +1220,15 @@ out: spin_unlock_bh(&ipx_interfaces_lock);
static ipx_interface *ipxitf_auto_create(struct net_device *dev,
unsigned short dlink_type)
{
- struct datalink_proto *datalink = NULL;
- ipx_interface *intrfc;
+ ipx_interface *intrfc = NULL;
+ struct datalink_proto *datalink;
+
+ if (!dev)
+ goto out;
+
+ /* Check addresses are suitable */
+ if (dev->addr_len > IPX_NODE_LEN)
+ goto out;
switch (htons(dlink_type)) {
case ETH_P_IPX:
@@ -1167,38 +1248,23 @@ static ipx_interface *ipxitf_auto_create(struct net_device *dev,
break;
default:
- return NULL;
+ goto out;
}
- if (!dev)
- return NULL;
-
- /* Check addresses are suitable */
- if (dev->addr_len > IPX_NODE_LEN)
- return NULL;
+ intrfc = ipxitf_alloc(dev, 0, dlink_type, datalink, 0,
+ dev->hard_header_len + datalink->header_length);
- intrfc = kmalloc(sizeof(ipx_interface), GFP_ATOMIC);
if (intrfc) {
- intrfc->if_dev = dev;
- intrfc->if_netnum = 0;
- intrfc->if_dlink_type = dlink_type;
- intrfc->if_dlink = datalink;
- intrfc->if_sklist = NULL;
- intrfc->if_internal = 0;
- intrfc->if_sknum = IPX_MIN_EPHEMERAL_SOCKET;
- intrfc->if_ipx_offset = dev->hard_header_len +
- datalink->header_length;
memset(intrfc->if_node, 0, IPX_NODE_LEN);
memcpy((char *)&(intrfc->if_node[IPX_NODE_LEN-dev->addr_len]),
dev->dev_addr, dev->addr_len);
spin_lock_init(&intrfc->if_sklist_lock);
atomic_set(&intrfc->refcnt, 1);
- MOD_INC_USE_COUNT;
ipxitf_insert(intrfc);
dev_hold(dev);
}
- return intrfc;
+out: return intrfc;
}
static int ipxitf_ioctl(unsigned int cmd, void *arg)
@@ -1284,6 +1350,17 @@ static int ipxitf_ioctl(unsigned int cmd, void *arg)
* *
\**************************************************************************/
+static inline void ipxrtr_hold(ipx_route *rt)
+{
+ atomic_inc(&rt->refcnt);
+}
+
+static inline void ipxrtr_put(ipx_route *rt)
+{
+ if (atomic_dec_and_test(&rt->refcnt))
+ kfree(rt);
+}
+
static ipx_route *ipxrtr_lookup(__u32 net)
{
ipx_route *r;
@@ -1291,6 +1368,8 @@ static ipx_route *ipxrtr_lookup(__u32 net)
read_lock_bh(&ipx_routes_lock);
for (r = ipx_routes; r && r->ir_net != net; r = r->ir_next)
;
+ if (r)
+ ipxrtr_hold(r);
read_unlock_bh(&ipx_routes_lock);
return r;
@@ -1301,21 +1380,27 @@ static ipx_route *ipxrtr_lookup(__u32 net)
static int ipxrtr_add_route(__u32 network, ipx_interface *intrfc, unsigned char *node)
{
ipx_route *rt;
+ int ret;
/* Get a route structure; either existing or create */
rt = ipxrtr_lookup(network);
if (!rt) {
rt = kmalloc(sizeof(ipx_route),GFP_ATOMIC);
+ ret = -EAGAIN;
if (!rt)
- return -EAGAIN;
+ goto out;
+ atomic_set(&rt->refcnt, 1);
+ ipxrtr_hold(rt);
write_lock_bh(&ipx_routes_lock);
rt->ir_next = ipx_routes;
ipx_routes = rt;
write_unlock_bh(&ipx_routes_lock);
+ } else {
+ ret = -EEXIST;
+ if (intrfc == ipx_internal_net)
+ goto out_put;
}
- else if (intrfc == ipx_internal_net)
- return -EEXIST;
rt->ir_net = network;
rt->ir_intrfc = intrfc;
@@ -1327,7 +1412,10 @@ static int ipxrtr_add_route(__u32 network, ipx_interface *intrfc, unsigned char
rt->ir_routed = 1;
}
- return 0;
+ ret = 0;
+out_put:
+ ipxrtr_put(rt);
+out: return ret;
}
static void ipxrtr_del_routes(ipx_interface *intrfc)
@@ -1338,7 +1426,7 @@ static void ipxrtr_del_routes(ipx_interface *intrfc)
for (r = &ipx_routes; (tmp = *r) != NULL;) {
if (tmp->ir_intrfc == intrfc) {
*r = tmp->ir_next;
- kfree(tmp);
+ ipxrtr_put(tmp);
} else
r = &(tmp->ir_next);
}
@@ -1374,7 +1462,7 @@ static int ipxrtr_delete(long net)
goto out;
*r = tmp->ir_next;
- kfree(tmp);
+ ipxrtr_put(tmp);
err = 0;
goto out;
}
@@ -1433,7 +1521,6 @@ static int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx, stru
struct sk_buff *skb;
ipx_interface *intrfc;
struct ipxhdr *ipx;
- struct ipx_cb *cb;
int size;
int ipx_offset;
ipx_route *rt = NULL;
@@ -1445,9 +1532,9 @@ static int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx, stru
intrfc = ipx_primary_net;
} else {
rt = ipxrtr_lookup(usipx->sipx_network);
+ err = -ENETUNREACH;
if (!rt)
- return -ENETUNREACH;
-
+ goto out;
intrfc = rt->ir_intrfc;
}
@@ -1455,47 +1542,46 @@ static int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx, stru
ipx_offset = intrfc->if_ipx_offset;
size = sizeof(struct ipxhdr) + len + ipx_offset;
- skb = sock_alloc_send_skb(sk, size, 0, noblock, &err);
+ skb = sock_alloc_send_skb(sk, size, noblock, &err);
if (!skb)
- goto out;
+ goto out_put;
skb_reserve(skb,ipx_offset);
skb->sk = sk;
- cb = (struct ipx_cb *) skb->cb;
/* Fill in IPX header */
ipx = (struct ipxhdr *)skb_put(skb, sizeof(struct ipxhdr));
ipx->ipx_pktsize= htons(len + sizeof(struct ipxhdr));
- cb->ipx_tctrl = 0;
+ IPX_SKB_CB(skb)->ipx_tctrl = 0;
ipx->ipx_type = usipx->sipx_type;
skb->h.raw = (void *)skb->nh.ipxh = ipx;
- cb->last_hop_index = -1;
-
+ IPX_SKB_CB(skb)->last_hop.index = -1;
#ifdef CONFIG_IPX_INTERN
- cb->ipx_source_net = sk->protinfo.af_ipx.intrfc->if_netnum;
+ IPX_SKB_CB(skb)->ipx_source_net = sk->protinfo.af_ipx.intrfc->if_netnum;
memcpy(ipx->ipx_source.node, sk->protinfo.af_ipx.node, IPX_NODE_LEN);
#else
err = ntohs(sk->protinfo.af_ipx.port);
if (err == 0x453 || err == 0x452) {
/* RIP/SAP special handling for mars_nwe */
- cb->ipx_source_net = intrfc->if_netnum;
+ IPX_SKB_CB(skb)->ipx_source_net = intrfc->if_netnum;
memcpy(ipx->ipx_source.node, intrfc->if_node, IPX_NODE_LEN);
} else {
- cb->ipx_source_net = sk->protinfo.af_ipx.intrfc->if_netnum;
+ IPX_SKB_CB(skb)->ipx_source_net =
+ sk->protinfo.af_ipx.intrfc->if_netnum;
memcpy(ipx->ipx_source.node, sk->protinfo.af_ipx.intrfc->if_node, IPX_NODE_LEN);
}
#endif /* CONFIG_IPX_INTERN */
ipx->ipx_source.sock = sk->protinfo.af_ipx.port;
- cb->ipx_dest_net = usipx->sipx_network;
+ IPX_SKB_CB(skb)->ipx_dest_net = usipx->sipx_network;
memcpy(ipx->ipx_dest.node,usipx->sipx_node,IPX_NODE_LEN);
ipx->ipx_dest.sock = usipx->sipx_port;
err = memcpy_fromiovec(skb_put(skb,len),iov,len);
if (err) {
kfree_skb(skb);
- goto out;
+ goto out_put;
}
/* Apply checksum. Not allowed on 802.3 links. */
@@ -1506,15 +1592,19 @@ static int ipxrtr_route_packet(struct sock *sk, struct sockaddr_ipx *usipx, stru
err = ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ?
rt->ir_router_node : ipx->ipx_dest.node);
-out: ipxitf_put(intrfc);
- return err;
+out_put:
+ ipxitf_put(intrfc);
+ if (rt)
+ ipxrtr_put(rt);
+out: return err;
}
-
+
+/* the skb has to be unshared, we'll end up calling ipxitf_send, that'll
+ * modify the packet */
int ipxrtr_route_skb(struct sk_buff *skb)
{
struct ipxhdr *ipx = skb->nh.ipxh;
- struct ipx_cb *cb = (struct ipx_cb *) skb->cb;
- ipx_route *r = ipxrtr_lookup(cb->ipx_dest_net);
+ ipx_route *r = ipxrtr_lookup(IPX_SKB_CB(skb)->ipx_dest_net);
if (!r) { /* no known route */
kfree_skb(skb);
@@ -1525,6 +1615,7 @@ int ipxrtr_route_skb(struct sk_buff *skb)
ipxitf_send(r->ir_intrfc, skb, (r->ir_routed) ?
r->ir_router_node : ipx->ipx_dest.node);
ipxitf_put(r->ir_intrfc);
+ ipxrtr_put(r);
return 0;
}
@@ -2034,6 +2125,7 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
{
struct sock *sk = sock->sk;
struct sockaddr_ipx *addr;
+ ipx_route *rt;
sk->state = TCP_CLOSE;
sock->state = SS_UNCONNECTED;
@@ -2065,8 +2157,8 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
/* We can either connect to primary network or somewhere
* we can route to */
- if (!(!addr->sipx_network && ipx_primary_net) &&
- !ipxrtr_lookup(addr->sipx_network))
+ rt = ipxrtr_lookup(addr->sipx_network);
+ if (!rt && !(!addr->sipx_network && ipx_primary_net))
return -ENETUNREACH;
sk->protinfo.af_ipx.dest_addr.net = addr->sipx_network;
@@ -2080,6 +2172,8 @@ static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
sk->state = TCP_ESTABLISHED;
}
+ if (rt)
+ ipxrtr_put(rt);
return 0;
}
@@ -2130,7 +2224,6 @@ int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
/* NULL here for pt means the packet was looped back */
ipx_interface *intrfc;
struct ipxhdr *ipx;
- struct ipx_cb *cb;
u16 ipx_pktsize;
int ret;
@@ -2152,21 +2245,22 @@ int ipx_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)
ipx->ipx_checksum != ipx_cksum(ipx, ipx_pktsize))
goto drop;
- cb = (struct ipx_cb *) skb->cb;
- cb->ipx_tctrl = ipx->ipx_tctrl;
- cb->ipx_dest_net = ipx->ipx_dest.net;
- cb->ipx_source_net = ipx->ipx_source.net;
+ IPX_SKB_CB(skb)->ipx_tctrl = ipx->ipx_tctrl;
+ IPX_SKB_CB(skb)->ipx_dest_net = ipx->ipx_dest.net;
+ IPX_SKB_CB(skb)->ipx_source_net = ipx->ipx_source.net;
/* Determine what local ipx endpoint this is */
intrfc = ipxitf_find_using_phys(dev, pt->type);
if (!intrfc) {
if (ipxcfg_auto_create_interfaces &&
- ntohl(cb->ipx_dest_net)) {
+ ntohl(IPX_SKB_CB(skb)->ipx_dest_net)) {
intrfc = ipxitf_auto_create(dev, pt->type);
- ipxitf_hold(intrfc);
+ if (intrfc)
+ ipxitf_hold(intrfc);
}
if (!intrfc) /* Not one of ours */
+ /* or invalid packet for auto creation */
goto drop;
}
@@ -2291,11 +2385,10 @@ static int ipx_recvmsg(struct socket *sock, struct msghdr *msg, int size,
msg->msg_namelen = sizeof(*sipx);
if (sipx) {
- struct ipx_cb *cb = (struct ipx_cb *) skb->cb;
sipx->sipx_family = AF_IPX;
sipx->sipx_port = ipx->ipx_source.sock;
memcpy(sipx->sipx_node,ipx->ipx_source.node,IPX_NODE_LEN);
- sipx->sipx_network = cb->ipx_source_net;
+ sipx->sipx_network = IPX_SKB_CB(skb)->ipx_source_net;
sipx->sipx_type = ipx->ipx_type;
}
err = copied;
@@ -2438,6 +2531,7 @@ static struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
sendmsg: ipx_sendmsg,
recvmsg: ipx_recvmsg,
mmap: sock_no_mmap,
+ sendpage: sock_no_sendpage,
};
#include <linux/smp_lock.h>
@@ -2470,6 +2564,10 @@ 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 };
+static const char banner[] __initdata =
+ KERN_INFO "NET4: Linux IPX 0.46 for NET4.0\n"
+ KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n" \
+ KERN_INFO "IPX Portions Copyright (c) 2000, 2001 Conectiva, Inc.\n";
static int __init ipx_init(void)
{
@@ -2490,14 +2588,13 @@ static int __init ipx_init(void)
printk(KERN_CRIT "IPX: Unable to register with SNAP\n");
register_netdevice_notifier(&ipx_dev_notifier);
+ ipx_register_sysctl();
#ifdef CONFIG_PROC_FS
proc_net_create("ipx", 0, ipx_get_info);
proc_net_create("ipx_interface", 0, ipx_interface_get_info);
proc_net_create("ipx_route", 0, ipx_rt_get_info);
#endif
- printk(KERN_INFO "NET4: Linux IPX 0.44 for NET4.0\n");
- printk(KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n");
- printk(KERN_INFO "IPX Portions Copyright (c) 2000 Conectiva, Inc.\n");
+ printk(banner);
return 0;
}
@@ -2507,8 +2604,13 @@ module_init(ipx_init);
int ipx_if_offset(unsigned long ipx_net_number)
{
ipx_route *rt = ipxrtr_lookup(ipx_net_number);
+ int ret = -ENETUNREACH;
- return rt ? rt->ir_intrfc->if_ipx_offset : -ENETUNREACH;
+ if (!rt)
+ goto out;
+ ret = rt->ir_intrfc->if_ipx_offset;
+ ipxrtr_put(rt);
+out: return ret;
}
/* Export symbols for higher layers */
@@ -2531,8 +2633,7 @@ EXPORT_SYMBOL(ipx_unregister_spx);
* sockets be closed from user space.
*/
-#ifdef MODULE
-static void ipx_proto_finito(void)
+static void __exit ipx_proto_finito(void)
{
/* no need to worry about having anything on the ipx_interfaces
* list, when a interface is created we increment the module
@@ -2542,6 +2643,7 @@ static void ipx_proto_finito(void)
proc_net_remove("ipx_route");
proc_net_remove("ipx_interface");
proc_net_remove("ipx");
+ ipx_unregister_sysctl();
unregister_netdevice_notifier(&ipx_dev_notifier);
@@ -2563,5 +2665,3 @@ static void ipx_proto_finito(void)
}
module_exit(ipx_proto_finito);
-#endif /* MODULE */
-#endif /* CONFIG_IPX || CONFIG_IPX_MODULE */
diff --git a/net/ipx/sysctl_net_ipx.c b/net/ipx/sysctl_net_ipx.c
index c699d6ff0a97..f28943f0edc7 100644
--- a/net/ipx/sysctl_net_ipx.c
+++ b/net/ipx/sysctl_net_ipx.c
@@ -3,11 +3,51 @@
*
* Begun April 1, 1996, Mike Shaver.
* Added /proc/sys/net/ipx directory entry (empty =) ). [MS]
+ * Added /proc/sys/net/ipx/ipx_pprop_broadcasting - acme March 4, 2001
*/
#include <linux/mm.h>
#include <linux/sysctl.h>
+/* From af_ipx.c */
+extern int sysctl_ipx_pprop_broadcasting;
+
+#ifdef CONFIG_SYSCTL
ctl_table ipx_table[] = {
- {0}
+ { NET_IPX_PPROP_BROADCASTING, "ipx_pprop_broadcasting",
+ &sysctl_ipx_pprop_broadcasting, sizeof(int), 0644, NULL,
+ &proc_dointvec },
+ { 0 }
+};
+
+static ctl_table ipx_dir_table[] = {
+ { NET_IPX, "ipx", NULL, 0, 0555, ipx_table },
+ { 0 }
+};
+
+static ctl_table ipx_root_table[] = {
+ { CTL_NET, "net", NULL, 0, 0555, ipx_dir_table },
+ { 0 }
};
+
+static struct ctl_table_header *ipx_table_header;
+
+void ipx_register_sysctl(void)
+{
+ ipx_table_header = register_sysctl_table(ipx_root_table, 1);
+}
+
+void ipx_unregister_sysctl(void)
+{
+ unregister_sysctl_table(ipx_table_header);
+}
+
+#else
+void ipx_register_sysctl(void)
+{
+}
+
+void ipx_unregister_sysctl(void)
+{
+}
+#endif
diff --git a/net/khttpd/main.c b/net/khttpd/main.c
index 2ade82be2685..c0b4da1635e7 100644
--- a/net/khttpd/main.c
+++ b/net/khttpd/main.c
@@ -138,7 +138,7 @@ static int MainDaemon(void *cpu_pointer)
changes +=DataSending(CPUNR);
changes +=Userspace(CPUNR);
changes +=Logging(CPUNR);
- /* Test for incomming connections _again_, because it is possible
+ /* Test for incoming connections _again_, because it is possible
one came in during the other steps, and the wakeup doesn't happen
then.
*/
diff --git a/net/khttpd/rfc.c b/net/khttpd/rfc.c
index c2629682ac6f..a9f2491781e9 100644
--- a/net/khttpd/rfc.c
+++ b/net/khttpd/rfc.c
@@ -101,7 +101,7 @@ char *ResolveMimeType(const char *File,__kernel_size_t *Len)
/*
The returned string is for READ ONLY, ownership of the memory is NOT
- transfered.
+ transferred.
*/
{
diff --git a/net/netsyms.c b/net/netsyms.c
index 52b98f4e1a8c..8adcef849acf 100644
--- a/net/netsyms.c
+++ b/net/netsyms.c
@@ -432,17 +432,7 @@ EXPORT_SYMBOL(arp_find);
#endif /* CONFIG_INET */
#ifdef CONFIG_TR
-EXPORT_SYMBOL(tr_setup);
EXPORT_SYMBOL(tr_type_trans);
-EXPORT_SYMBOL(register_trdev);
-EXPORT_SYMBOL(unregister_trdev);
-EXPORT_SYMBOL(init_trdev);
-#endif
-
-#ifdef CONFIG_NET_FC
-EXPORT_SYMBOL(register_fcdev);
-EXPORT_SYMBOL(unregister_fcdev);
-EXPORT_SYMBOL(init_fcdev);
#endif
/* Device callback registration */
@@ -451,14 +441,10 @@ EXPORT_SYMBOL(unregister_netdevice_notifier);
/* support for loadable net drivers */
#ifdef CONFIG_NET
-EXPORT_SYMBOL(init_etherdev);
EXPORT_SYMBOL(loopback_dev);
EXPORT_SYMBOL(register_netdevice);
EXPORT_SYMBOL(unregister_netdevice);
-EXPORT_SYMBOL(register_netdev);
-EXPORT_SYMBOL(unregister_netdev);
EXPORT_SYMBOL(netdev_state_change);
-EXPORT_SYMBOL(ether_setup);
EXPORT_SYMBOL(dev_new_index);
EXPORT_SYMBOL(dev_get_by_index);
EXPORT_SYMBOL(__dev_get_by_index);
@@ -469,8 +455,6 @@ EXPORT_SYMBOL(netdev_set_master);
EXPORT_SYMBOL(eth_type_trans);
#ifdef CONFIG_FDDI
EXPORT_SYMBOL(fddi_type_trans);
-EXPORT_SYMBOL(fddi_setup);
-EXPORT_SYMBOL(init_fddidev);
#endif /* CONFIG_FDDI */
#if 0
EXPORT_SYMBOL(eth_copy_and_sum);
@@ -511,8 +495,6 @@ EXPORT_SYMBOL(if_port_text);
#ifdef CONFIG_HIPPI
EXPORT_SYMBOL(hippi_type_trans);
-EXPORT_SYMBOL(init_hippi_dev);
-EXPORT_SYMBOL(unregister_hipdev);
#endif
#ifdef CONFIG_SYSCTL
@@ -523,12 +505,6 @@ EXPORT_SYMBOL(sysctl_ip_default_ttl);
#endif
#endif
-#if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE)
-#include<linux/if_ltalk.h>
-EXPORT_SYMBOL(ltalk_setup);
-#endif
-
-
/* Packet scheduler modules want these. */
EXPORT_SYMBOL(qdisc_destroy);
EXPORT_SYMBOL(qdisc_reset);
diff --git a/net/sched/cls_tcindex.c b/net/sched/cls_tcindex.c
index c8673269c8b1..750eb46722db 100644
--- a/net/sched/cls_tcindex.c
+++ b/net/sched/cls_tcindex.c
@@ -76,7 +76,7 @@ static struct tcindex_filter_result *lookup(struct tcindex_data *p,__u16 key)
struct tcindex_filter *f;
if (p->perfect)
- return p->perfect[key].res.classid ? p->perfect+key : NULL;
+ return p->perfect[key].res.class ? p->perfect+key : NULL;
if (!p->h)
return NULL;
for (f = p->h[key % p->hash]; f; f = f->next) {
@@ -122,8 +122,14 @@ static int tcindex_classify(struct sk_buff *skb, struct tcf_proto *tp,
static unsigned long tcindex_get(struct tcf_proto *tp, u32 handle)
{
+ struct tcindex_data *p = PRIV(tp);
+ struct tcindex_filter_result *r;
+
DPRINTK("tcindex_get(tp %p,handle 0x%08x)\n",tp,handle);
- return (unsigned long) lookup(PRIV(tp),handle);
+ if (p->perfect && handle >= p->alloc_hash)
+ return 0;
+ r = lookup(PRIV(tp),handle);
+ return r && r->res.class ? (unsigned long) r : 0;
}
@@ -164,7 +170,7 @@ static int tcindex_delete(struct tcf_proto *tp, unsigned long arg)
DPRINTK("tcindex_delete(tp %p,arg 0x%lx),p %p,f %p\n",tp,arg,p,f);
if (p->perfect) {
- if (!r->res.classid)
+ if (!r->res.class)
return -ENOENT;
} else {
int i;
@@ -212,7 +218,7 @@ static int tcindex_change(struct tcf_proto *tp,unsigned long base,u32 handle,
struct tcindex_filter *f;
struct tcindex_filter_result *r = (struct tcindex_filter_result *) *arg;
struct tcindex_filter **walk;
- int hash;
+ int hash,shift;
__u16 mask;
DPRINTK("tcindex_change(tp %p,handle 0x%08x,tca %p,arg %p),opt %p,"
@@ -237,17 +243,22 @@ static int tcindex_change(struct tcf_proto *tp,unsigned long base,u32 handle,
return -EINVAL;
mask = *(__u16 *) RTA_DATA(tb[TCA_TCINDEX_MASK-1]);
}
- if (p->perfect && hash <= mask)
+ if (!tb[TCA_TCINDEX_SHIFT-1])
+ shift = p->shift;
+ else {
+ if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT-1]) < sizeof(__u16))
+ return -EINVAL;
+ shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT-1]);
+ }
+ if (p->perfect && hash <= (mask >> shift))
+ return -EBUSY;
+ if (p->perfect && hash > p->alloc_hash)
return -EBUSY;
- if ((p->perfect || p->h) && hash > p->alloc_hash)
+ if (p->h && hash != p->alloc_hash)
return -EBUSY;
p->hash = hash;
p->mask = mask;
- if (tb[TCA_TCINDEX_SHIFT-1]) {
- if (RTA_PAYLOAD(tb[TCA_TCINDEX_SHIFT-1]) < sizeof(__u16))
- return -EINVAL;
- p->shift = *(int *) RTA_DATA(tb[TCA_TCINDEX_SHIFT-1]);
- }
+ p->shift = shift;
if (tb[TCA_TCINDEX_FALL_THROUGH-1]) {
if (RTA_PAYLOAD(tb[TCA_TCINDEX_FALL_THROUGH-1]) < sizeof(int))
return -EINVAL;
@@ -258,9 +269,9 @@ static int tcindex_change(struct tcf_proto *tp,unsigned long base,u32 handle,
tb[TCA_TCINDEX_POLICE-1]);
if (!tb[TCA_TCINDEX_CLASSID-1] && !tb[TCA_TCINDEX_POLICE-1])
return 0;
- if (!p->hash) {
- if (p->mask < PERFECT_HASH_THRESHOLD) {
- p->hash = p->mask+1;
+ if (!hash) {
+ if ((mask >> shift) < PERFECT_HASH_THRESHOLD) {
+ p->hash = (mask >> shift)+1;
} else {
p->hash = DEFAULT_HASH_SIZE;
}
@@ -268,7 +279,7 @@ static int tcindex_change(struct tcf_proto *tp,unsigned long base,u32 handle,
if (!p->perfect && !p->h) {
p->alloc_hash = p->hash;
DPRINTK("hash %d mask %d\n",p->hash,p->mask);
- if (p->hash > p->mask) {
+ if (p->hash > (mask >> shift)) {
p->perfect = kmalloc(p->hash*
sizeof(struct tcindex_filter_result),GFP_KERNEL);
if (!p->perfect)
@@ -283,7 +294,15 @@ static int tcindex_change(struct tcf_proto *tp,unsigned long base,u32 handle,
memset(p->h, 0, p->hash*sizeof(struct tcindex_filter *));
}
}
- if (handle > p->mask)
+ /*
+ * Note: this could be as restrictive as
+ * if (handle & ~(mask >> shift))
+ * but then, we'd fail handles that may become valid after some
+ * future mask change. While this is extremely unlikely to ever
+ * matter, the check below is safer (and also more
+ * backwards-compatible).
+ */
+ if (p->perfect && handle >= p->alloc_hash)
return -EINVAL;
if (p->perfect) {
r = p->perfect+handle;
@@ -308,17 +327,16 @@ static int tcindex_change(struct tcf_proto *tp,unsigned long base,u32 handle,
}
}
#ifdef CONFIG_NET_CLS_POLICE
- if (!tb[TCA_TCINDEX_POLICE-1]) {
- r->police = NULL;
- } else {
- struct tcf_police *police =
- tcf_police_locate(tb[TCA_TCINDEX_POLICE-1],NULL);
+ {
+ struct tcf_police *police;
- tcf_tree_lock(tp);
+ police = tb[TCA_TCINDEX_POLICE-1] ?
+ tcf_police_locate(tb[TCA_TCINDEX_POLICE-1],NULL) : NULL;
+ tcf_tree_lock(tp);
police = xchg(&r->police,police);
- tcf_tree_unlock(tp);
+ tcf_tree_unlock(tp);
tcf_police_release(police);
- }
+ }
#endif
if (r != &new_filter_result)
return 0;
@@ -345,7 +363,7 @@ static void tcindex_walk(struct tcf_proto *tp, struct tcf_walker *walker)
DPRINTK("tcindex_walk(tp %p,walker %p),p %p\n",tp,walker,p);
if (p->perfect) {
for (i = 0; i < p->hash; i++) {
- if (!p->perfect[i].res.classid)
+ if (!p->perfect[i].res.class)
continue;
if (walker->count >= walker->skip) {
if (walker->fn(tp,
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index 5d21c5e17861..a0c2d7585a6e 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -1740,9 +1740,13 @@ cbq_destroy(struct Qdisc* sch)
}
for (h = 0; h < 16; h++) {
- for (cl = q->classes[h]; cl; cl = cl->next)
+ struct cbq_class *next;
+
+ for (cl = q->classes[h]; cl; cl = next) {
+ next = cl->next;
if (cl != &q->link)
cbq_destroy_class(cl);
+ }
}
qdisc_put_rtab(q->link.R_tab);
diff --git a/net/sched/sch_dsmark.c b/net/sched/sch_dsmark.c
index d30d08896ab2..184ca0ac8fda 100644
--- a/net/sched/sch_dsmark.c
+++ b/net/sched/sch_dsmark.c
@@ -84,7 +84,9 @@ static int dsmark_graft(struct Qdisc *sch,unsigned long arg,
static struct Qdisc *dsmark_leaf(struct Qdisc *sch, unsigned long arg)
{
- return NULL;
+ struct dsmark_qdisc_data *p = PRIV(sch);
+
+ return p->q;
}
@@ -187,7 +189,7 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch)
struct dsmark_qdisc_data *p = PRIV(sch);
struct tcf_result res;
int result;
- int ret;
+ int ret = NET_XMIT_POLICED;
D2PRINTK("dsmark_enqueue(skb %p,sch %p,[qdisc %p])\n",skb,sch,p);
if (p->set_tc_index) {
@@ -237,7 +239,7 @@ static int dsmark_enqueue(struct sk_buff *skb,struct Qdisc *sch)
((ret = p->q->enqueue(skb,p->q)) != 0)) {
sch->stats.drops++;
- return 0;
+ return ret;
}
sch->stats.bytes += skb->len;
sch->stats.packets++;
diff --git a/net/sched/sch_tbf.c b/net/sched/sch_tbf.c
index 061ef312abd6..7b5248e74de7 100644
--- a/net/sched/sch_tbf.c
+++ b/net/sched/sch_tbf.c
@@ -66,7 +66,7 @@
N(t+delta) = min{B/R, N(t) + delta}
If the first packet in queue has length S, it may be
- transmited only at the time t_* when S/R <= N(t_*),
+ transmitted only at the time t_* when S/R <= N(t_*),
and in this case N(t) jumps:
N(t_* + 0) = N(t_* - 0) - S/R.
@@ -276,7 +276,7 @@ static int tbf_change(struct Qdisc* sch, struct rtattr *opt)
struct tc_tbf_qopt *qopt;
struct qdisc_rate_table *rtab = NULL;
struct qdisc_rate_table *ptab = NULL;
- int max_size;
+ int max_size,n;
if (rtattr_parse(tb, TCA_TBF_PTAB, RTA_DATA(opt), RTA_PAYLOAD(opt)) ||
tb[TCA_TBF_PARMS-1] == NULL ||
@@ -295,15 +295,18 @@ static int tbf_change(struct Qdisc* sch, struct rtattr *opt)
goto done;
}
- max_size = psched_mtu(sch->dev);
+ for (n = 0; n < 256; n++)
+ if (rtab->data[n] > qopt->buffer) break;
+ max_size = (n << qopt->rate.cell_log)-1;
if (ptab) {
- int n = max_size>>qopt->peakrate.cell_log;
- while (n>0 && ptab->data[n-1] > qopt->mtu) {
- max_size -= (1<<qopt->peakrate.cell_log);
- n--;
- }
+ int size;
+
+ for (n = 0; n < 256; n++)
+ if (ptab->data[n] > qopt->mtu) break;
+ size = (n << qopt->peakrate.cell_log)-1;
+ if (size < max_size) max_size = size;
}
- if (rtab->data[max_size>>qopt->rate.cell_log] > qopt->buffer)
+ if (max_size < 0)
goto done;
sch_tree_lock(sch);
diff --git a/net/sysctl_net.c b/net/sysctl_net.c
index 61f94839093a..23d157c61248 100644
--- a/net/sysctl_net.c
+++ b/net/sysctl_net.c
@@ -20,10 +20,6 @@
extern ctl_table ipv4_table[];
#endif
-#ifdef CONFIG_IPX
-extern ctl_table ipx_table[];
-#endif
-
extern ctl_table core_table[];
#ifdef CONFIG_NET
@@ -51,9 +47,6 @@ ctl_table net_table[] = {
#ifdef CONFIG_INET
{NET_IPV4, "ipv4", NULL, 0, 0555, ipv4_table},
#endif
-#ifdef CONFIG_IPX
- {NET_IPX, "ipx", NULL, 0, 0555, ipx_table},
-#endif
#ifdef CONFIG_IPV6
{NET_IPV6, "ipv6", NULL, 0, 0555, ipv6_table},
#endif
diff --git a/net/wanrouter/wanmain.c b/net/wanrouter/wanmain.c
index 26e3f913064c..cdb2c210e9de 100644
--- a/net/wanrouter/wanmain.c
+++ b/net/wanrouter/wanmain.c
@@ -5,7 +5,7 @@
* the following common services for the WAN Link Drivers:
* o WAN device managenment (registering, unregistering)
* o Network interface management
-* o Physical connection management (dial-up, incomming calls)
+* o Physical connection management (dial-up, incoming calls)
* o Logical connection management (switched virtual circuits)
* o Protocol encapsulation/decapsulation
*