IPXRIPD (IPX Router for Netware)

IPXRIPD (IPX Router for Netware)

Post by Unitrendix Co » Mon, 02 Jan 1995 07:02:36



I have uploaded the following software to
        sunsite.unc.edu:/pub/Linux/Incoming/ipxripd-002.tar.gz
It should eventualy be moved to /pub/Linux/system/Network/router.

Announcment of IPXRIPD (version Alpha 0.02)

This program implements Novell's IPX RIP/SAP protocols (See "IPX
router specification" from Novell).  This along with the IPX support
already built into the Linux kernel will convert a Linux box into a
IPX router.

There is a problem with the Linux forwarding code.  Included at the
end of this post is a patch for it.  (BTW, how does one submit fixes
or patches to the kernel?  Since this is for the IPX code, should it
be submitted to Linus or to Alan Cox?)

The kernel patch does the following:
        Fixes the forwarding code
        Displays the frame type on the routes listing
        Prevents packets destined to the current node that came from
        a different netwok to be send to the wire again

LSM for IPXRIPD

Begin3
Title:          ipxripd
Version:        Alpha v0.02
Entered-date:   29DEC94
Description:    IPX Routing and SAP protocol daemons.  Turns your Linux
                box into a IPX router (and SAP agent).
                Includes a kernel patch to fix a problem with IPX routing.
Keywords:       IPX router RIP SAP Netware
Author:         lab...@unitrx.com (Alex Liu)
Maintained-by:  lab...@unitrx.com (Alex Liu)
Primary-site:   sunsite.unc.edu /pub/Linux/system/Network/router
                67kB ipxripd-002.tar.gz
Platform:       Kernel with IPX support compiled in.
Copying-policy: Public domain
End

README file for IPXRIPD

        IPXRIPD, Alpha version 0.02

This program has been placed under the public domain.

This software is intended to run under the Linux operating system.  It
implements the IPX RIP/SAP protocols as described in the "IPX Router
Specification" from Novell Inc.  (Nov 17,1992; Version 1.10; Part
Number: 107-000029-001).

The Linux kernel supports the IPX protocol.  The Linux kernel
implementation has some code for IPX packet forwarding except for the
NetBIOS flood-fill forwarding mode.

Unfortunaly, even though the Kernel supports packet forwarding, it is
missing the RIP/SAP protocol functionality to act like a real IPX
router.  This program provides the RIP/SAP functionality.

This RIP/SAP is simmilar in functionality to TCP/IP's ROUTED or GATED
daemons.  In TCP/IP, the kernel provides gatewaying support, however,
routes and route broadcasting is done trough ROUTED/GATED daemons.
TCP/IP unlike IPX has the option of using static routes.  IPX on the
other hands very seldom uses static routes but mostly uses dynamic
routes.  Dynamic routes are propagated using a RIP/SAP daemon.

Ok, basically, this program will load a file "networks.ipx" to
initialize network numbers.  Then will start listening on IPX sockets
0x0452 and 0x0453 waiting for RIP and SAP broadcast.  As RIP/SAP
packets are received, it will udpate its internal tables (including
the network ipx routing tables).  The program will also broadcast
routes and services to other networks.  This program will also process
SAP and RIP request.

The format of "networks.ipx" file is one network per line.  The # is
used as a comment.  The first field is used to identify the network
interface.  (Use ifconfig to list interfaces).  The second field used
to specify a frame type.  Options are: 802.3, 802.2, Ethernet_II and
SNAP.  (SNAP is not supported by the Linux kernel as of v1.1.73).  The
third number is the network number.  This is a hex number.  The same
number you would use in your novell server.

NOTES on Linux v1.1.73
I have only tested this software under Linux kernel v1.1.73. (There has
been no changes in the IPX code on kernels trough 1.1.75 so this still
should work).

The standard IPX code in the kernel (v1.1.73) has a problem with
forwarding packets of different frames.  Included there is a context
diff file (kpatch.dif) to fix it.  It also contains a couple of
"improvements" over the ipx code.  To apply cd to the kernel's
net/inet subdirectory and run "patch < path_to/kpatch.dif".

Apparently, the IPX support in the Linux kernel there is not too stable.
At some point, this code may or may not cause kernel panics.  (Happen
to me a couple of times for no apparent reason).
BTW, you can't use Linux as a remote IPX router trough PPP or SLIP.
You probably will have to use an IP tunnel for that.  This version
of the software does not support IP tunnels so you will need a real
Novell server for that.

Again, this is ALPHA code so don't expect it to work.  Since I have
limited resouces I have only been able to test the IPX router as frame
converter.  (i.e. The netware server uses frame type 802.3.  The
netware client uses frame type Ethernet_II.  Then I use the Linux box,
acting as router to convert from one type to the other).

Alex Liu
lab...@unitrx.com

Kernel patch.  (Apply to linux v1.1.73/net/inet/ipx.c)

*** ipx.orig    Fri Nov 18 05:17:48 1994
--- ipx.c       Sun Jan  1 11:40:29 1995
***************
*** 431,436 ****
--- 431,447 ----
  }

  /* Called from proc fs */
