summaryrefslogtreecommitdiff
path: root/pfinet/linux-inet/ipx.c
diff options
context:
space:
mode:
authorRoland McGrath <roland@gnu.org>2000-02-04 06:32:39 +0000
committerRoland McGrath <roland@gnu.org>2000-02-04 06:32:39 +0000
commitdb9a26cbd125ec106e040ea6084911f9bc0c0198 (patch)
tree8394aedf0addf9de2afd46d00c192d20d9eb9092 /pfinet/linux-inet/ipx.c
parent8880a73970b23f10c720011cb910c0e0e1e02975 (diff)
2000-02-03 Roland McGrath <roland@baalperazim.frob.com>
Complete overhaul of pfinet based on the IPv4 networking code from the Linux 2.2.12 kernel sources. This page describes a single unified set of interdependent changes, but there are so many changes that I have broken up the log entry into paragraphs based on rough topical divisions of the work involved. Subset of verbatim Linux 2.2.12 sources imported on a vendor branch. * linux-src: New directory, see README for details. * README: New file, describes linux-src layout and procedures for tracking Linux source updates. Light modifications to linux-src files to avoid really bending over backwards with the glue macros. All modifications to files in linux-src are conditionalized by #ifdef _HURD_. * linux-src/include/linux/net.h [_HURD_] (struct socket): New members refcnt and identity; elide members fasync_list, file. * linux-src/include/linux/rtnetlink.h [! CONFIG_RTNETLINK] (rtnl_shlock, rtnl_shunlock) [! _HURD_]: Conditionalize contents on this, making these no-ops #ifdef _HURD_. * linux-src/net/core/dev.c [_HURD_] (dev_ioctl): Don't define the function, instead #define it to 0. * linux-src/net/ipv4/af_inet.c [_HURD_] (inet_ioctl): Likewise. * linux-src/net/ipv4/arp.c [_HURD_] (arp_ioctl): Likewise. * linux-src/net/ipv4/udp.c [_HURD_] (udp_ioctl): Likewise. * linux-src/net/ipv4/tcp.c [_HURD_] (tcp_ioctl): Likewise. [_HURD_] (tcp_tiocinq): New function, TIOCINQ code from tcp_ioctl. * linux-src/net/ipv4/devinet.c [_HURD_] (devinet_ioctl): Don't define the function, instead #define it to 0. [_HURD_] (configure_device): New function, cobbled from SIOCSIFADDR and SIOCSIFNETMASK code from devinet_ioctl. * glue-include/asm, glue-include/linux: New directories. These contain glue kludge headers that replace all of the Linux <asm/*.h> headers except checksum.h, and several of the Linux <linux/*.h> headers (the remainder come from linux-src/include/linux and are mostly unmodified). * glue-include/asm/atomic.h: New file, glue replacement header. * glue-include/asm/bitops.h: New file, glue replacement header. * glue-include/asm/byteorder.h: New file, glue replacement header. * glue-include/asm/checksum.h: New file, glue replacement header. * glue-include/asm/errno.h: New file, glue replacement header. * glue-include/asm/hardirq.h: New file, glue replacement header. * glue-include/asm/init.h: New file, glue replacement header. * glue-include/asm/segment.h: New file, glue replacement header. * glue-include/asm/spinlock.h: New file, glue replacement header. * glue-include/asm/system.h: New file, glue replacement header. * glue-include/asm/types.h: New file, glue replacement header. * glue-include/asm/uaccess.h: New file, glue replacement header. * glue-include/linux/autoconf.h: New file, glue replacement header. * glue-include/linux/binfmts.h: New file, glue replacement header. * glue-include/linux/config.h: New file, glue replacement header. * glue-include/linux/errno.h: New file, glue replacement header. * glue-include/linux/fcntl.h: New file, glue replacement header. * glue-include/linux/fs.h: New file, glue replacement header. * glue-include/linux/in.h: New file, glue replacement header. * glue-include/linux/in6.h: New file, glue replacement header. * glue-include/linux/interrupt.h: New file, glue replacement header. * glue-include/linux/ioctl.h: New file, glue replacement header. * glue-include/linux/ipv6.h: New file, glue replacement header. * glue-include/linux/kernel.h: New file, glue replacement header. * glue-include/linux/limits.h: New file, glue replacement header. * glue-include/linux/major.h: New file, glue replacement header. * glue-include/linux/malloc.h: New file, glue replacement header. * glue-include/linux/mm.h: New file, glue replacement header. * glue-include/linux/param.h: New file, glue replacement header. * glue-include/linux/personality.h: New file, glue replacement header. * glue-include/linux/poll.h: New file, glue replacement header. * glue-include/linux/proc_fs.h: New file, glue replacement header. * glue-include/linux/sched.h: New file, glue replacement header. * glue-include/linux/slab.h: New file, glue replacement header. * glue-include/linux/socket.h: New file, glue replacement header. * glue-include/linux/sockios.h: New file, glue replacement header. * glue-include/linux/stat.h: New file, glue replacement header. * glue-include/linux/string.h: New file, glue replacement header. * glue-include/linux/termios.h: New file, glue replacement header. * glue-include/linux/time.h: New file, glue replacement header. * glue-include/linux/timer.h: New file, glue replacement header. * glue-include/linux/timex.h: New file, glue replacement header. * glue-include/linux/types.h: New file, glue replacement header. * glue-include/linux/un.h: New file, glue replacement header. * glue-include/linux/version.h: New file, glue replacement header. * glue-include/linux/wait.h: New file, glue replacement header. * kmem_cache.c: New file. Glue code replaces Linux kmem_cache_t et al. * stubs.c: New file. No-op functions and stub variables for a few things the Linux networking code needs to link. * Makefile (core-srcs, arch-lib-srcs, ethernet-srcs, ipv4-srcs): New variables, listing sources used from linux-src subdirectories. (LINUXSRCS): Define using those. (SRCS): Remove devices.c; add kmem_cache.c, stubs.c. (UNUSEDSRC): Variable removed. (vpath %.c): Remove vpath for $(srcdir)/linux-inet directory. Add vpaths for $(srcdir)/linux-src subdirectories. (CPPFLAGS): Add -D_HURD_SYSTYPE defining it to $(asm_syntax) as a double-quoted string. Add -I's for glue-include and linux-src/include. * pfinet.h: Include <sys/socket.h>, and not <linux/netdevice.h>. (master_device): Remove decl. (global_lock, packet_queue_lock): Remove common defns. (global_lock, net_bh_lock): Declare them as externs. (struct sockaddr): Remove len member, make address member just a struct sockaddr rather than a 0-length array. (setup_loopback_device, become_task_protid, become_task): Remove decls. (ethernet_initialize): Declare it. (input_work_thread): Remove decl. (net_bh_thread): Declare it. (tcp_readable): Remove decl. (tcp_tiocinq): Declare it. * config.h: Rewritten based on Linux 2.2.12 set of CONFIG_* options. (CONFIG_NET, CONFIG_INET, CONFIG_SKB_LARGE): These are the only Linux config options we set. (CONFIG_IP_NOSIOCRT): New macro (not a proper config option, but used conveniently in the code). * ethernet.c (ethernet_set_multi): Take only one parameter. Remove assert, since we always get passed IGMP_ALL_HOSTS. (ethernet_thread): Make static. (ethernet_demuxer): Use __mutex_lock in place of mutex_lock, so as to get cthreads instead of linux/spinlock.h glue macros. Lock net_bh_lock instead of global_lock. Set SKB->protocol with eth_type_trans before calling netif_rx. (ethernet_initialize): New function, one-time initialization broken out of ethernet_open. (ethernet_open): Ports setup moved to ethernet_initialize. Don't use `errno' to avoid glue conflicts. Use get_privileged_ports here to get the master device port, and deallocate it after calling device_open. (ethernet_xmit): Use assert_perror. Only one arg to dev_kfree_skb now. (setup_ethernet_device): Change initializations for structure changes. Call dev_init_buffers and register_netdevice on the device. * timer-emul.c (all functions): Use __mutex_lock instead of mutex_lock. Adjust for renaming of `prevp' member to `prev' in struct timer_list. (mod_timer): New function. * socket.c (proto_ops): Variable removed. (net_families): New variable replaces it. (sock_register): Rewritten for new calling convention, set net_families rather than proto_ops. (make_sock_user, clean_socketport, sock_alloc, sock_release): Functions moved here from misc.c. * sched.c (packet_queue_lock): Variable removed. (net_bh_lock, net_bh_wakeup): New variables. (current): Variable removed (now a macro in the glue headers). (interruptible_sleep_on, wake_up_interruptible): Functions removed. They are replaced by inlines in the glue headers. (become_task, become_task_protid): Functions removed; they are replaced by macros in glue-include/linux/sched.h. (net_bh_worker): New function. * loopback.c: Completely rewritten, mostly copied from linux-2.2.12's drivers/net/loopback.c source file. * io-ops.c (all functions): Use __mutex_lock in place of mutex_lock. (S_io_write): Call ops->sendmsg instead of ops->write, which no longer exists. If O_NONBLOCK is set, set MSG_DONTWAIT in msg_flags. (S_io_read): Call ops->recvmsg instead of ops->read, which no longer exists If O_NONBLOCK is set, pass MSG_DONTWAIT. (S_io_readable): Use USER->sock->data in place of USER->sock->sk. For SOCK_STREAM and SOCK_SEQPACKET types, call tcp_tiocinq. (S_io_set_all_openmodes, S_io_get_openmodes, S_io_set_some_openmodes, S_io_clear_some_openmodes): Member USER->sock->userflags is now renamed USER->sock->flags. (S_io_select): Completely rewritten using ops->poll. (select_wait): Function removed. (S_io_stat): Set st_mode to reflect S_IFSOCK. * socket-ops.c (all functions): Use __mutex_lock instead of mutex_lock. (S_socket_create): Don't set SOCK->ops or call SOCK->ops->create. Instead, call net_families[PF_INET]->create. (S_socket_listen): Remove extra checks; just call ops->listen. (S_socket_accept): Remove extra checks before ops->accept call. Avoid use of goto. (S_socket_connect): Remove extra checks; just call ops->connect. (S_socket_bind): Adjust for struct sock_addr changes. (S_socket_create_address): Likewise. (S_socket_whatis_address): Likewise. (S_socket_connect2): Don't diddle data structures after ops->socketpair call. (S_socket_getopt): Use sock_getsockopt if LEVEL is SOL_SOCKET. Accept any data size, not just sizeof (int). (S_socket_setopt): Use sock_setsockopt if LEVEL is SOL_SOCKET. (S_socket_send): Always use ops->sendmsg instead of ops->send or ops->sendto, which no longer exist. If O_NONBLOCK is set, set MSG_DONTWAIT in msg_flags. (S_socket_recv): Always use ops->recvmsg instead of ops->recv, which no longer exists. If O_NONBLOCK is set, set MSG_DONTWAIT in flags. Check for error from S_socket_create_address. * main.c (find_device): Don't try to set ether_dev.pa_mask (it's gone). (main): Don't call init_devices. Call ethernet_initialize. Start net_bh_worker instead of input_work_thread. Don't call setup_loopback_device. Instead, take global_lock, do prepare_current, and then call sk_init, skb_init, inet_proto_init, and net_dev_init. Keep global_lock held while calling argp_parse. Call arrange_shutdown_notification only after all that. Fix error call for "contacting parent" to pass ERR instead of errno. * options.c (ADDR): #undef before defining macro. (parse_opt): #if 0 out EDESTADDRREQ check (I don't understand it). To apply settings, call configure_devices. (ADD_ADDR_OPT): #if 0 --address and --netmask options. Needs fixed. * misc.c (make_sock_user, clean_socketport, sock_alloc, sock_release): Functions moved to socket.c. (sock_release_peer): Function removed. (make_sockaddr_port): Use struct sockaddr_storage to size buffer. Fix size calculation for new struct sock_addr layout. Initialize sa_family and sa_len of new struct sock_addr. Remove the old Linux (2.0.??) network stack and the glue code for it. * linux-inet, asm, linux: Directories and all files removed. Some of the new files in glue-include came from the old glue headers in the asm and linux directories, but most were substantially modified. * devices.c: File removed. The equivalent glue is now elsewhere.
Diffstat (limited to 'pfinet/linux-inet/ipx.c')
-rw-r--r--pfinet/linux-inet/ipx.c1947
1 files changed, 0 insertions, 1947 deletions
diff --git a/pfinet/linux-inet/ipx.c b/pfinet/linux-inet/ipx.c
deleted file mode 100644
index 88b53c30..00000000
--- a/pfinet/linux-inet/ipx.c
+++ /dev/null
@@ -1,1947 +0,0 @@
-/*
- * Implements an IPX socket layer (badly - but I'm working on it).
- *
- * This code is derived from work by
- * Ross Biro : Writing the original IP stack
- * Fred Van Kempen : Tidying up the TCP/IP
- *
- * Many thanks go to Keith Baker, Institute For Industrial Information
- * Technology Ltd, Swansea University for allowing me to work on this
- * in my own time even though it was in some ways related to commercial
- * work I am currently employed to do there.
- *
- * All the material in this file is subject to the Gnu license version 2.
- * Neither Alan Cox nor the Swansea University Computer Society admit liability
- * nor provide warranty for any of this software. This material is provided
- * as is and at no charge.
- *
- * Revision 0.21: Uses the new generic socket option code.
- * Revision 0.22: Gcc clean ups and drop out device registration. Use the
- * new multi-protocol edition of hard_header
- * Revision 0.23: IPX /proc by Mark Evans.
- * Adding a route will overwrite any existing route to the same
- * network.
- * Revision 0.24: Supports new /proc with no 4K limit
- * Revision 0.25: Add ephemeral sockets, passive local network
- * identification, support for local net 0 and
- * multiple datalinks <Greg Page>
- * Revision 0.26: Device drop kills IPX routes via it. (needed for modules)
- * Revision 0.27: Autobind <Mark Evans>
- * Revision 0.28: Small fix for multiple local networks <Thomas Winder>
- * Revision 0.29: Assorted major errors removed <Mark Evans>
- * Small correction to promisc mode error fix <Alan Cox>
- * Asynchronous I/O support.
- * Changed to use notifiers and the newer packet_type stuff.
- * Assorted major fixes <Alejandro Liu>
- *
- * Portions Copyright (c) 1995 Caldera, Inc. <greg@caldera.com>
- * Neither Greg Page nor Caldera, Inc. admit liability nor provide
- * warranty for any of this software. This material is provided
- * "AS-IS" and at no charge.
- */
-
-#include <linux/config.h>
-#include <linux/errno.h>
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/timer.h>
-#include <linux/string.h>
-#include <linux/sockios.h>
-#include <linux/net.h>
-#include <linux/ipx.h>
-#include <linux/inet.h>
-#include <linux/netdevice.h>
-#include <linux/skbuff.h>
-#include "sock.h"
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/fcntl.h>
-#include <linux/mm.h>
-#include <linux/termios.h> /* For TIOCOUTQ/INQ */
-#include <linux/interrupt.h>
-#include "p8022.h"
-#include "psnap.h"
-
-#ifdef CONFIG_IPX
-/* Configuration Variables */
-static unsigned char ipxcfg_max_hops = 16;
-static char ipxcfg_auto_select_primary = 0;
-static char ipxcfg_auto_create_interfaces = 0;
-
-/* Global Variables */
-static struct datalink_proto *p8022_datalink = NULL;
-static struct datalink_proto *pEII_datalink = NULL;
-static struct datalink_proto *p8023_datalink = NULL;
-static struct datalink_proto *pSNAP_datalink = NULL;
-
-static ipx_interface *ipx_interfaces = NULL;
-static ipx_route *ipx_routes = NULL;
-static ipx_interface *ipx_internal_net = NULL;
-static ipx_interface *ipx_primary_net = NULL;
-
-static int
-ipxcfg_set_auto_create(char val)
-{
- ipxcfg_auto_create_interfaces = val;
- return 0;
-}
-
-static int
-ipxcfg_set_auto_select(char val)
-{
- ipxcfg_auto_select_primary = val;
- if (val && (ipx_primary_net == NULL))
- ipx_primary_net = ipx_interfaces;
- return 0;
-}
-
-static int
-ipxcfg_get_config_data(ipx_config_data *arg)
-{
- ipx_config_data vals;
-
- vals.ipxcfg_auto_create_interfaces = ipxcfg_auto_create_interfaces;
- vals.ipxcfg_auto_select_primary = ipxcfg_auto_select_primary;
- memcpy_tofs(arg, &vals, sizeof(vals));
- return 0;
-}
-
-
-/***********************************************************************************************************************\
-* *
-* Handlers for the socket list. *
-* *
-\***********************************************************************************************************************/
-
-/*
- * Note: Sockets may not be removed _during_ an interrupt or inet_bh
- * handler using this technique. They can be added although we do not
- * use this facility.
- */
-
-static void
-ipx_remove_socket(ipx_socket *sk)
-{
- ipx_socket *s;
- ipx_interface *intrfc;
- unsigned long flags;
-
- save_flags(flags);
- cli();
-
- /* Determine interface with which socket is associated */
- intrfc = sk->ipx_intrfc;
- if (intrfc == NULL) {
- restore_flags(flags);
- return;
- }
-
- s=intrfc->if_sklist;
- if(s==sk) {
- intrfc->if_sklist=s->next;
- restore_flags(flags);
- return;
- }
-
- while(s && s->next) {
- if(s->next==sk) {
- s->next=sk->next;
- restore_flags(flags);
- return;
- }
- s=s->next;
- }
- restore_flags(flags);
-}
-
-/*
- * This is only called from user mode. Thus it protects itself against
- * interrupt users but doesn't worry about being called during work.
- * Once it is removed from the queue no interrupt or bottom half will
- * touch it and we are (fairly 8-) ) safe.
- */
-
-static void
-ipx_destroy_socket(ipx_socket *sk)
-{
- struct sk_buff *skb;
-
- ipx_remove_socket(sk);
- while((skb=skb_dequeue(&sk->receive_queue))!=NULL) {
- kfree_skb(skb,FREE_READ);
- }
-
- kfree_s(sk,sizeof(*sk));
-}
-
-/* The following code is used to support IPX Interfaces (IPXITF). An
- * IPX interface is defined by a physical device and a frame type.
- */
-
-static ipx_route * ipxrtr_lookup(unsigned long);
-
-static void
-ipxitf_clear_primary_net(void)
-{
- if (ipxcfg_auto_select_primary && (ipx_interfaces != NULL))
- ipx_primary_net = ipx_interfaces;
- else
- ipx_primary_net = NULL;
-}
-
-static ipx_interface *
-ipxitf_find_using_phys(struct device *dev, unsigned short datalink)
-{
- ipx_interface *i;
-
- for (i=ipx_interfaces;
- i && ((i->if_dev!=dev) || (i->if_dlink_type!=datalink));
- i=i->if_next)
- ;
- return i;
-}
-
-static ipx_interface *
-ipxitf_find_using_net(unsigned long net)
-{
- ipx_interface *i;
-
- if (net == 0L)
- return ipx_primary_net;
-
- for (i=ipx_interfaces; i && (i->if_netnum!=net); i=i->if_next)
- ;
-
- return i;
-}
-
-/* Sockets are bound to a particular IPX interface. */
-static void
-ipxitf_insert_socket(ipx_interface *intrfc, ipx_socket *sk)
-{
- ipx_socket *s;
-
- sk->ipx_intrfc = intrfc;
- sk->next = NULL;
- if (intrfc->if_sklist == NULL) {
- intrfc->if_sklist = sk;
- } else {
- for (s = intrfc->if_sklist; s->next != NULL; s = s->next)
- ;
- s->next = sk;
- }
-}
-
-static ipx_socket *
-ipxitf_find_socket(ipx_interface *intrfc, unsigned short port)
-{
- ipx_socket *s;
-
- for (s=intrfc->if_sklist;
- (s != NULL) && (s->ipx_port != port);
- s=s->next)
- ;
-
- return s;
-}
-
-static void ipxrtr_del_routes(ipx_interface *);
-
-static void
-ipxitf_down(ipx_interface *intrfc)
-{
- ipx_interface *i;
- ipx_socket *s, *t;
-
- /* Delete all routes associated with this interface */
- ipxrtr_del_routes(intrfc);
-
- /* error sockets */
- for (s = intrfc->if_sklist; s != NULL; ) {
- s->err = ENOLINK;
- s->error_report(s);
- s->ipx_intrfc = NULL;
- s->ipx_port = 0;
- s->zapped=1; /* Indicates it is no longer bound */
- t = s;
- s = s->next;
- t->next = NULL;
- }
- intrfc->if_sklist = NULL;
-
- /* remove this interface from list */
- if (intrfc == ipx_interfaces) {
- ipx_interfaces = intrfc->if_next;
- } else {
- for (i = ipx_interfaces;
- (i != NULL) && (i->if_next != intrfc);
- i = i->if_next)
- ;
- if ((i != NULL) && (i->if_next == intrfc))
- i->if_next = intrfc->if_next;
- }
-
- /* remove this interface from *special* networks */
- if (intrfc == ipx_primary_net)
- ipxitf_clear_primary_net();
- if (intrfc == ipx_internal_net)
- ipx_internal_net = NULL;
-
- kfree_s(intrfc, sizeof(*intrfc));
-}
-
-static int
-ipxitf_device_event(unsigned long event, void *ptr)
-{
- struct device *dev = ptr;
- ipx_interface *i, *tmp;
-
- if(event!=NETDEV_DOWN)
- return NOTIFY_DONE;
-
- for (i = ipx_interfaces; i != NULL; ) {
-
- tmp = i->if_next;
- if (i->if_dev == dev)
- ipxitf_down(i);
- i = tmp;
-
- }
-
- return NOTIFY_DONE;
-}
-
-static int
-ipxitf_def_skb_handler(struct sock *sock, struct sk_buff *skb)
-{
- int retval;
-
- if((retval = sock_queue_rcv_skb(sock, skb))<0) {
- /*
- * We do a FREE_WRITE here because this indicates how
- * to treat the socket with which the packet is
- * associated. If this packet is associated with a
- * socket at all, it must be the originator of the
- * packet. Incoming packets will have no socket
- * associated with them at this point.
- */
- kfree_skb(skb,FREE_WRITE);
- }
- return retval;
-}
-
-static int
-ipxitf_demux_socket(ipx_interface *intrfc, struct sk_buff *skb, int copy)
-{
- ipx_packet *ipx = (ipx_packet *)(skb->h.raw);
- ipx_socket *sock1 = NULL, *sock2 = NULL;
- struct sk_buff *skb1 = NULL, *skb2 = NULL;
- int ipx_offset;
-
- sock1 = ipxitf_find_socket(intrfc, ipx->ipx_dest.sock);
-
- /*
- * We need to check if there is a primary net and if
- * this is addressed to one of the *SPECIAL* sockets because
- * these need to be propagated to the primary net.
- * The *SPECIAL* socket list contains: 0x452(SAP), 0x453(RIP) and
- * 0x456(Diagnostic).
- */
- if (ipx_primary_net && (intrfc != ipx_primary_net)) {
- switch (ntohs(ipx->ipx_dest.sock)) {
- case 0x452:
- case 0x453:
- case 0x456:
- /*
- * The appropriate thing to do here is to
- * dup the packet and route to the primary net
- * interface via ipxitf_send; however, we'll cheat
- * and just demux it here.
- */
- sock2 = ipxitf_find_socket(ipx_primary_net,
- ipx->ipx_dest.sock);
- break;
- default:
- break;
- }
- }
-
- /* if there is nothing to do, return */
- if ((sock1 == NULL) && (sock2 == NULL)) {
- if (!copy)
- kfree_skb(skb,FREE_WRITE);
- return 0;
- }
-
- ipx_offset = (char *)(skb->h.raw) - (char *)(skb->data);
-
- /* This next segment of code is a little awkward, but it sets it up
- * so that the appropriate number of copies of the SKB are made and
- * that skb1 and skb2 point to it (them) so that it (they) can be
- * demuxed to sock1 and/or sock2. If we are unable to make enough
- * copies, we do as much as is possible.
- */
- if (copy) {
- skb1 = skb_clone(skb, GFP_ATOMIC);
- if (skb1 != NULL) {
- skb1->h.raw = (unsigned char *)&(skb1->data[ipx_offset]);
- skb1->arp = skb1->free = 1;
- }
- } else {
- skb1 = skb;
- }
-
- if (skb1 == NULL) return -ENOMEM;
-
- /* Do we need 2 SKBs? */
- if (sock1 && sock2) {
- skb2 = skb_clone(skb1, GFP_ATOMIC);
- if (skb2 != NULL) {
- skb2->h.raw = (unsigned char *)&(skb2->data[ipx_offset]);
- skb2->arp = skb2->free = 1;
- }
- } else {
- skb2 = skb1;
- }
-
- if (sock1) {
- (void) ipxitf_def_skb_handler(sock1, skb1);
- }
-
- if (skb2 == NULL) return -ENOMEM;
-
- if (sock2) {
- (void) ipxitf_def_skb_handler(sock2, skb2);
- }
-
- return 0;
-}
-
-static struct sk_buff *
-ipxitf_adjust_skbuff(ipx_interface *intrfc, struct sk_buff *skb)
-{
- struct sk_buff *skb2;
- int in_offset = skb->h.raw - skb->data;
- int out_offset = intrfc->if_ipx_offset;
- char *oldraw;
- int len;
-
- /* Hopefully, most cases */
- if (in_offset == out_offset) {
- skb->len += out_offset;
- skb->arp = skb->free = 1;
- return skb;
- }
-
- /* Existing SKB will work, just need to move things around a little */
- if (in_offset > out_offset) {
- oldraw = skb->h.raw;
- skb->h.raw = &(skb->data[out_offset]);
- memmove(skb->h.raw, oldraw, skb->len);
- skb->len += out_offset;
- skb->arp = skb->free = 1;
- return skb;
- }
-
- /* Need new SKB */
- len = skb->len + out_offset;
- skb2 = alloc_skb(len, GFP_ATOMIC);
- if (skb2 != NULL) {
- skb2->h.raw = &(skb2->data[out_offset]);
- skb2->len = len;
- skb2->free=1;
- skb2->arp=1;
- memcpy(skb2->h.raw, skb->h.raw, skb->len);
- }
- kfree_skb(skb, FREE_WRITE);
- return skb2;
-}
-
-static int
-ipxitf_send(ipx_interface *intrfc, struct sk_buff *skb, char *node)
-{
- ipx_packet *ipx = (ipx_packet *)(skb->h.raw);
- struct 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;
-
- /* We need to know how many skbuffs it will take to send out this
- * packet to avoid unnecessary copies.
- */
- if ((dl == NULL) || (dev == NULL) || (dev->flags & IFF_LOOPBACK))
- send_to_wire = 0;
-
- /* See if this should be demuxed to sockets on this interface */
- if (ipx->ipx_dest.net == intrfc->if_netnum) {
- if (memcmp(intrfc->if_node, node, IPX_NODE_LEN) == 0)
- return ipxitf_demux_socket(intrfc, skb, 0);
- if (memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0) {
- ipxitf_demux_socket(intrfc, skb, send_to_wire);
- if (!send_to_wire) return 0;
- }
- }
-
- /* if the originating net is not equal to our net; this is routed */
- if (ipx->ipx_source.net != intrfc->if_netnum) {
- if (++(ipx->ipx_tctrl) > ipxcfg_max_hops)
- send_to_wire = 0;
- }
-
- if (!send_to_wire) {
- /*
- * We do a FREE_WRITE here because this indicates how
- * to treat the socket with which the packet is
- * associated. If this packet is associated with a
- * socket at all, it must be the originator of the
- * packet. Routed packets will have no socket associated
- * with them.
- */
- kfree_skb(skb,FREE_WRITE);
- return 0;
- }
-
- /* determine the appropriate hardware address */
- addr_len = dev->addr_len;
- if (memcmp(ipx_broadcast_node, node, IPX_NODE_LEN) == 0) {
- memcpy(dest_node, dev->broadcast, addr_len);
- } else {
- memcpy(dest_node, &(node[IPX_NODE_LEN-addr_len]), addr_len);
- }
-
- /* make any compensation for differing physical/data link size */
- skb = ipxitf_adjust_skbuff(intrfc, skb);
- if (skb == NULL) return 0;
-
- /* set up data link and physical headers */
- skb->dev = dev;
- dl->datalink_header(dl, skb, dest_node);
-
- if (skb->sk != NULL) {
- /* This is an outbound packet from this host. We need to
- * increment the write count.
- */
- skb->sk->wmem_alloc += skb->mem_len;
- }
-
- /* Send it out */
- dev_queue_xmit(skb, dev, SOPRI_NORMAL);
- return 0;
-}
-
-static int
-ipxrtr_add_route(unsigned long, ipx_interface *, unsigned char *);
-
-static int
-ipxitf_add_local_route(ipx_interface *intrfc)
-{
- return ipxrtr_add_route(intrfc->if_netnum, intrfc, NULL);
-}
-
-static char * ipx_frame_name(unsigned short);
-static char * ipx_device_name(ipx_interface *);
-static int ipxrtr_route_skb(struct sk_buff *);
-
-static int
-ipxitf_rcv(ipx_interface *intrfc, struct sk_buff *skb)
-{
- ipx_packet *ipx = (ipx_packet *) (skb->h.raw);
- ipx_interface *i;
-
- /* See if we should update our network number */
- if ((intrfc->if_netnum == 0L) &&
- (ipx->ipx_source.net == ipx->ipx_dest.net) &&
- (ipx->ipx_source.net != 0L)) {
- /* 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=ipxitf_find_using_net(ipx->ipx_source.net))==NULL) {
- intrfc->if_netnum = ipx->ipx_source.net;
- (void) ipxitf_add_local_route(intrfc);
- } else {
- printk("IPX: Network number collision %lx\n\t%s %s and %s %s\n",
- htonl(ipx->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));
- }
- }
-
- if (ipx->ipx_dest.net == 0L)
- ipx->ipx_dest.net = intrfc->if_netnum;
- if (ipx->ipx_source.net == 0L)
- ipx->ipx_source.net = intrfc->if_netnum;
-
- if (intrfc->if_netnum != ipx->ipx_dest.net) {
- /* We only route point-to-point packets. */
- if ((skb->pkt_type != PACKET_BROADCAST) &&
- (skb->pkt_type != PACKET_MULTICAST))
- return ipxrtr_route_skb(skb);
-
- kfree_skb(skb,FREE_READ);
- return 0;
- }
-
- /* see if we should keep it */
- if ((memcmp(ipx_broadcast_node, ipx->ipx_dest.node, IPX_NODE_LEN) == 0)
- || (memcmp(intrfc->if_node, ipx->ipx_dest.node, IPX_NODE_LEN) == 0)) {
- return ipxitf_demux_socket(intrfc, skb, 0);
- }
-
- /* we couldn't pawn it off so unload it */
- kfree_skb(skb,FREE_READ);
- return 0;
-}
-
-static void
-ipxitf_insert(ipx_interface *intrfc)
-{
- ipx_interface *i;
-
- intrfc->if_next = NULL;
- if (ipx_interfaces == NULL) {
- ipx_interfaces = intrfc;
- } else {
- for (i = ipx_interfaces; i->if_next != NULL; i = i->if_next)
- ;
- i->if_next = intrfc;
- }
-
- if (ipxcfg_auto_select_primary && (ipx_primary_net == NULL))
- ipx_primary_net = intrfc;
-}
-
-static int
-ipxitf_create_internal(ipx_interface_definition *idef)
-{
- ipx_interface *intrfc;
-
- /* Only one primary network allowed */
- if (ipx_primary_net != NULL) return -EEXIST;
-
- /* Must have a valid network number */
- if (idef->ipx_network == 0L) return -EADDRNOTAVAIL;
- if (ipxitf_find_using_net(idef->ipx_network) != NULL)
- return -EADDRINUSE;
-
- intrfc=(ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);
- if (intrfc==NULL)
- 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 = intrfc;
- ipx_primary_net = intrfc;
- ipxitf_insert(intrfc);
- return ipxitf_add_local_route(intrfc);
-}
-
-static int
-ipx_map_frame_type(unsigned char type)
-{
- switch (type) {
- case IPX_FRAME_ETHERII: return htons(ETH_P_IPX);
- case IPX_FRAME_8022: return htons(ETH_P_802_2);
- case IPX_FRAME_SNAP: return htons(ETH_P_SNAP);
- case IPX_FRAME_8023: return htons(ETH_P_802_3);
- }
- return 0;
-}
-
-static int
-ipxitf_create(ipx_interface_definition *idef)
-{
- struct device *dev;
- unsigned short dlink_type = 0;
- struct datalink_proto *datalink = NULL;
- ipx_interface *intrfc;
-
- if (idef->ipx_special == IPX_INTERNAL)
- return ipxitf_create_internal(idef);
-
- if ((idef->ipx_special == IPX_PRIMARY) && (ipx_primary_net != NULL))
- return -EEXIST;
-
- if ((idef->ipx_network != 0L) &&
- (ipxitf_find_using_net(idef->ipx_network) != NULL))
- return -EADDRINUSE;
-
- switch (idef->ipx_dlink_type) {
- case IPX_FRAME_ETHERII:
- dlink_type = htons(ETH_P_IPX);
- datalink = pEII_datalink;
- break;
- case IPX_FRAME_8022:
- dlink_type = htons(ETH_P_802_2);
- datalink = p8022_datalink;
- break;
- case IPX_FRAME_SNAP:
- dlink_type = htons(ETH_P_SNAP);
- datalink = pSNAP_datalink;
- break;
- case IPX_FRAME_8023:
- dlink_type = htons(ETH_P_802_3);
- datalink = p8023_datalink;
- break;
- case IPX_FRAME_NONE:
- default:
- break;
- }
-
- if (datalink == NULL)
- return -EPROTONOSUPPORT;
-
- dev=dev_get(idef->ipx_device);
- if (dev==NULL)
- return -ENODEV;
-
- if (!(dev->flags & IFF_UP))
- return -ENETDOWN;
-
- /* Check addresses are suitable */
- if(dev->addr_len>IPX_NODE_LEN)
- return -EINVAL;
-
- if ((intrfc = ipxitf_find_using_phys(dev, dlink_type)) == NULL) {
-
- /* Ok now create */
- intrfc=(ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);
- if (intrfc==NULL)
- return -EAGAIN;
- 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;
- 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);
-
- ipxitf_insert(intrfc);
- }
-
- /* If the network number is known, add a route */
- if (intrfc->if_netnum == 0L)
- return 0;
-
- return ipxitf_add_local_route(intrfc);
-}
-
-static int
-ipxitf_delete(ipx_interface_definition *idef)
-{
- struct device *dev = NULL;
- unsigned short dlink_type = 0;
- ipx_interface *intrfc;
-
- if (idef->ipx_special == IPX_INTERNAL) {
- if (ipx_internal_net != NULL) {
- ipxitf_down(ipx_internal_net);
- return 0;
- }
- return -ENOENT;
- }
-
- dlink_type = ipx_map_frame_type(idef->ipx_dlink_type);
- if (dlink_type == 0)
- return -EPROTONOSUPPORT;
-
- dev=dev_get(idef->ipx_device);
- if(dev==NULL) return -ENODEV;
-
- intrfc = ipxitf_find_using_phys(dev, dlink_type);
- if (intrfc != NULL) {
- ipxitf_down(intrfc);
- return 0;
- }
- return -EINVAL;
-}
-
-static ipx_interface *
-ipxitf_auto_create(struct device *dev, unsigned short dlink_type)
-{
- struct datalink_proto *datalink = NULL;
- ipx_interface *intrfc;
-
- switch (htons(dlink_type)) {
- case ETH_P_IPX: datalink = pEII_datalink; break;
- case ETH_P_802_2: datalink = p8022_datalink; break;
- case ETH_P_SNAP: datalink = pSNAP_datalink; break;
- case ETH_P_802_3: datalink = p8023_datalink; break;
- default: return NULL;
- }
-
- if (dev == NULL)
- return NULL;
-
- /* Check addresses are suitable */
- if(dev->addr_len>IPX_NODE_LEN) return NULL;
-
- intrfc=(ipx_interface *)kmalloc(sizeof(ipx_interface),GFP_ATOMIC);
- if (intrfc!=NULL) {
- intrfc->if_dev=dev;
- intrfc->if_netnum=0L;
- 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);
- ipxitf_insert(intrfc);
- }
-
- return intrfc;
-}
-
-static int
-ipxitf_ioctl(unsigned int cmd, void *arg)
-{
- int err;
- switch(cmd)
- {
- case SIOCSIFADDR:
- {
- struct ifreq ifr;
- struct sockaddr_ipx *sipx;
- ipx_interface_definition f;
- err=verify_area(VERIFY_READ,arg,sizeof(ifr));
- if(err)
- return err;
- memcpy_fromfs(&ifr,arg,sizeof(ifr));
- sipx=(struct sockaddr_ipx *)&ifr.ifr_addr;
- if(sipx->sipx_family!=AF_IPX)
- return -EINVAL;
- f.ipx_network=sipx->sipx_network;
- memcpy(f.ipx_device, ifr.ifr_name, sizeof(f.ipx_device));
- memcpy(f.ipx_node, sipx->sipx_node, IPX_NODE_LEN);
- f.ipx_dlink_type=sipx->sipx_type;
- f.ipx_special=sipx->sipx_special;
- if(sipx->sipx_action==IPX_DLTITF)
- return ipxitf_delete(&f);
- else
- return ipxitf_create(&f);
- }
- case SIOCGIFADDR:
- {
- struct ifreq ifr;
- struct sockaddr_ipx *sipx;
- ipx_interface *ipxif;
- struct device *dev;
- err=verify_area(VERIFY_WRITE,arg,sizeof(ifr));
- if(err)
- return err;
- memcpy_fromfs(&ifr,arg,sizeof(ifr));
- sipx=(struct sockaddr_ipx *)&ifr.ifr_addr;
- dev=dev_get(ifr.ifr_name);
- if(!dev)
- return -ENODEV;
- ipxif=ipxitf_find_using_phys(dev, ipx_map_frame_type(sipx->sipx_type));
- if(ipxif==NULL)
- return -EADDRNOTAVAIL;
- sipx->sipx_network=ipxif->if_netnum;
- memcpy(sipx->sipx_node, ipxif->if_node, sizeof(sipx->sipx_node));
- memcpy_tofs(arg,&ifr,sizeof(ifr));
- return 0;
- }
- case SIOCAIPXITFCRT:
- err=verify_area(VERIFY_READ,arg,sizeof(char));
- if(err)
- return err;
- return ipxcfg_set_auto_create(get_fs_byte(arg));
- case SIOCAIPXPRISLT:
- err=verify_area(VERIFY_READ,arg,sizeof(char));
- if(err)
- return err;
- return ipxcfg_set_auto_select(get_fs_byte(arg));
- default:
- return -EINVAL;
- }
-}
-
-/*******************************************************************************************************************\
-* *
-* Routing tables for the IPX socket layer *
-* *
-\*******************************************************************************************************************/
-
-static ipx_route *
-ipxrtr_lookup(unsigned long net)
-{
- ipx_route *r;
-
- for (r=ipx_routes; (r!=NULL) && (r->ir_net!=net); r=r->ir_next)
- ;
-
- return r;
-}
-
-static int
-ipxrtr_add_route(unsigned long network, ipx_interface *intrfc, unsigned char *node)
-{
- ipx_route *rt;
-
- /* Get a route structure; either existing or create */
- rt = ipxrtr_lookup(network);
- if (rt==NULL) {
- rt=(ipx_route *)kmalloc(sizeof(ipx_route),GFP_ATOMIC);
- if(rt==NULL)
- return -EAGAIN;
- rt->ir_next=ipx_routes;
- ipx_routes=rt;
- }
-
- rt->ir_net = network;
- rt->ir_intrfc = intrfc;
- if (node == NULL) {
- memset(rt->ir_router_node, '\0', IPX_NODE_LEN);
- rt->ir_routed = 0;
- } else {
- memcpy(rt->ir_router_node, node, IPX_NODE_LEN);
- rt->ir_routed=1;
- }
- return 0;
-}
-
-static void
-ipxrtr_del_routes(ipx_interface *intrfc)
-{
- ipx_route **r, *tmp;
-
- for (r = &ipx_routes; (tmp = *r) != NULL; ) {
- if (tmp->ir_intrfc == intrfc) {
- *r = tmp->ir_next;
- kfree_s(tmp, sizeof(ipx_route));
- } else {
- r = &(tmp->ir_next);
- }
- }
-}
-
-static int
-ipxrtr_create(ipx_route_definition *rd)
-{
- ipx_interface *intrfc;
-
- /* Find the appropriate interface */
- intrfc = ipxitf_find_using_net(rd->ipx_router_network);
- if (intrfc == NULL)
- return -ENETUNREACH;
-
- return ipxrtr_add_route(rd->ipx_network, intrfc, rd->ipx_router_node);
-}
-
-
-static int
-ipxrtr_delete(long net)
-{
- ipx_route **r;
- ipx_route *tmp;
-
- for (r = &ipx_routes; (tmp = *r) != NULL; ) {
- if (tmp->ir_net == net) {
- if (!(tmp->ir_routed)) {
- /* Directly connected; can't lose route */
- return -EPERM;
- }
- *r = tmp->ir_next;
- kfree_s(tmp, sizeof(ipx_route));
- return 0;
- }
- r = &(tmp->ir_next);
- }
-
- return -ENOENT;
-}
-
-static int
-ipxrtr_route_packet(ipx_socket *sk, struct sockaddr_ipx *usipx, void *ubuf, int len)
-{
- struct sk_buff *skb;
- ipx_interface *intrfc;
- ipx_packet *ipx;
- int size;
- int ipx_offset;
- ipx_route *rt = NULL;
-
- /* Find the appropriate interface on which to send packet */
- if ((usipx->sipx_network == 0L) && (ipx_primary_net != NULL)) {
- usipx->sipx_network = ipx_primary_net->if_netnum;
- intrfc = ipx_primary_net;
- } else {
- rt = ipxrtr_lookup(usipx->sipx_network);
- if (rt==NULL) {
- return -ENETUNREACH;
- }
- intrfc = rt->ir_intrfc;
- }
-
- ipx_offset = intrfc->if_ipx_offset;
- size=sizeof(ipx_packet)+len;
- size += ipx_offset;
-
- if(size+sk->wmem_alloc>sk->sndbuf) return -EAGAIN;
-
- skb=alloc_skb(size,GFP_KERNEL);
- if(skb==NULL) return -ENOMEM;
-
- skb->sk=sk;
- skb->len=size;
- skb->free=1;
- skb->arp=1;
-
- /* Fill in IPX header */
- ipx=(ipx_packet *)&(skb->data[ipx_offset]);
- ipx->ipx_checksum=0xFFFF;
- ipx->ipx_pktsize=htons(len+sizeof(ipx_packet));
- ipx->ipx_tctrl=0;
- ipx->ipx_type=usipx->sipx_type;
- skb->h.raw = (unsigned char *)ipx;
-
- ipx->ipx_source.net = sk->ipx_intrfc->if_netnum;
- memcpy(ipx->ipx_source.node, sk->ipx_intrfc->if_node, IPX_NODE_LEN);
- ipx->ipx_source.sock = sk->ipx_port;
- ipx->ipx_dest.net=usipx->sipx_network;
- memcpy(ipx->ipx_dest.node,usipx->sipx_node,IPX_NODE_LEN);
- ipx->ipx_dest.sock=usipx->sipx_port;
-
- memcpy_fromfs((char *)(ipx+1),ubuf,len);
- return ipxitf_send(intrfc, skb, (rt && rt->ir_routed) ?
- rt->ir_router_node : ipx->ipx_dest.node);
-}
-
-static int
-ipxrtr_route_skb(struct sk_buff *skb)
-{
- ipx_packet *ipx = (ipx_packet *) (skb->h.raw);
- ipx_route *r;
- ipx_interface *i;
-
- r = ipxrtr_lookup(ipx->ipx_dest.net);
- if (r == NULL) {
- /* no known route */
- kfree_skb(skb,FREE_READ);
- return 0;
- }
- i = r->ir_intrfc;
- (void)ipxitf_send(i, skb, (r->ir_routed) ?
- r->ir_router_node : ipx->ipx_dest.node);
- return 0;
-}
-
-/*
- * We use a normal struct rtentry for route handling
- */
-
-static int ipxrtr_ioctl(unsigned int cmd, void *arg)
-{
- int err;
- struct rtentry rt; /* Use these to behave like 'other' stacks */
- struct sockaddr_ipx *sg,*st;
-
- err=verify_area(VERIFY_READ,arg,sizeof(rt));
- if(err)
- return err;
-
- memcpy_fromfs(&rt,arg,sizeof(rt));
-
- sg=(struct sockaddr_ipx *)&rt.rt_gateway;
- st=(struct sockaddr_ipx *)&rt.rt_dst;
-
- if(!(rt.rt_flags&RTF_GATEWAY))
- return -EINVAL; /* Direct routes are fixed */
- if(sg->sipx_family!=AF_IPX)
- return -EINVAL;
- if(st->sipx_family!=AF_IPX)
- return -EINVAL;
-
- switch(cmd)
- {
- case SIOCDELRT:
- return ipxrtr_delete(st->sipx_network);
- case SIOCADDRT:
- {
- struct ipx_route_definition f;
- f.ipx_network=st->sipx_network;
- f.ipx_router_network=sg->sipx_network;
- memcpy(f.ipx_router_node, sg->sipx_node, IPX_NODE_LEN);
- return ipxrtr_create(&f);
- }
- default:
- return -EINVAL;
- }
-}
-
-static char *
-ipx_frame_name(unsigned short frame)
-{
- switch (ntohs(frame)) {
- case ETH_P_IPX: return "EtherII";
- case ETH_P_802_2: return "802.2";
- case ETH_P_SNAP: return "SNAP";
- case ETH_P_802_3: return "802.3";
- default: return "None";
- }
-}
-
-static char *
-ipx_device_name(ipx_interface *intrfc)
-{
- return (intrfc->if_internal ? "Internal" :
- (intrfc->if_dev ? intrfc->if_dev->name : "Unknown"));
-}
-
-/* Called from proc fs */
-int
-ipx_get_interface_info(char *buffer, char **start, off_t offset, int length)
-{
- ipx_interface *i;
- int len=0;
- off_t pos=0;
- off_t begin=0;
-
- /* Theory.. Keep printing in the same place until we pass offset */
-
- len += sprintf (buffer,"%-11s%-15s%-9s%-11s%s\n", "Network",
- "Node_Address", "Primary", "Device", "Frame_Type");
- for (i = ipx_interfaces; i != NULL; i = i->if_next) {
- len += sprintf(buffer+len, "%08lX ", ntohl(i->if_netnum));
- len += sprintf (buffer+len,"%02X%02X%02X%02X%02X%02X ",
- i->if_node[0], i->if_node[1], i->if_node[2],
- i->if_node[3], i->if_node[4], i->if_node[5]);
- len += sprintf(buffer+len, "%-9s", (i == ipx_primary_net) ?
- "Yes" : "No");
- len += sprintf (buffer+len, "%-11s", ipx_device_name(i));
- len += sprintf (buffer+len, "%s\n",
- ipx_frame_name(i->if_dlink_type));
-
- /* Are we still dumping unwanted data then discard the record */
- pos=begin+len;
-
- if(pos<offset) {
- len=0; /* Keep dumping into the buffer start */
- begin=pos;
- }
- if(pos>offset+length) /* We have dumped enough */
- break;
- }
-
- /* The data in question runs from begin to begin+len */
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Remove unwanted header data from length */
- if(len>length)
- len=length; /* Remove unwanted tail data from length */
-
- return len;
-}
-
-int
-ipx_get_info(char *buffer, char **start, off_t offset, int length)
-{
- ipx_socket *s;
- ipx_interface *i;
- int len=0;
- off_t pos=0;
- off_t begin=0;
-
- /* Theory.. Keep printing in the same place until we pass offset */
-
- len += sprintf (buffer,"%-15s%-28s%-10s%-10s%-7s%s\n", "Local_Address",
- "Remote_Address", "Tx_Queue", "Rx_Queue",
- "State", "Uid");
- for (i = ipx_interfaces; i != NULL; i = i->if_next) {
- for (s = i->if_sklist; s != NULL; s = s->next) {
- len += sprintf (buffer+len,"%08lX:%04X ",
- htonl(i->if_netnum),
- htons(s->ipx_port));
- if (s->state!=TCP_ESTABLISHED) {
- len += sprintf(buffer+len, "%-28s", "Not_Connected");
- } else {
- len += sprintf (buffer+len,
- "%08lX:%02X%02X%02X%02X%02X%02X:%04X ",
- htonl(s->ipx_dest_addr.net),
- s->ipx_dest_addr.node[0], s->ipx_dest_addr.node[1],
- s->ipx_dest_addr.node[2], s->ipx_dest_addr.node[3],
- s->ipx_dest_addr.node[4], s->ipx_dest_addr.node[5],
- htons(s->ipx_dest_addr.sock));
- }
- len += sprintf (buffer+len,"%08lX %08lX ",
- s->wmem_alloc, s->rmem_alloc);
- len += sprintf (buffer+len,"%02X %03d\n",
- s->state, SOCK_INODE(s->socket)->i_uid);
-
- /* Are we still dumping unwanted data then discard the record */
- pos=begin+len;
-
- if(pos<offset)
- {
- len=0; /* Keep dumping into the buffer start */
- begin=pos;
- }
- if(pos>offset+length) /* We have dumped enough */
- break;
- }
- }
-
- /* The data in question runs from begin to begin+len */
- *start=buffer+(offset-begin); /* Start of wanted data */
- len-=(offset-begin); /* Remove unwanted header data from length */
- if(len>length)
- len=length; /* Remove unwanted tail data from length */
-
- return len;
-}
-
-int ipx_rt_get_info(char *buffer, char **start, off_t offset, int length)
-{
- ipx_route *rt;
- int len=0;
- off_t pos=0;
- off_t begin=0;
-
- len += sprintf (buffer,"%-11s%-13s%s\n",
- "Network", "Router_Net", "Router_Node");
- for (rt = ipx_routes; rt != NULL; rt = rt->ir_next)
- {
- len += sprintf (buffer+len,"%08lX ", ntohl(rt->ir_net));
- if (rt->ir_routed) {
- len += sprintf (buffer+len,"%08lX %02X%02X%02X%02X%02X%02X\n",
- ntohl(rt->ir_intrfc->if_netnum),
- rt->ir_router_node[0], rt->ir_router_node[1],
- rt->ir_router_node[2], rt->ir_router_node[3],
- rt->ir_router_node[4], rt->ir_router_node[5]);
- } else {
- len += sprintf (buffer+len, "%-13s%s\n",
- "Directly", "Connected");
- }
- pos=begin+len;
- if(pos<offset)
- {
- len=0;
- begin=pos;
- }
- if(pos>offset+length)
- break;
- }
- *start=buffer+(offset-begin);
- len-=(offset-begin);
- if(len>length)
- len=length;
- return len;
-}
-
-/*******************************************************************************************************************\
-* *
-* Handling for system calls applied via the various interfaces to an IPX socket object *
-* *
-\*******************************************************************************************************************/
-
-static int ipx_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg)
-{
- switch(cmd)
- {
- default:
- return(-EINVAL);
- }
-}
-
-static int ipx_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen)
-{
- ipx_socket *sk;
- int err,opt;
-
- sk=(ipx_socket *)sock->data;
-
- if(optval==NULL)
- return(-EINVAL);
-
- err=verify_area(VERIFY_READ,optval,sizeof(int));
- if(err)
- return err;
- opt=get_fs_long((unsigned long *)optval);
-
- switch(level)
- {
- case SOL_IPX:
- switch(optname)
- {
- case IPX_TYPE:
- sk->ipx_type=opt;
- return 0;
- default:
- return -EOPNOTSUPP;
- }
- break;
-
- case SOL_SOCKET:
- return sock_setsockopt(sk,level,optname,optval,optlen);
-
- default:
- return -EOPNOTSUPP;
- }
-}
-
-static int ipx_getsockopt(struct socket *sock, int level, int optname,
- char *optval, int *optlen)
-{
- ipx_socket *sk;
- int val=0;
- int err;
-
- sk=(ipx_socket *)sock->data;
-
- switch(level)
- {
-
- case SOL_IPX:
- switch(optname)
- {
- case IPX_TYPE:
- val=sk->ipx_type;
- break;
- default:
- return -ENOPROTOOPT;
- }
- break;
-
- case SOL_SOCKET:
- return sock_getsockopt(sk,level,optname,optval,optlen);
-
- default:
- return -EOPNOTSUPP;
- }
- err=verify_area(VERIFY_WRITE,optlen,sizeof(int));
- if(err)
- return err;
- put_fs_long(sizeof(int),(unsigned long *)optlen);
- err=verify_area(VERIFY_WRITE,optval,sizeof(int));
- put_fs_long(val,(unsigned long *)optval);
- return(0);
-}
-
-static int ipx_listen(struct socket *sock, int backlog)
-{
- return -EOPNOTSUPP;
-}
-
-static void def_callback1(struct sock *sk)
-{
- if(!sk->dead)
- wake_up_interruptible(sk->sleep);
-}
-
-static void def_callback2(struct sock *sk, int len)
-{
- if(!sk->dead)
- {
- wake_up_interruptible(sk->sleep);
- sock_wake_async(sk->socket, 1);
- }
-}
-
-static int
-ipx_create(struct socket *sock, int protocol)
-{
- ipx_socket *sk;
- sk=(ipx_socket *)kmalloc(sizeof(*sk),GFP_KERNEL);
- if(sk==NULL)
- return(-ENOMEM);
- switch(sock->type)
- {
- case SOCK_DGRAM:
- break;
- default:
- kfree_s((void *)sk,sizeof(*sk));
- return(-ESOCKTNOSUPPORT);
- }
- sk->dead=0;
- sk->next=NULL;
- sk->broadcast=0;
- sk->rcvbuf=SK_RMEM_MAX;
- sk->sndbuf=SK_WMEM_MAX;
- sk->wmem_alloc=0;
- sk->rmem_alloc=0;
- sk->inuse=0;
- sk->shutdown=0;
- sk->prot=NULL; /* So we use default free mechanisms */
- sk->broadcast=0;
- sk->err=0;
- skb_queue_head_init(&sk->receive_queue);
- skb_queue_head_init(&sk->write_queue);
- sk->send_head=NULL;
- skb_queue_head_init(&sk->back_log);
- sk->state=TCP_CLOSE;
- sk->socket=sock;
- sk->type=sock->type;
- sk->ipx_type=0; /* General user level IPX */
- sk->debug=0;
- sk->ipx_intrfc = NULL;
- memset(&sk->ipx_dest_addr,'\0',sizeof(sk->ipx_dest_addr));
- sk->ipx_port = 0;
- sk->mtu=IPX_MTU;
-
- if(sock!=NULL)
- {
- sock->data=(void *)sk;
- sk->sleep=sock->wait;
- }
-
- sk->state_change=def_callback1;
- sk->data_ready=def_callback2;
- sk->write_space=def_callback1;
- sk->error_report=def_callback1;
-
- sk->zapped=1;
- return 0;
-}
-
-static int ipx_release(struct socket *sock, struct socket *peer)
-{
- ipx_socket *sk=(ipx_socket *)sock->data;
- if(sk==NULL)
- return(0);
- if(!sk->dead)
- sk->state_change(sk);
- sk->dead=1;
- sock->data=NULL;
- ipx_destroy_socket(sk);
- return(0);
-}
-
-static int ipx_dup(struct socket *newsock,struct socket *oldsock)
-{
- return(ipx_create(newsock,SOCK_DGRAM));
-}
-
-static unsigned short
-ipx_first_free_socketnum(ipx_interface *intrfc)
-{
- unsigned short socketNum = intrfc->if_sknum;
-
- if (socketNum < IPX_MIN_EPHEMERAL_SOCKET)
- socketNum = IPX_MIN_EPHEMERAL_SOCKET;
-
- while (ipxitf_find_socket(intrfc, ntohs(socketNum)) != NULL)
- if (socketNum > IPX_MAX_EPHEMERAL_SOCKET)
- socketNum = IPX_MIN_EPHEMERAL_SOCKET;
- else
- socketNum++;
-
- intrfc->if_sknum = socketNum;
- return ntohs(socketNum);
-}
-
-static int ipx_bind(struct socket *sock, struct sockaddr *uaddr,int addr_len)
-{
- ipx_socket *sk;
- ipx_interface *intrfc;
- struct sockaddr_ipx *addr=(struct sockaddr_ipx *)uaddr;
-
- sk=(ipx_socket *)sock->data;
-
- if(sk->zapped==0)
- return -EIO;
-
- if(addr_len!=sizeof(struct sockaddr_ipx))
- return -EINVAL;
-
- intrfc = ipxitf_find_using_net(addr->sipx_network);
- if (intrfc == NULL)
- return -EADDRNOTAVAIL;
-
- if (addr->sipx_port == 0) {
- addr->sipx_port = ipx_first_free_socketnum(intrfc);
- if (addr->sipx_port == 0)
- return -EINVAL;
- }
-
- if(ntohs(addr->sipx_port)<IPX_MIN_EPHEMERAL_SOCKET && !suser())
- return -EPERM; /* protect IPX system stuff like routing/sap */
-
- /* Source addresses are easy. It must be our network:node pair for
- an interface routed to IPX with the ipx routing ioctl() */
-
- if(ipxitf_find_socket(intrfc, addr->sipx_port)!=NULL) {
- if(sk->debug)
- printk("IPX: bind failed because port %X in use.\n",
- (int)addr->sipx_port);
- return -EADDRINUSE;
- }
-
- sk->ipx_port=addr->sipx_port;
- ipxitf_insert_socket(intrfc, sk);
- sk->zapped=0;
- if(sk->debug)
- printk("IPX: socket is bound.\n");
- return 0;
-}
-
-static int ipx_connect(struct socket *sock, struct sockaddr *uaddr,
- int addr_len, int flags)
-{
- ipx_socket *sk=(ipx_socket *)sock->data;
- struct sockaddr_ipx *addr;
-
- sk->state = TCP_CLOSE;
- sock->state = SS_UNCONNECTED;
-
- if(addr_len!=sizeof(*addr))
- return(-EINVAL);
- addr=(struct sockaddr_ipx *)uaddr;
-
- if(sk->ipx_port==0)
- /* put the autobinding in */
- {
- struct sockaddr_ipx uaddr;
- int ret;
-
- uaddr.sipx_port = 0;
- uaddr.sipx_network = 0L;
- ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
- if (ret != 0) return (ret);
- }
-
- if(ipxrtr_lookup(addr->sipx_network)==NULL)
- return -ENETUNREACH;
- sk->ipx_dest_addr.net=addr->sipx_network;
- sk->ipx_dest_addr.sock=addr->sipx_port;
- memcpy(sk->ipx_dest_addr.node,addr->sipx_node,IPX_NODE_LEN);
- sk->ipx_type=addr->sipx_type;
- sock->state = SS_CONNECTED;
- sk->state=TCP_ESTABLISHED;
- return 0;
-}
-
-static int ipx_socketpair(struct socket *sock1, struct socket *sock2)
-{
- return(-EOPNOTSUPP);
-}
-
-static int ipx_accept(struct socket *sock, struct socket *newsock, int flags)
-{
- if(newsock->data)
- kfree_s(newsock->data,sizeof(ipx_socket));
- return -EOPNOTSUPP;
-}
-
-static int ipx_getname(struct socket *sock, struct sockaddr *uaddr,
- int *uaddr_len, int peer)
-{
- ipx_address *addr;
- struct sockaddr_ipx sipx;
- ipx_socket *sk;
-
- sk=(ipx_socket *)sock->data;
-
- *uaddr_len = sizeof(struct sockaddr_ipx);
-
- if(peer) {
- if(sk->state!=TCP_ESTABLISHED)
- return -ENOTCONN;
- addr=&sk->ipx_dest_addr;
- sipx.sipx_network = addr->net;
- memcpy(sipx.sipx_node,addr->node,IPX_NODE_LEN);
- sipx.sipx_port = addr->sock;
- } else {
- if (sk->ipx_intrfc != NULL) {
- sipx.sipx_network = sk->ipx_intrfc->if_netnum;
- memcpy(sipx.sipx_node, sk->ipx_intrfc->if_node,
- IPX_NODE_LEN);
- } else {
- sipx.sipx_network = 0L;
- memset(sipx.sipx_node, '\0', IPX_NODE_LEN);
- }
- sipx.sipx_port = sk->ipx_port;
- }
-
- sipx.sipx_family = AF_IPX;
- sipx.sipx_type = sk->ipx_type;
- memcpy(uaddr,&sipx,sizeof(sipx));
- return 0;
-}
-
-#if 0
-/*
- * User to dump IPX packets (debugging)
- */
-void dump_data(char *str,unsigned char *d) {
- static char h2c[] = "0123456789ABCDEF";
- int l,i;
- char *p, b[64];
- for (l=0;l<16;l++) {
- p = b;
- for (i=0; i < 8 ; i++) {
- *(p++) = h2c[d[i] & 0x0f];
- *(p++) = h2c[(d[i] >> 4) & 0x0f];
- *(p++) = ' ';
- }
- *(p++) = '-';
- *(p++) = ' ';
- for (i=0; i < 8 ; i++) *(p++) = ' '<= d[i] && d[i]<'\177' ? d[i] : '.';
- *p = '\000';
- d += i;
- printk("%s-%04X: %s\n",str,l*8,b);
- }
-}
-
-void dump_addr(char *str,ipx_address *p) {
- printk("%s: %08X:%02X%02X%02X%02X%02X%02X:%04X\n",
- str,ntohl(p->net),p->node[0],p->node[1],p->node[2],
- p->node[3],p->node[4],p->node[5],ntohs(p->sock));
-}
-
-void dump_hdr(char *str,ipx_packet *p) {
- printk("%s: CHKSUM=%04X SIZE=%d (%04X) HOPS=%d (%02X) TYPE=%02X\n",
- str,p->ipx_checksum,ntohs(p->ipx_pktsize),ntohs(p->ipx_pktsize),
- p->ipx_tctrl,p->ipx_tctrl,p->ipx_type);
- dump_addr(" IPX-DST",&p->ipx_dest);
- dump_addr(" IPX-SRC",&p->ipx_source);
-}
-
-void dump_pkt(char *str,ipx_packet *p) {
- dump_hdr(str,p);
- dump_data(str,(unsigned char *)p);
-}
-#endif
-
-int ipx_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
-{
- /* NULL here for pt means the packet was looped back */
- ipx_interface *intrfc;
- ipx_packet *ipx;
-
- ipx=(ipx_packet *)skb->h.raw;
-
- if(ipx->ipx_checksum!=IPX_NO_CHECKSUM) {
- /* We don't do checksum options. We can't really. Novell don't seem to have documented them.
- If you need them try the XNS checksum since IPX is basically XNS in disguise. It might be
- the same... */
- kfree_skb(skb,FREE_READ);
- return 0;
- }
-
- /* Too small */
- if(htons(ipx->ipx_pktsize)<sizeof(ipx_packet)) {
- kfree_skb(skb,FREE_READ);
- return 0;
- }
-
- /* Determine what local ipx endpoint this is */
- intrfc = ipxitf_find_using_phys(dev, pt->type);
- if (intrfc == NULL) {
- if (ipxcfg_auto_create_interfaces) {
- intrfc = ipxitf_auto_create(dev, pt->type);
- }
-
- if (intrfc == NULL) {
- /* Not one of ours */
- kfree_skb(skb,FREE_READ);
- return 0;
- }
- }
-
- return ipxitf_rcv(intrfc, skb);
-}
-
-static int ipx_sendto(struct socket *sock, void *ubuf, int len, int noblock,
- unsigned flags, struct sockaddr *usip, int addr_len)
-{
- ipx_socket *sk=(ipx_socket *)sock->data;
- struct sockaddr_ipx *usipx=(struct sockaddr_ipx *)usip;
- struct sockaddr_ipx local_sipx;
- int retval;
-
- if (sk->zapped) return -EIO; /* Socket not bound */
- if(flags) return -EINVAL;
-
- if(usipx) {
- if(sk->ipx_port == 0) {
- struct sockaddr_ipx uaddr;
- int ret;
-
- uaddr.sipx_port = 0;
- uaddr.sipx_network = 0L;
- ret = ipx_bind (sock, (struct sockaddr *)&uaddr, sizeof(struct sockaddr_ipx));
- if (ret != 0) return ret;
- }
-
- if(addr_len <sizeof(*usipx))
- return -EINVAL;
- if(usipx->sipx_family != AF_IPX)
- return -EINVAL;
- } else {
- if(sk->state!=TCP_ESTABLISHED)
- return -ENOTCONN;
- usipx=&local_sipx;
- usipx->sipx_family=AF_IPX;
- usipx->sipx_type=sk->ipx_type;
- usipx->sipx_port=sk->ipx_dest_addr.sock;
- usipx->sipx_network=sk->ipx_dest_addr.net;
- memcpy(usipx->sipx_node,sk->ipx_dest_addr.node,IPX_NODE_LEN);
- }
-
- retval = ipxrtr_route_packet(sk, usipx, ubuf, len);
- if (retval < 0) return retval;
-
- return len;
-}
-
-static int ipx_send(struct socket *sock, void *ubuf, int size, int noblock, unsigned flags)
-{
- return ipx_sendto(sock,ubuf,size,noblock,flags,NULL,0);
-}
-
-static int ipx_recvfrom(struct socket *sock, void *ubuf, int size, int noblock,
- unsigned flags, struct sockaddr *sip, int *addr_len)
-{
- ipx_socket *sk=(ipx_socket *)sock->data;
- struct sockaddr_ipx *sipx=(struct sockaddr_ipx *)sip;
- struct ipx_packet *ipx = NULL;
- int copied = 0;
- int truesize;
- struct sk_buff *skb;
- int er;
-
- if(sk->err)
- {
- er= -sk->err;
- sk->err=0;
- return er;
- }
-
- if (sk->zapped)
- return -EIO;
-
- if(addr_len)
- *addr_len=sizeof(*sipx);
-
- skb=skb_recv_datagram(sk,flags,noblock,&er);
- if(skb==NULL)
- return er;
-
- ipx = (ipx_packet *)(skb->h.raw);
- truesize=ntohs(ipx->ipx_pktsize) - sizeof(ipx_packet);
- copied = (truesize > size) ? size : truesize;
- skb_copy_datagram(skb,sizeof(struct ipx_packet),ubuf,copied);
-
- if(sipx)
- {
- 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=ipx->ipx_source.net;
- sipx->sipx_type = ipx->ipx_type;
- }
- skb_free_datagram(skb);
- return(truesize);
-}
-
-static int ipx_write(struct socket *sock, char *ubuf, int size, int noblock)
-{
- return ipx_send(sock,ubuf,size,noblock,0);
-}
-
-
-static int ipx_recv(struct socket *sock, void *ubuf, int size , int noblock,
- unsigned flags)
-{
- ipx_socket *sk=(ipx_socket *)sock->data;
- if(sk->zapped)
- return -ENOTCONN;
- return ipx_recvfrom(sock,ubuf,size,noblock,flags,NULL, NULL);
-}
-
-static int ipx_read(struct socket *sock, char *ubuf, int size, int noblock)
-{
- return ipx_recv(sock,ubuf,size,noblock,0);
-}
-
-
-static int ipx_shutdown(struct socket *sk,int how)
-{
- return -EOPNOTSUPP;
-}
-
-static int ipx_select(struct socket *sock , int sel_type, select_table *wait)
-{
- ipx_socket *sk=(ipx_socket *)sock->data;
-
- return datagram_select(sk,sel_type,wait);
-}
-
-static int ipx_ioctl(struct socket *sock,unsigned int cmd, unsigned long arg)
-{
- int err;
- long amount=0;
- ipx_socket *sk=(ipx_socket *)sock->data;
-
- switch(cmd)
- {
- case TIOCOUTQ:
- err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long));
- if(err)
- return err;
- amount=sk->sndbuf-sk->wmem_alloc;
- if(amount<0)
- amount=0;
- put_fs_long(amount,(unsigned long *)arg);
- return 0;
- case TIOCINQ:
- {
- struct sk_buff *skb;
- /* These two are safe on a single CPU system as only user tasks fiddle here */
- if((skb=skb_peek(&sk->receive_queue))!=NULL)
- amount=skb->len;
- err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(unsigned long));
- put_fs_long(amount,(unsigned long *)arg);
- return 0;
- }
- case SIOCADDRT:
- case SIOCDELRT:
- if(!suser())
- return -EPERM;
- return(ipxrtr_ioctl(cmd,(void *)arg));
- case SIOCSIFADDR:
- case SIOCGIFADDR:
- case SIOCAIPXITFCRT:
- case SIOCAIPXPRISLT:
- if(!suser())
- return -EPERM;
- return(ipxitf_ioctl(cmd,(void *)arg));
- case SIOCIPXCFGDATA:
- {
- err=verify_area(VERIFY_WRITE,(void *)arg,
- sizeof(ipx_config_data));
- if(err) return err;
- return(ipxcfg_get_config_data((void *)arg));
- }
- case SIOCGSTAMP:
- if (sk)
- {
- if(sk->stamp.tv_sec==0)
- return -ENOENT;
- err=verify_area(VERIFY_WRITE,(void *)arg,sizeof(struct timeval));
- if(err)
- return err;
- memcpy_tofs((void *)arg,&sk->stamp,sizeof(struct timeval));
- return 0;
- }
- return -EINVAL;
- case SIOCGIFDSTADDR:
- case SIOCSIFDSTADDR:
- case SIOCGIFBRDADDR:
- case SIOCSIFBRDADDR:
- case SIOCGIFNETMASK:
- case SIOCSIFNETMASK:
- return -EINVAL;
- default:
- return(dev_ioctl(cmd,(void *) arg));
- }
- /*NOTREACHED*/
- return(0);
-}
-
-static struct proto_ops ipx_proto_ops = {
- AF_IPX,
-
- ipx_create,
- ipx_dup,
- ipx_release,
- ipx_bind,
- ipx_connect,
- ipx_socketpair,
- ipx_accept,
- ipx_getname,
- ipx_read,
- ipx_write,
- ipx_select,
- ipx_ioctl,
- ipx_listen,
- ipx_send,
- ipx_recv,
- ipx_sendto,
- ipx_recvfrom,
- ipx_shutdown,
- ipx_setsockopt,
- ipx_getsockopt,
- ipx_fcntl,
-};
-
-/* Called by ddi.c on kernel start up */
-
-static struct packet_type ipx_8023_packet_type =
-
-{
- 0, /* MUTTER ntohs(ETH_P_8023),*/
- NULL, /* All devices */
- ipx_rcv,
- NULL,
- NULL,
-};
-
-static struct packet_type ipx_dix_packet_type =
-{
- 0, /* MUTTER ntohs(ETH_P_IPX),*/
- NULL, /* All devices */
- ipx_rcv,
- NULL,
- NULL,
-};
-
-static struct notifier_block ipx_dev_notifier={
- ipxitf_device_event,
- NULL,
- 0
-};
-
-
-extern struct datalink_proto *make_EII_client(void);
-extern struct datalink_proto *make_8023_client(void);
-
-void ipx_proto_init(struct net_proto *pro)
-{
- unsigned char val = 0xE0;
- unsigned char snapval[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
-
- (void) sock_register(ipx_proto_ops.family, &ipx_proto_ops);
-
- pEII_datalink = make_EII_client();
- ipx_dix_packet_type.type=htons(ETH_P_IPX);
- dev_add_pack(&ipx_dix_packet_type);
-
- p8023_datalink = make_8023_client();
- ipx_8023_packet_type.type=htons(ETH_P_802_3);
- dev_add_pack(&ipx_8023_packet_type);
-
- if ((p8022_datalink = register_8022_client(val, ipx_rcv)) == NULL)
- printk("IPX: Unable to register with 802.2\n");
-
- if ((pSNAP_datalink = register_snap_client(snapval, ipx_rcv)) == NULL)
- printk("IPX: Unable to register with SNAP\n");
-
- register_netdevice_notifier(&ipx_dev_notifier);
-
- printk("Swansea University Computer Society IPX 0.29 BETA for NET3.019\n");
- printk("IPX Portions Copyright (c) 1995 Caldera, Inc.\n");
-}
-#endif