diff options
| author | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-04 18:06:16 -0800 |
|---|---|---|
| committer | Linus Torvalds <torvalds@athlon.transmeta.com> | 2002-02-04 18:06:16 -0800 |
| commit | 8b11a705bdc5fd9f39b113f7d1dc9c8eeabe301b (patch) | |
| tree | f00c6c3accce342c055af338eaa88583e5fe3552 /net | |
| parent | 90a880a460aeb2374d6c766c08fa7786fb982aae (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.c | 1 | ||||
| -rw-r--r-- | net/core/dv.c | 2 | ||||
| -rw-r--r-- | net/decnet/af_decnet.c | 7 | ||||
| -rw-r--r-- | net/ipv4/devinet.c | 8 | ||||
| -rw-r--r-- | net/ipv4/ip_fragment.c | 13 | ||||
| -rw-r--r-- | net/ipv4/sysctl_net_ipv4.c | 5 | ||||
| -rw-r--r-- | net/ipv6/ip6_fib.c | 31 | ||||
| -rw-r--r-- | net/ipv6/ipv6_sockglue.c | 9 | ||||
| -rw-r--r-- | net/ipv6/reassembly.c | 13 | ||||
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 2 | ||||
| -rw-r--r-- | net/ipx/af_ipx.c | 474 | ||||
| -rw-r--r-- | net/ipx/sysctl_net_ipx.c | 42 | ||||
| -rw-r--r-- | net/khttpd/main.c | 2 | ||||
| -rw-r--r-- | net/khttpd/rfc.c | 2 | ||||
| -rw-r--r-- | net/netsyms.c | 24 | ||||
| -rw-r--r-- | net/sched/cls_tcindex.c | 68 | ||||
| -rw-r--r-- | net/sched/sch_cbq.c | 6 | ||||
| -rw-r--r-- | net/sched/sch_dsmark.c | 8 | ||||
| -rw-r--r-- | net/sched/sch_tbf.c | 21 | ||||
| -rw-r--r-- | net/sysctl_net.c | 7 | ||||
| -rw-r--r-- | net/wanrouter/wanmain.c | 2 |
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 * |
