replaced by maths.h
[btb/d2x.git] / unused / bios / ipx.c
1 /*
2 THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
3 SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
4 END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
5 ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
6 IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
7 SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
8 FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
9 CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
10 AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
11 COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14
15 #pragma off (unreferenced)
16 static char rcsid[] = "$Id: ipx.c,v 1.1.1.1 2001-01-19 03:30:14 bradleyb Exp $";
17 #pragma on (unreferenced)
18
19 #include <i86.h>
20 #include <dos.h>
21 #include <stdio.h>
22 #include <string.h>
23 #include <malloc.h>
24 #include <stdlib.h>
25 #include <conio.h>
26 #include <assert.h>
27
28 #include "types.h"
29 #include "timer.h"
30 #include "ipx.h"
31 #include "error.h"
32 #include "dpmi.h"
33 #include "key.h"
34
35 typedef unsigned char BYTE;
36 typedef unsigned short WORD;
37 typedef unsigned long DWORD;
38
39 typedef struct local_address {
40         ubyte address[6];
41 } local_address;
42
43 typedef struct net_address {
44         BYTE                            network_id[4];                  
45         local_address   node_id;
46         WORD                            socket_id;
47 } net_address;
48
49 typedef struct ipx_header {
50         WORD                    checksum;
51         WORD                    length;
52         BYTE                    transport_control;
53         BYTE                    packet_type;
54         net_address     destination;
55         net_address     source;
56 } ipx_header;
57
58 typedef struct ecb_header {
59         WORD                    link[2];
60         WORD                    esr_address[2];
61         BYTE                    in_use;
62         BYTE                    completion_code;
63         WORD                    socket_id;
64         BYTE                    ipx_reserved[14];        
65         WORD                    connection_id;
66         local_address immediate_address;
67         WORD                    fragment_count;
68         WORD                    fragment_pointer[2];
69         WORD                    fragment_size;
70 } ecb_header;
71
72 typedef struct packet_data {
73         int                     packetnum;
74         byte                    data[IPX_MAX_DATA_SIZE];
75 } packet_data;
76
77 typedef struct ipx_packet {
78         ecb_header      ecb;
79         ipx_header      ipx;
80         packet_data     pd;
81 } ipx_packet;
82
83 typedef struct user_address {
84         ubyte network[4];
85         ubyte node[6];
86         ubyte address[6];
87 } user_address;
88
89 #define MAX_USERS 64
90 int Ipx_num_users = 0;
91 user_address Ipx_users[MAX_USERS];
92
93 #define MAX_NETWORKS 64
94 int Ipx_num_networks = 0;
95 uint Ipx_networks[MAX_NETWORKS];
96
97 int ipx_packetnum = 0;
98
99 #define MAX_PACKETS 64
100
101 static packet_data packet_buffers[MAX_PACKETS];
102 static short packet_free_list[MAX_PACKETS];
103 static int num_packets = 0;
104 static int largest_packet_index = 0;
105 static short packet_size[MAX_PACKETS];
106
107 WORD ipx_socket=0;
108 ubyte ipx_installed=0;
109 WORD ipx_vector_segment;
110 WORD ipx_vector_offset;
111 ubyte ipx_socket_life = 0;      // 0=closed at prog termination, 0xff=closed when requested.
112 DWORD ipx_network = 0;
113 local_address ipx_my_node;
114 WORD ipx_num_packets=32;                // 32 Ipx packets
115 ipx_packet * packets;
116 int neterrors = 0;
117 ushort ipx_packets_selector;
118
119 ecb_header * last_ecb=NULL;
120 int lastlen=0;
121
122 void free_packet( int id )
123 {
124         packet_buffers[id].packetnum = -1;
125         packet_free_list[ --num_packets ] = id;
126         if (largest_packet_index==id)   
127                 while ((--largest_packet_index>0) && (packet_buffers[largest_packet_index].packetnum == -1 ));
128 }
129
130 int ipx_get_packet_data( ubyte * data )
131 {
132         int i, n, best, best_id, size;
133
134         for (i=1; i<ipx_num_packets; i++ )      {
135                 if ( !packets[i].ecb.in_use )   {
136                         got_new_packet( &packets[i].ecb );
137                         packets[i].ecb.in_use = 0;
138                         ipx_listen_for_packet(&packets[i].ecb);
139                 }                       
140         }
141
142         best = -1;
143         n = 0;
144         best_id = -1;
145
146         for (i=0; i<=largest_packet_index; i++ )        {
147                 if ( packet_buffers[i].packetnum > -1 ) {
148                         n++;
149                         if ( best == -1 || (packet_buffers[i].packetnum<best) ) {
150                                 best = packet_buffers[i].packetnum;
151                                 best_id = i;
152                         }
153                 }                       
154         }
155
156         //mprintf( (0, "Best id = %d, pn = %d, last_ecb = %x, len=%x, ne = %d\n", best_id, best, last_ecb, lastlen, neterrors ));
157         //mprintf( (1, "<%d> ", neterrors ));
158
159         if ( best_id < 0 ) return 0;
160
161         size = packet_size[best_id];
162         memcpy( data, packet_buffers[best_id].data, size );
163         free_packet(best_id);
164
165         return size;
166 }
167
168 unsigned int swap_short( unsigned int short );
169 #pragma aux swap_short parm [eax] = "xchg al,ah";
170
171 void got_new_packet( ecb_header * ecb )
172 {
173         ipx_packet * p;
174         int id;
175         unsigned short datasize;
176
177         datasize = 0;
178         last_ecb = ecb;
179         p = (ipx_packet *)ecb;
180
181         if ( p->ecb.in_use ) { neterrors++; return; }
182         if      ( p->ecb.completion_code )      { neterrors++; return; }
183
184         //      Error( "Recieve error %d for completion code", p->ecb.completion_code );
185         
186         if ( memcmp( &p->ipx.source.node_id, &ipx_my_node, 6 ) )        {
187                 datasize=swap_short(p->ipx.length);
188                 lastlen=datasize;
189                 datasize -= sizeof(ipx_header);
190                 // Find slot to put packet in...
191                 if ( datasize > 0 && datasize <= sizeof(packet_data) )  {
192                         if ( num_packets >= MAX_PACKETS ) {
193                                 //printf( 1, "IPX: Packet buffer overrun!!!\n" );
194                                 neterrors++;
195                                 return;
196                         }               
197                         id = packet_free_list[ num_packets++ ];
198                         if (id > largest_packet_index ) largest_packet_index = id;
199                         packet_size[id] = datasize-sizeof(int);
200                         packet_buffers[id].packetnum =  p->pd.packetnum;
201                         if ( packet_buffers[id].packetnum < 0 ) { neterrors++; return; }
202                         memcpy( packet_buffers[id].data, p->pd.data, packet_size[id] );
203                 } else {
204                         neterrors++; return;
205                 }
206         } 
207         // Repost the ecb
208         p->ecb.in_use = 0;
209         //ipx_listen_for_packet(&p->ecb);
210 }
211
212 ubyte * ipx_get_my_local_address()
213 {
214         return ipx_my_node.address;
215 }
216
217 ubyte * ipx_get_my_server_address()
218 {
219         return (ubyte *)&ipx_network;
220 }
221
222 void ipx_listen_for_packet(ecb_header * ecb )   
223 {
224         dpmi_real_regs rregs;
225         ecb->in_use = 0x1d;
226         memset(&rregs,0,sizeof(dpmi_real_regs));
227         rregs.ebx = 4;  // Listen For Packet function
228         rregs.esi = DPMI_real_offset(ecb);
229         rregs.es = DPMI_real_segment(ecb);
230         dpmi_real_int386x( 0x7A, &rregs );
231 }
232
233 void ipx_cancel_listen_for_packet(ecb_header * ecb )    
234 {
235         dpmi_real_regs rregs;
236         memset(&rregs,0,sizeof(dpmi_real_regs));
237         rregs.ebx = 6;  // IPX Cancel event
238         rregs.esi = DPMI_real_offset(ecb);
239         rregs.es = DPMI_real_segment(ecb);
240         dpmi_real_int386x( 0x7A, &rregs );
241 }
242
243
244 void ipx_send_packet(ecb_header * ecb ) 
245 {
246         dpmi_real_regs rregs;
247         memset(&rregs,0,sizeof(dpmi_real_regs));
248         rregs.ebx = 3;  // Send Packet function
249         rregs.esi = DPMI_real_offset(ecb);
250         rregs.es = DPMI_real_segment(ecb);
251         dpmi_real_int386x( 0x7A, &rregs );
252 }
253
254 typedef struct {
255         ubyte   network[4];
256         ubyte           node[6];
257         ubyte           local_target[6];
258 } net_xlat_info;
259
260 void ipx_get_local_target( ubyte * server, ubyte * node, ubyte * local_target )
261 {
262         net_xlat_info * info;
263         dpmi_real_regs rregs;
264                 
265         // Get dos memory for call...
266         info = (net_xlat_info *)dpmi_get_temp_low_buffer( sizeof(net_xlat_info) );      
267         assert( info != NULL );
268         memcpy( info->network, server, 4 );
269         memcpy( info->node, node, 6 );
270         
271         memset(&rregs,0,sizeof(dpmi_real_regs));
272
273         rregs.ebx = 2;          // Get Local Target     
274         rregs.es = DPMI_real_segment(info);
275         rregs.esi = DPMI_real_offset(info->network);
276         rregs.edi = DPMI_real_offset(info->local_target);
277
278         dpmi_real_int386x( 0x7A, &rregs );
279
280         // Save the local target...
281         memcpy( local_target, info->local_target, 6 );
282 }
283
284 void ipx_close()
285 {
286         dpmi_real_regs rregs;
287         if ( ipx_installed )    {
288                 // When using VLM's instead of NETX, the sockets don't
289                 // seem to automatically get closed, so we must explicitly
290                 // close them at program termination.
291                 ipx_installed = 0;
292                 memset(&rregs,0,sizeof(dpmi_real_regs));
293                 rregs.edx = ipx_socket;
294                 rregs.ebx = 1;  // Close socket
295                 dpmi_real_int386x( 0x7A, &rregs );
296         }
297 }
298
299
300 //---------------------------------------------------------------
301 // Initializes all IPX internals. 
302 // If socket_number==0, then opens next available socket.
303 // Returns:     0  if successful.
304 //                              -1 if socket already open.
305 //                              -2      if socket table full.
306 //                              -3 if IPX not installed.
307 //                              -4 if couldn't allocate low dos memory
308 //                              -5 if error with getting internetwork address
309
310 int ipx_init( int socket_number, int show_address )
311 {
312         dpmi_real_regs rregs;
313         ubyte *ipx_real_buffer;
314         int i;
315
316         atexit(ipx_close);
317
318         ipx_packetnum = 0;
319
320         // init packet buffers.
321         for (i=0; i<MAX_PACKETS; i++ )  {
322                 packet_buffers[i].packetnum = -1;
323                 packet_free_list[i] = i;
324         }
325         num_packets = 0;
326         largest_packet_index = 0;
327
328         // Get the IPX vector
329         memset(&rregs,0,sizeof(dpmi_real_regs));
330         rregs.eax=0x00007a00;
331         dpmi_real_int386x( 0x2f, &rregs );
332
333         if ( (rregs.eax & 0xFF) != 0xFF )       {
334                 return 3;   
335         }
336         ipx_vector_offset = rregs.edi & 0xFFFF;
337         ipx_vector_segment = rregs.es;
338         //printf( "IPX entry point at %.4x:%.4x\n", ipx_vector_segment, ipx_vector_offset );
339
340         // Open a socket for IPX
341
342         memset(&rregs,0,sizeof(dpmi_real_regs));
343         swab( (char *)&socket_number,(char *)&ipx_socket, 2 );
344         rregs.edx = ipx_socket;
345         rregs.eax = ipx_socket_life;
346         rregs.ebx = 0;  // Open socket
347         dpmi_real_int386x( 0x7A, &rregs );
348         
349         ipx_socket = rregs.edx & 0xFFFF;
350         
351         if ( rregs.eax & 0xFF ) {
352                 //mprintf( (1, "IPX error opening channel %d\n", socket_number-IPX_DEFAULT_SOCKET ));
353                 return -2;
354         }
355         
356         ipx_installed = 1;
357
358         // Find our internetwork address
359         ipx_real_buffer = dpmi_get_temp_low_buffer( 1024 );     // 1k block
360         if ( ipx_real_buffer == NULL )  {
361                 //printf( "Error allocation realmode memory\n" );
362                 return -4;
363         }
364
365         memset(&rregs,0,sizeof(dpmi_real_regs));
366         rregs.ebx = 9;          // Get internetwork address
367         rregs.esi = DPMI_real_offset(ipx_real_buffer);
368         rregs.es = DPMI_real_segment(ipx_real_buffer);
369         dpmi_real_int386x( 0x7A, &rregs );
370
371         if ( rregs.eax & 0xFF ) {
372                 //printf( "Error getting internetwork address!\n" );
373                 return -2;
374         }
375
376         memcpy( &ipx_network, ipx_real_buffer, 4 );
377         memcpy( &ipx_my_node, &ipx_real_buffer[4], 6 );
378
379         Ipx_num_networks = 0;
380         memcpy( &Ipx_networks[Ipx_num_networks++], &ipx_network, 4 );
381
382         if ( show_address )     {
383                 printf( "My IPX addresss is " );
384                 printf( "%02X%02X%02X%02X/", ipx_real_buffer[0],ipx_real_buffer[1],ipx_real_buffer[2],ipx_real_buffer[3] );
385                 printf( "%02X%02X%02X%02X%02X%02X\n", ipx_real_buffer[4],ipx_real_buffer[5],ipx_real_buffer[6],ipx_real_buffer[7],ipx_real_buffer[8],ipx_real_buffer[9] );
386                 printf( "\n" );
387         }
388
389         packets = dpmi_real_malloc( sizeof(ipx_packet)*ipx_num_packets, &ipx_packets_selector );
390         if ( packets == NULL )  {
391                 //printf( "Couldn't allocate real memory for %d packets\n", ipx_num_packets );
392                 return -4;
393         }
394         if (!dpmi_lock_region( packets, sizeof(ipx_packet)*ipx_num_packets ))   {
395                 //printf( "Couldn't lock real memory for %d packets\n", ipx_num_packets );
396                 return -4;
397         }
398         memset( packets, 0, sizeof(ipx_packet)*ipx_num_packets );
399
400         for (i=1; i<ipx_num_packets; i++ )      {
401                 packets[i].ecb.in_use = 0x1d;
402                 //packets[i].ecb.in_use = 0;
403                 packets[i].ecb.socket_id = ipx_socket;
404                 packets[i].ecb.fragment_count = 1;
405                 packets[i].ecb.fragment_pointer[0] = DPMI_real_offset(&packets[i].ipx);
406                 packets[i].ecb.fragment_pointer[1] = DPMI_real_segment(&packets[i].ipx);
407                 packets[i].ecb.fragment_size = sizeof(ipx_packet)-sizeof(ecb_header);                   //-sizeof(ecb_header);
408
409                 ipx_listen_for_packet(&packets[i].ecb);
410         }
411
412         packets[0].ecb.socket_id = ipx_socket;
413         packets[0].ecb.fragment_count = 1;
414         packets[0].ecb.fragment_pointer[0] = DPMI_real_offset(&packets[0].ipx);
415         packets[0].ecb.fragment_pointer[1] = DPMI_real_segment(&packets[0].ipx);
416         packets[0].ipx.packet_type = 4;         // IPX packet
417         packets[0].ipx.destination.socket_id = ipx_socket;
418 //      memcpy( packets[0].ipx.destination.network_id, &ipx_network, 4 );
419         memset( packets[0].ipx.destination.network_id, 0, 4 );
420
421         return 0;
422 }
423
424 void ipx_send_packet_data( ubyte * data, int datasize, ubyte *network, ubyte *address, ubyte *immediate_address )
425 {
426         assert(ipx_installed);
427
428         Assert(datasize < IPX_MAX_DATA_SIZE);
429
430         // Make sure no one is already sending something
431         while( packets[0].ecb.in_use )
432         {
433         }
434         
435 //      if (packets[0].ecb.completion_code)
436           //    Error("IPX: Send error %d for completion code\n", packets[0].ecb.completion_code );
437
438         // Fill in destination address
439         if ( memcmp( network, &ipx_network, 4 ) )
440                 memcpy( packets[0].ipx.destination.network_id, network, 4 );
441         else
442                 memset( packets[0].ipx.destination.network_id, 0, 4 );
443         memcpy( packets[0].ipx.destination.node_id.address, address, 6 );
444         memcpy( packets[0].ecb.immediate_address.address, immediate_address, 6 );
445         packets[0].pd.packetnum = ipx_packetnum++;
446
447         // Fill in data to send
448         packets[0].ecb.fragment_size = sizeof(ipx_header) + sizeof(int) + datasize;
449
450         assert( datasize > 1 );
451         assert( packets[0].ecb.fragment_size <= 576 );
452
453         memcpy( packets[0].pd.data, data, datasize );
454
455         // Send it
456         ipx_send_packet( &packets[0].ecb );
457
458 }
459
460 void ipx_send_broadcast_packet_data( ubyte * data, int datasize )       
461 {
462         int i, j;
463         ubyte broadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
464         ubyte local_address[6];
465
466         // Set to all networks besides mine
467         for (i=0; i<Ipx_num_networks; i++ )     {
468                 if ( memcmp( &Ipx_networks[i], &ipx_network, 4 ) )      {
469                         ipx_get_local_target( (ubyte *)&Ipx_networks[i], broadcast, local_address );
470                         ipx_send_packet_data( data, datasize, (ubyte *)&Ipx_networks[i], broadcast, local_address );
471                 } else {
472                         ipx_send_packet_data( data, datasize, (ubyte *)&Ipx_networks[i], broadcast, broadcast );
473                 }
474         }
475
476         //OLDipx_send_packet_data( data, datasize, (ubyte *)&ipx_network, broadcast, broadcast );
477
478         // Send directly to all users not on my network or in the network list.
479         for (i=0; i<Ipx_num_users; i++ )        {
480                 if ( memcmp( Ipx_users[i].network, &ipx_network, 4 ) )  {
481                         for (j=0; j<Ipx_num_networks; j++ )             {
482                                 if (!memcmp( Ipx_users[i].network, &Ipx_networks[j], 4 ))
483                                         goto SkipUser;
484                         }
485                         ipx_send_packet_data( data, datasize, Ipx_users[i].network, Ipx_users[i].node, Ipx_users[i].address );
486 SkipUser:
487                         j = 0;
488                 }
489         }
490 }
491
492 // Sends a non-localized packet... needs 4 byte server, 6 byte address
493 void ipx_send_internetwork_packet_data( ubyte * data, int datasize, ubyte * server, ubyte *address )
494 {
495         ubyte local_address[6];
496
497         if ( (*(uint *)server) != 0 )   {
498                 ipx_get_local_target( server, address, local_address );
499                 ipx_send_packet_data( data, datasize, server, address, local_address );
500         } else {
501                 // Old method, no server info.
502                 ipx_send_packet_data( data, datasize, server, address, address );
503         }
504 }
505
506 int ipx_change_default_socket( ushort socket_number )
507 {
508         int i;
509         WORD new_ipx_socket;
510         dpmi_real_regs rregs;
511
512         if ( !ipx_installed ) return -3;
513
514         // Open a new socket    
515         memset(&rregs,0,sizeof(dpmi_real_regs));
516         swab( (char *)&socket_number,(char *)&new_ipx_socket, 2 );
517         rregs.edx = new_ipx_socket;
518         rregs.eax = ipx_socket_life;
519         rregs.ebx = 0;  // Open socket
520         dpmi_real_int386x( 0x7A, &rregs );
521         
522         new_ipx_socket = rregs.edx & 0xFFFF;
523         
524         if ( rregs.eax & 0xFF ) {
525                 //printf( (1, "IPX error opening channel %d\n", socket_number-IPX_DEFAULT_SOCKET ));
526                 return -2;
527         }
528
529         for (i=1; i<ipx_num_packets; i++ )      {
530                 ipx_cancel_listen_for_packet(&packets[i].ecb);
531         }
532
533         // Close existing socket...
534         memset(&rregs,0,sizeof(dpmi_real_regs));
535         rregs.edx = ipx_socket;
536         rregs.ebx = 1;  // Close socket
537         dpmi_real_int386x( 0x7A, &rregs );
538
539         ipx_socket = new_ipx_socket;
540
541         // Repost all listen requests on the new socket...      
542         for (i=1; i<ipx_num_packets; i++ )      {
543                 packets[i].ecb.in_use = 0;
544                 packets[i].ecb.socket_id = ipx_socket;
545                 ipx_listen_for_packet(&packets[i].ecb);
546         }
547
548         packets[0].ecb.socket_id = ipx_socket;
549         packets[0].ipx.destination.socket_id = ipx_socket;
550
551         ipx_packetnum = 0;
552         // init packet buffers.
553         for (i=0; i<MAX_PACKETS; i++ )  {
554                 packet_buffers[i].packetnum = -1;
555                 packet_free_list[i] = i;
556         }
557         num_packets = 0;
558         largest_packet_index = 0;
559
560         return 0;
561 }
562
563 void ipx_read_user_file(char * filename)
564 {
565         FILE * fp;
566         user_address tmp;
567         char temp_line[132], *p1;
568         int n, ln=0;
569
570         if (!filename) return;
571
572         Ipx_num_users = 0;
573
574         fp = fopen( filename, "rt" );
575         if ( !fp ) return;
576
577         printf( "Broadcast Users:\n" );
578
579         while (fgets(temp_line, 132, fp)) {
580                 ulong net;
581                 char *np;
582                 ln++;
583                 p1 = strchr(temp_line,'\n'); if (p1) *p1 = '\0';
584                 p1 = strchr(temp_line,';'); if (p1) *p1 = '\0';
585                 if (strlen(temp_line) == 0) continue;  //skip blank lines
586                 //n = sscanf( temp_line, "%2x%2x%2x%2x/%2x%2x%2x%2x%2x%2x", &tmp.network[0], &tmp.network[1], &tmp.network[2], &tmp.network[3], &tmp.node[0], &tmp.node[1], &tmp.node[2],&tmp.node[3], &tmp.node[4], &tmp.node[5] );
587                 //if ( n != 10 ) continue;
588                 np = strchr(temp_line,'/');
589                 if (!np)
590                         Error("Invalid entry <%s> on line %d of IPX User file <%s>",temp_line,ln,filename);
591                 else np++;
592                 n = sscanf( temp_line, "%x", &net);
593                 if (n != 1)
594                         Error("Invalid entry <%s> on line %d of IPX User file <%s>",temp_line,ln,filename);
595                 else {
596                         tmp.network[3] = (net & 0xff); net >>= 8;
597                         tmp.network[2] = (net & 0xff); net >>= 8;
598                         tmp.network[1] = (net & 0xff); net >>= 8;
599                         tmp.network[0] = (net & 0xff);
600                 }
601                 n = sscanf( np, "%2x%2x%2x%2x%2x%2x", &tmp.node[0], &tmp.node[1], &tmp.node[2],&tmp.node[3], &tmp.node[4], &tmp.node[5] );
602                 if (n != 6)
603                         Error("Invalid entry <%s> on line %d of IPX User file <%s>\n"
604                                         "  Node address must be 6 bytes (12 digits)",temp_line,ln,filename);
605                 if ( Ipx_num_users < MAX_USERS )        {
606                         ubyte * ipx_real_buffer = (ubyte *)&tmp;
607                         ipx_get_local_target( tmp.network, tmp.node, tmp.address );
608                         Ipx_users[Ipx_num_users++] = tmp;
609                         printf( "%02X%02X%02X%02X/", ipx_real_buffer[0],ipx_real_buffer[1],ipx_real_buffer[2],ipx_real_buffer[3] );
610                         printf( "%02X%02X%02X%02X%02X%02X\n", ipx_real_buffer[4],ipx_real_buffer[5],ipx_real_buffer[6],ipx_real_buffer[7],ipx_real_buffer[8],ipx_real_buffer[9] );
611                 } else {
612                         printf( "Too many addresses in %s! (Limit of %d)\n", filename, MAX_USERS );
613                         fclose(fp);
614                         return;
615                 }
616         }
617         fclose(fp);
618
619 }
620
621
622 void ipx_read_network_file(char * filename)
623 {
624         FILE * fp;
625         user_address tmp;
626         char temp_line[132], *p1;
627         int i, n, ln=0;
628
629         if (!filename) return;
630
631         fp = fopen( filename, "rt" );
632         if ( !fp ) return;
633
634         printf( "Using Networks:\n" );
635         for (i=0; i<Ipx_num_networks; i++ )             {
636                 ubyte * n1 = (ubyte *)&Ipx_networks[i];
637                 printf("* %02x%02x%02x%02x\n", n1[0], n1[1], n1[2], n1[3] );
638         }
639
640         while (fgets(temp_line, 132, fp)) {
641                 ulong net;
642                 ln++;
643                 p1 = strchr(temp_line,'\n'); if (p1) *p1 = '\0';
644                 p1 = strchr(temp_line,';'); if (p1) *p1 = '\0';
645                 if (strlen(temp_line) == 0) continue;  //skip blank lines
646                 //n = sscanf( temp_line, "%2x%2x%2x%2x", &tmp.network[0], &tmp.network[1], &tmp.network[2], &tmp.network[3] );
647                 //if ( n != 4 ) continue;
648                 n = sscanf( temp_line, "%x", &net );
649                 if (n != 1)
650                         Error("Invalid entry <%s> on line %d of IPX Net file <%s>",temp_line,ln,filename);
651                 else {
652                         tmp.network[3] = (net & 0xff); net >>= 8;
653                         tmp.network[2] = (net & 0xff); net >>= 8;
654                         tmp.network[1] = (net & 0xff); net >>= 8;
655                         tmp.network[0] = (net & 0xff);
656                 }
657
658                 if ( Ipx_num_networks < MAX_NETWORKS  ) {
659                         int j;
660                         for (j=0; j<Ipx_num_networks; j++ )     
661                                 if ( !memcmp( &Ipx_networks[j], tmp.network, 4 ) )
662                                         break;
663                         if ( j >= Ipx_num_networks )    {
664                                 memcpy( &Ipx_networks[Ipx_num_networks++], tmp.network, 4 );
665                                 printf("  %02x%02x%02x%02x\n", tmp.network[0], tmp.network[1], tmp.network[2], tmp.network[3] );
666                         }
667                 } else {
668                         printf( "Too many networks in %s! (Limit of %d)\n", filename, MAX_NETWORKS );
669                         fclose(fp);
670                         return;
671                 }
672         }
673         fclose(fp);
674
675 }
676
677 //---typedef struct rip_entry {
678 //---   uint            network;
679 //---   ushort  nhops;
680 //---   ushort  nticks;
681 //---} rip_entry;
682 //---
683 //---typedef struct rip_packet {
684 //---   ushort          operation;              //1=request, 2=response
685 //---   rip_entry       rip[50];
686 //---} rip_packet;
687 //---
688 //---
689 //---void  ipx_find_all_servers()
690 //---{
691 //---   int i;
692 //---   rip_packet * rp;
693 //---   assert(ipx_installed);
694 //---
695 //---   ipx_change_default_socket( 0x0453 );
696 //---   //      ipx_change_default_socket( 0x5304 );
697 //---
698 //---   // Make sure no one is already sending something
699 //---   while( packets[0].ecb.in_use )
700 //---   {
701 //---   }
702 //---   
703 //---   if (packets[0].ecb.completion_code)     {
704 //---           printf( "AAAA:Send error %d for completion code\n", packets[0].ecb.completion_code );
705 //---           //exit(1);
706 //---   }
707 //---
708 //---   rp = (rip_packet *)&packets[0].pd;
709 //---
710 //---   // Fill in destination address
711 //---   {
712 //---           char mzero1[] = {0,0,0,1};
713 //---           char mzero[] = {0,0,0,0,0,1};
714 //---           char immediate[6];
715 //---           //memcpy( packets[0].ipx.destination.network_id, &ipx_network, 4 );
716 //---           //memcpy( packets[0].ipx.destination.node_id.address, ipx_my_node.address, 6 );
717 //---
718 //---           memcpy( packets[0].ipx.destination.network_id, mzero1, 4 );
719 //---           memcpy( packets[0].ipx.destination.node_id.address, mzero, 6 );
720 //---
721 //---           memcpy( packets[0].ipx.destination.socket_id, &ipx_socket, 2 );
722 //---           memcpy( packets[0].ipx.source.network_id, &ipx_network, 4 );
723 //---           memcpy( packets[0].ipx.source.node_id.address, ipx_my_node.address, 6 );
724 //---           memcpy( packets[0].ipx.source.socket_id, &ipx_socket, 2 );
725 //---           //memcpy( packets[0].ecb.immediate_address.address, ipx_my_node.address, 6 );
726 //---           //mzero1[3] = 1;
727 //---           //memcpy( packets[0].ipx.destination.network_id, mzero1, 4 );
728 //---           //mzero[5] = 1;
729 //---           //memcpy( packets[0].ipx.destination.node_id.address, mzero, 6 );
730 //---           //ipx_get_local_target( mzero1, mzero, immediate );
731 //---           //memcpy( packets[0].ecb.immediate_address.address, mzero, 6 );
732 //---           //memcpy( packets[0].ecb.immediate_address.address, immediate, 6 );
733 //---           //mzero[5] = 0;
734 //---   }
735 //---
736 //---   packets[0].ipx.packet_type = 1;         // RIP packet
737 //---
738 //---   // Fill in data to send
739 //---   packets[0].ecb.fragment_size = sizeof(ipx_header) + sizeof(rip_packet);
740 //---   assert( packets[0].ecb.fragment_size <= 576 );
741 //---
742 //---   rp->operation = 0;              // Request
743 //---   for (i=0;i<50; i++)     {
744 //---           rp->rip[i].network = 0xFFFFFFFF;
745 //---           rp->rip[i].nhops = 0;
746 //---           rp->rip[i].nticks = 0;
747 //---   }
748 //---
749 //---   // Send it
750 //---   ipx_send_packet( &packets[0].ecb );
751 //---
752 //---   for (i=0;i<50; i++)     {
753 //---           if ( rp->rip[i].network != 0xFFFFFFFF )
754 //---                   printf( "Network = %8x, Hops=%d, Ticks=%d\n", rp->rip[i].network, rp->rip[i].nhops, rp->rip[i].nticks );
755 //---   }
756 //---}
757 //---
758 //---