+ static char *int2frame(int frame) {
+   static char fmt[6];
+   switch (frame) {
+   case ETH_P_SNAP:    return "SNAP";
+   case ETH_P_IPX:     return "Ethernet_II";
+   case ETH_P_802_2:   return "802.2";
+   case ETH_P_802_3:   return "802.3";
+   default:            sprintf(fmt,"%04X",frame); return fmt;
+   }
+ }
+
  int ipx_rt_get_info(char *buffer, char **start, off_t offset, int length)
  {
        ipx_route *rt;
***************
*** 438,449 ****
        off_t pos=0;
        off_t begin=0;

!       len += sprintf (buffer,"Net      Router                Flags Dev\n");
        for (rt = ipx_router_list; rt != NULL; rt = rt->next)
        {
!               len += sprintf (buffer+len,"%08lX %08lX:%02X%02X%02X%02X%02X%02X %02X    %s\n", ntohl(rt->net),
                        ntohl(rt->router_net), rt->router_node[0], rt->router_node[1], rt->router_node[2],
!                       rt->router_node[3], rt->router_node[4], rt->router_node[5], rt->flags, rt->dev->name);
                pos=begin+len;
                if(pos<offset)
                {
--- 449,460 ----
        off_t pos=0;
        off_t begin=0;

!       len += sprintf (buffer,"Net      Router                Flags Dev   Frame\n");
        for (rt = ipx_router_list; rt != NULL; rt = rt->next)
        {
!               len += sprintf (buffer+len,"%08lX %08lX:%02X%02X%02X%02X%02X%02X %02X    %-5s %s\n", ntohl(rt->net),
                        ntohl(rt->router_net), rt->router_node[0], rt->router_node[1], rt->router_node[2],
!                       rt->router_node[3], rt->router_node[4], rt->router_node[5], rt->flags, rt->dev->name,int2frame(ntohs(rt->dlink_type)));
                pos=begin+len;
                if(pos<offset)
                {
***************
*** 804,809 ****
--- 815,864 ----
        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 */
***************
*** 883,888 ****
--- 938,950 ----
                        return(0);
                }

+               /* Ok, before we forward, make sure this is not a local packet on the */
+               /* other network */
+               if (rt->router_net == 0) {
+                       memset(IPXaddr,'\0',6);
+                       memcpy(IPXaddr+(6-rt->dev->addr_len),rt->dev->dev_addr,rt->dev->addr_len);
+                       if (memcmp(IPXaddr,ipx->ipx_dest.node,6) == 0) goto DELIVER;
+               }
                /* Check for differences in outgoing and incoming packet size */
                incoming_size = skb->len - ntohs(ipx->ipx_pktsize);
                outgoing_size = rt->datalink->header_length + rt->dev->hard_header_len;
***************
*** 890,895 ****
--- 952,965 ----
                {
                        /* A different header length causes a copy. Awkward to avoid with the current
                           sk_buff stuff. */
+ /*
+                       printk("IPX: Forwarding with resize\n");
+                       printk("IPX: IN=%d OUT=%d LEN=%d PKS=%d HD=%d HL=%d\n",
+                              incoming_size,outgoing_size,
+                              skb->len,ntohs(ipx->ipx_pktsize),
+                              rt->datalink->header_length,
+                              rt->dev->hard_header_len);
+  */
                        skb2=alloc_skb(ntohs(ipx->ipx_pktsize) + outgoing_size,
                                        GFP_ATOMIC);
                        if(skb2==NULL)
***************
*** 898,912 ****
                                return 0;
                        }
                        free_it=1;
-                       skb2->free=1;
-                       skb2->len=ntohs(ipx->ipx_pktsize) + outgoing_size;
                        skb2->mem_addr = skb2;
-                       skb2->arp = 1;
                        skb2->sk = NULL;

                        /* Need to copy with appropriate offsets */
!                       memcpy((char *)(skb2+1)+outgoing_size,
!                               (char *)(skb+1)+incoming_size,
                                ntohs(ipx->ipx_pktsize));
                }
                else
--- 968,986 ----
                                return 0;
                        }
                        free_it=1;
                        skb2->mem_addr = skb2;
                        skb2->sk = NULL;
+                       skb2->free=1;
+                       skb2->arp = 1;
+                       skb2->len=ntohs(ipx->ipx_pktsize) + outgoing_size;

                        /* Need to copy with appropriate offsets */
!                       /*
!                          NOTE: src arg for memcpy used to be (skb+1)+insize
!                          however, that doesn't work... (dunno why)
!                          it should though...
!                          */
!                       memcpy((char *)(skb2+1)+outgoing_size,ipx,
                                ntohs(ipx->ipx_pktsize));
                }
                else
***************
*** 929,935 ****
                return(0);
        }
        /************ End of router: Now sanity check stuff for us ***************/
!      
        /* Ok its for us ! */
        if (ln->net == 0L) {
  /*            printk("IPX: Registering local net %lx\n", ipx->ipx_dest.net);*/
--- 1003,1009 ----
                return(0);
        }
        /************ End of router: Now sanity check stuff for us ***************/
! DELIVER:      
        /* Ok its for us ! */
        if (ln->net == 0L) {
  /*            printk("IPX: Registering local net %lx\n", ipx->ipx_dest.net);*/
***************
*** 1317,1322 ****
--- 1391,1397 ----
  /* Called by ddi.c on kernel start up */

  static struct packet_type ipx_8023_packet_type =
+
  {
        0,      /* MUTTER ntohs(ETH_P_8023),*/
        0,              /* copy */