]> icculus.org git repositories - btb/d2x.git/blob - arch/dos/ipx.c
use the orientation parameter of g3_draw_bitmap
[btb/d2x.git] / arch / dos / 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-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
12 */
13
14 /*
15  *
16  * Routines for IPX communications, copied from d1x
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <conf.h>
22 #endif
23
24 #ifdef __GNUC__
25 #define _BORLAND_DOS_REGS 1
26 #define far
27 #endif
28
29 #include <i86.h>
30 #include <dos.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <malloc.h>
34 #include <stdlib.h>
35 #include <conio.h>
36 #include <assert.h>
37
38 #include "pstypes.h"
39 #include "timer.h"
40 #include "ipx.h"
41 #include "dxxerror.h"
42 #include "u_dpmi.h"
43 #include "key.h"
44 #include "ipx_drv.h"
45
46 typedef unsigned char BYTE;
47 typedef unsigned short WORD;
48 typedef unsigned long DWORD;
49
50 typedef struct local_address {
51         ubyte address[6];
52 } __pack__ local_address;
53
54 typedef struct net_address {
55         BYTE                            network_id[4];                  
56         local_address   node_id;
57         WORD                            socket_id;
58 } __pack__ net_address;
59
60 typedef struct ipx_header {
61         WORD                    checksum;
62         WORD                    length;
63         BYTE                    transport_control;
64         BYTE                    packet_type;
65         net_address     destination;
66         net_address     source;
67 } __pack__ ipx_header;
68
69 typedef struct ecb_header {
70         WORD                    link[2];
71         WORD                    esr_address[2];
72         BYTE                    in_use;
73         BYTE                    completion_code;
74         WORD                    socket_id;
75         BYTE                    ipx_reserved[14];        
76         WORD                    connection_id;
77         local_address immediate_address;
78         WORD                    fragment_count;
79         WORD                    fragment_pointer[2];
80         WORD                    fragment_size;
81 } __pack__ ecb_header;
82
83 typedef struct packet_data {
84         int                     packetnum;
85         byte                    data[IPX_MAX_DATA_SIZE];
86 } __pack__ packet_data;
87
88 typedef struct ipx_packet {
89         ecb_header      ecb;
90         ipx_header      ipx;
91         packet_data     pd;
92 } __pack__ ipx_packet;
93
94 static int ipx_packetnum = 0;
95
96 #define MAX_PACKETS 64
97
98 static packet_data packet_buffers[MAX_PACKETS];
99 static short packet_free_list[MAX_PACKETS];
100 static int num_packets = 0;
101 static int largest_packet_index = 0;
102 static short packet_size[MAX_PACKETS];
103
104 WORD ipx_socket=0;
105 static ubyte ipx_installed=0;
106 WORD ipx_vector_segment;
107 WORD ipx_vector_offset;
108 ubyte ipx_socket_life = 0;      // 0=closed at prog termination, 0xff=closed when requested.
109 //DWORD ipx_network = 0;
110 //local_address ipx_my_node;
111 #define ipx_my_node (ipx_MyAddress+4)
112 WORD ipx_num_packets=32;                // 32 Ipx packets
113 ipx_packet * packets;
114 int neterrors = 0;
115 ushort ipx_packets_selector;
116
117 ecb_header * last_ecb=NULL;
118 int lastlen=0;
119
120 static void got_new_packet( ecb_header * ecb );
121 static void ipx_listen_for_packet(ecb_header * ecb );
122
123 static void free_packet( int id )
124 {
125         packet_buffers[id].packetnum = -1;
126         packet_free_list[ --num_packets ] = id;
127         if (largest_packet_index==id)   
128                 while ((--largest_packet_index>0) && (packet_buffers[largest_packet_index].packetnum == -1 ));
129 }
130
131 static int ipx_dos_get_packet_data( ubyte * data )
132 {
133         int i, n, best, best_id, size;
134
135         for (i=1; i<ipx_num_packets; i++ )      {
136                 if ( !packets[i].ecb.in_use )   {
137                         got_new_packet( &packets[i].ecb );
138                         packets[i].ecb.in_use = 0;
139                         ipx_listen_for_packet(&packets[i].ecb);
140                 }                       
141         }
142
143         best = -1;
144         n = 0;
145         best_id = -1;
146
147         for (i=0; i<=largest_packet_index; i++ )        {
148                 if ( packet_buffers[i].packetnum > -1 ) {
149                         n++;
150                         if ( best == -1 || (packet_buffers[i].packetnum<best) ) {
151                                 best = packet_buffers[i].packetnum;
152                                 best_id = i;
153                         }
154                 }                       
155         }
156
157         //mprintf( (0, "Best id = %d, pn = %d, last_ecb = %x, len=%x, ne = %d\n", best_id, best, last_ecb, lastlen, neterrors ));
158         //mprintf( (1, "<%d> ", neterrors ));
159
160         if ( best_id < 0 ) return 0;
161
162         size = packet_size[best_id];
163         memcpy( data, packet_buffers[best_id].data, size );
164         free_packet(best_id);
165
166         return size;
167 }
168
169 #ifndef __GNUC__
170 unsigned int swap_short( unsigned int short )
171 #pragma aux swap_short parm [eax] = "xchg al,ah";
172 #else
173 static inline unsigned int swap_short( unsigned int sshort ) {
174         int __retval;
175         asm("xchg %%ah,%%al" : "=a" (__retval) : "a" (sshort));
176         return __retval;
177 }
178 #endif
179
180 static void got_new_packet( ecb_header * ecb )
181 {
182         ipx_packet * p;
183         int id;
184         unsigned short datasize;
185
186         datasize = 0;
187         last_ecb = ecb;
188         p = (ipx_packet *)ecb;
189
190         if ( p->ecb.in_use ) { neterrors++; return; }
191         if      ( p->ecb.completion_code )      { neterrors++; return; }
192
193         //      Error( "Recieve error %d for completion code", p->ecb.completion_code );
194         
195         if ( memcmp( &p->ipx.source.node_id, ipx_my_node, 6 ) ) {
196                 datasize=swap_short(p->ipx.length);
197                 lastlen=datasize;
198                 datasize -= sizeof(ipx_header);
199                 // Find slot to put packet in...
200                 if ( datasize > 0 && datasize <= sizeof(packet_data) )  {
201                         if ( num_packets >= MAX_PACKETS ) {
202                                 //printf( 1, "IPX: Packet buffer overrun!!!\n" );
203                                 neterrors++;
204                                 return;
205                         }               
206                         id = packet_free_list[ num_packets++ ];
207                         if (id > largest_packet_index ) largest_packet_index = id;
208                         packet_size[id] = datasize-sizeof(int);
209                         packet_buffers[id].packetnum =  p->pd.packetnum;
210                         if ( packet_buffers[id].packetnum < 0 ) { neterrors++; return; }
211                         memcpy( packet_buffers[id].data, p->pd.data, packet_size[id] );
212                 } else {
213                         neterrors++; return;
214                 }
215         } 
216         // Repost the ecb
217         p->ecb.in_use = 0;
218         //ipx_listen_for_packet(&p->ecb);
219 }
220
221 /*ubyte * ipx_get_my_local_address()
222 {
223         return ipx_my_node.address;
224 }
225
226 ubyte * ipx_get_my_server_address()
227 {
228         return (ubyte *)&ipx_network;
229 }*/
230
231 static void ipx_listen_for_packet(ecb_header * ecb )    
232 {
233         dpmi_real_regs rregs;
234         ecb->in_use = 0x1d;
235         memset(&rregs,0,sizeof(dpmi_real_regs));
236         rregs.ebx = 4;  // Listen For Packet function
237         rregs.esi = DPMI_real_offset(ecb);
238         rregs.es = DPMI_real_segment(ecb);
239         dpmi_real_int386x( 0x7A, &rregs );
240 }
241
242 /*static void ipx_cancel_listen_for_packet(ecb_header * ecb )   
243 {
244         dpmi_real_regs rregs;
245         memset(&rregs,0,sizeof(dpmi_real_regs));
246         rregs.ebx = 6;  // IPX Cancel event
247         rregs.esi = DPMI_real_offset(ecb);
248         rregs.es = DPMI_real_segment(ecb);
249         dpmi_real_int386x( 0x7A, &rregs );
250 }
251 */
252
253 static void ipx_send_packet(ecb_header * ecb )  
254 {
255         dpmi_real_regs rregs;
256         memset(&rregs,0,sizeof(dpmi_real_regs));
257         rregs.ebx = 3;  // Send Packet function
258         rregs.esi = DPMI_real_offset(ecb);
259         rregs.es = DPMI_real_segment(ecb);
260         dpmi_real_int386x( 0x7A, &rregs );
261 }
262
263 typedef struct {
264         ubyte   network[4];
265         ubyte           node[6];
266         ubyte           local_target[6];
267 } __pack__ net_xlat_info;
268
269 static void ipx_dos_get_local_target( ubyte * server, ubyte * node, ubyte * local_target )
270 {
271         net_xlat_info * info;
272         dpmi_real_regs rregs;
273                 
274         // Get dos memory for call...
275         info = (net_xlat_info *)dpmi_get_temp_low_buffer( sizeof(net_xlat_info) );      
276         assert( info != NULL );
277         memcpy( info->network, server, 4 );
278         memcpy( info->node, node, 6 );
279         
280         memset(&rregs,0,sizeof(dpmi_real_regs));
281
282         rregs.ebx = 2;          // Get Local Target     
283         rregs.es = DPMI_real_segment(info);
284         rregs.esi = DPMI_real_offset(info->network);
285         rregs.edi = DPMI_real_offset(info->local_target);
286
287         dpmi_real_int386x( 0x7A, &rregs );
288
289         // Save the local target...
290         memcpy( local_target, info->local_target, 6 );
291 }
292
293 static void ipx_close()
294 {
295         dpmi_real_regs rregs;
296         if ( ipx_installed )    {
297                 // When using VLM's instead of NETX, the sockets don't
298                 // seem to automatically get closed, so we must explicitly
299                 // close them at program termination.
300                 ipx_installed = 0;
301                 memset(&rregs,0,sizeof(dpmi_real_regs));
302                 rregs.edx = ipx_socket;
303                 rregs.ebx = 1;  // Close socket
304                 dpmi_real_int386x( 0x7A, &rregs );
305         }
306 }
307
308 static int ipx_init(int socket_number)
309 {
310         int show_address=0;
311         dpmi_real_regs rregs;
312         ubyte *ipx_real_buffer;
313         int i;
314
315 //      atexit(ipx_close);
316
317         ipx_packetnum = 0;
318
319         // init packet buffers.
320         for (i=0; i<MAX_PACKETS; i++ )  {
321                 packet_buffers[i].packetnum = -1;
322                 packet_free_list[i] = i;
323         }
324         num_packets = 0;
325         largest_packet_index = 0;
326
327         // Get the IPX vector
328         memset(&rregs,0,sizeof(dpmi_real_regs));
329         rregs.eax=0x00007a00;
330         dpmi_real_int386x( 0x2f, &rregs );
331
332         if ( (rregs.eax & 0xFF) != 0xFF )       {
333                 return IPX_NOT_INSTALLED;   
334         }
335         ipx_vector_offset = rregs.edi & 0xFFFF;
336         ipx_vector_segment = rregs.es;
337         //printf( "IPX entry point at %.4x:%.4x\n", ipx_vector_segment, ipx_vector_offset );
338
339         // Open a socket for IPX
340
341         memset(&rregs,0,sizeof(dpmi_real_regs));
342         swab( (char *)&socket_number,(char *)&ipx_socket, 2 );
343         rregs.edx = ipx_socket;
344         rregs.eax = ipx_socket_life;
345         rregs.ebx = 0;  // Open socket
346         dpmi_real_int386x( 0x7A, &rregs );
347         
348         ipx_socket = rregs.edx & 0xFFFF;
349         
350         if ( rregs.eax & 0xFF ) {
351                 //mprintf( (1, "IPX error opening channel %d\n", socket_number-IPX_DEFAULT_SOCKET ));
352                 return IPX_SOCKET_TABLE_FULL;
353         }
354         
355         ipx_installed = 1;
356
357         // Find our internetwork address
358         ipx_real_buffer = dpmi_get_temp_low_buffer( 1024 );     // 1k block
359         if ( ipx_real_buffer == NULL )  {
360                 //printf( "Error allocation realmode memory\n" );
361                 return IPX_NO_LOW_DOS_MEM;
362         }
363
364         memset(&rregs,0,sizeof(dpmi_real_regs));
365         rregs.ebx = 9;          // Get internetwork address
366         rregs.esi = DPMI_real_offset(ipx_real_buffer);
367         rregs.es = DPMI_real_segment(ipx_real_buffer);
368         dpmi_real_int386x( 0x7A, &rregs );
369
370         if ( rregs.eax & 0xFF ) {
371                 //printf( "Error getting internetwork address!\n" );
372                 return IPX_SOCKET_TABLE_FULL;
373         }
374
375 /*      memcpy( &ipx_network, ipx_real_buffer, 4 );
376         memcpy( ipx_my_node, &ipx_real_buffer[4], 6 );*/
377         memcpy(ipx_MyAddress,ipx_real_buffer,10);
378
379         if ( show_address )     {
380                 printf( "My IPX addresss is " );
381                 printf( "%02X%02X%02X%02X/", ipx_real_buffer[0],ipx_real_buffer[1],ipx_real_buffer[2],ipx_real_buffer[3] );
382                 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] );
383                 printf( "\n" );
384         }
385
386         packets = dpmi_real_malloc( sizeof(ipx_packet)*ipx_num_packets, &ipx_packets_selector );
387         if ( packets == NULL )  {
388                 //printf( "Couldn't allocate real memory for %d packets\n", ipx_num_packets );
389                 return IPX_NO_LOW_DOS_MEM;
390         }
391 #if 0 /* adb: not needed, fails with cwsdpmi */
392         if (!dpmi_lock_region( packets, sizeof(ipx_packet)*ipx_num_packets ))   {
393                 //printf( "Couldn't lock real memory for %d packets\n", ipx_num_packets );
394                 return IPX_NO_LOW_DOS_MEM;
395         }
396 #endif
397         memset( packets, 0, sizeof(ipx_packet)*ipx_num_packets );
398
399         for (i=1; i<ipx_num_packets; i++ )      {
400                 packets[i].ecb.in_use = 0x1d;
401                 //packets[i].ecb.in_use = 0;
402                 packets[i].ecb.socket_id = ipx_socket;
403                 packets[i].ecb.fragment_count = 1;
404                 packets[i].ecb.fragment_pointer[0] = DPMI_real_offset(&packets[i].ipx);
405                 packets[i].ecb.fragment_pointer[1] = DPMI_real_segment(&packets[i].ipx);
406                 packets[i].ecb.fragment_size = sizeof(ipx_packet)-sizeof(ecb_header);                   //-sizeof(ecb_header);
407
408                 ipx_listen_for_packet(&packets[i].ecb);
409         }
410
411         packets[0].ecb.socket_id = ipx_socket;
412         packets[0].ecb.fragment_count = 1;
413         packets[0].ecb.fragment_pointer[0] = DPMI_real_offset(&packets[0].ipx);
414         packets[0].ecb.fragment_pointer[1] = DPMI_real_segment(&packets[0].ipx);
415         packets[0].ipx.packet_type = 4;         // IPX packet
416         packets[0].ipx.destination.socket_id = ipx_socket;
417 //      memcpy( packets[0].ipx.destination.network_id, &ipx_network, 4 );
418         memset( packets[0].ipx.destination.network_id, 0, 4 );
419
420         return IPX_INIT_OK;
421 }
422
423 static void ipx_dos_send_packet_data( ubyte * data, int datasize, ubyte *network, ubyte *address, ubyte *immediate_address )
424 {
425         assert(ipx_installed);
426
427         if ( datasize >= IPX_MAX_DATA_SIZE )    {
428                 printf( "Data too big\n" );
429 //added/replaced on 11/8/98 by Victor Rachels to stop crappage
430                 return;
431 //                exit(1);
432 //end this section replacement - VR
433         }
434
435         // Make sure no one is already sending something
436         while( packets[0].ecb.in_use )
437         {
438         }
439         
440         if (packets[0].ecb.completion_code)     {
441 //                printf( "Send error %d for completion code\n", packets[0].ecb.completion_code );
442 //added/replaced on 11/8/98 by Victor Rachels to stop crappage
443                 return;
444         //        exit(1);
445 //end this section replacement - VR
446
447         }
448
449         // Fill in destination address
450         if ( memcmp( network, &ipx_network, 4 ) )
451                 memcpy( packets[0].ipx.destination.network_id, network, 4 );
452         else
453                 memset( packets[0].ipx.destination.network_id, 0, 4 );
454         memcpy( packets[0].ipx.destination.node_id.address, address, 6 );
455         memcpy( packets[0].ecb.immediate_address.address, immediate_address, 6 );
456         packets[0].pd.packetnum = ipx_packetnum++;
457
458         // Fill in data to send
459         packets[0].ecb.fragment_size = sizeof(ipx_header) + sizeof(int) + datasize;
460
461         assert( datasize > 1 );
462         assert( packets[0].ecb.fragment_size <= 576 );
463
464         memcpy( packets[0].pd.data, data, datasize );
465
466         // Send it
467         ipx_send_packet( &packets[0].ecb );
468
469 }
470
471 /*static int ipx_change_default_socket( ushort socket_number )
472 {
473         int i;
474         WORD new_ipx_socket;
475         dpmi_real_regs rregs;
476
477         if ( !ipx_installed ) return -3;
478
479         // Open a new socket    
480         memset(&rregs,0,sizeof(dpmi_real_regs));
481         swab( (char *)&socket_number,(char *)&new_ipx_socket, 2 );
482         rregs.edx = new_ipx_socket;
483         rregs.eax = ipx_socket_life;
484         rregs.ebx = 0;  // Open socket
485         dpmi_real_int386x( 0x7A, &rregs );
486         
487         new_ipx_socket = rregs.edx & 0xFFFF;
488         
489         if ( rregs.eax & 0xFF ) {
490                 //printf( (1, "IPX error opening channel %d\n", socket_number-IPX_DEFAULT_SOCKET ));
491                 return -2;
492         }
493
494         for (i=1; i<ipx_num_packets; i++ )      {
495                 ipx_cancel_listen_for_packet(&packets[i].ecb);
496         }
497
498         // Close existing socket...
499         memset(&rregs,0,sizeof(dpmi_real_regs));
500         rregs.edx = ipx_socket;
501         rregs.ebx = 1;  // Close socket
502         dpmi_real_int386x( 0x7A, &rregs );
503
504         ipx_socket = new_ipx_socket;
505
506         // Repost all listen requests on the new socket...      
507         for (i=1; i<ipx_num_packets; i++ )      {
508                 packets[i].ecb.in_use = 0;
509                 packets[i].ecb.socket_id = ipx_socket;
510                 ipx_listen_for_packet(&packets[i].ecb);
511         }
512
513         packets[0].ecb.socket_id = ipx_socket;
514         packets[0].ipx.destination.socket_id = ipx_socket;
515
516         ipx_packetnum = 0;
517         // init packet buffers.
518         for (i=0; i<MAX_PACKETS; i++ )  {
519                 packet_buffers[i].packetnum = -1;
520                 packet_free_list[i] = i;
521         }
522         num_packets = 0;
523         largest_packet_index = 0;
524
525         return 0;
526 }
527 */
528
529 struct ipx_driver ipx_dos = {
530 //      NULL,
531         ipx_init,
532         ipx_close,
533         NULL,
534         NULL,
535         NULL,
536         NULL,
537         1,
538         ipx_dos_get_local_target,
539         ipx_dos_get_packet_data,
540         ipx_dos_send_packet_data
541 };
542
543 void arch_ipx_set_driver(int ipx_driver)
544 {
545         driver = &ipx_dos;
546         if (ipx_driver != IPX_DRIVER_IPX)
547                 Warning("Unknown network driver! Defaulting to real IPX");
548 }
549
550
551 //---typedef struct rip_entry {
552 //---   uint            network;
553 //---   ushort  nhops;
554 //---   ushort  nticks;
555 //---} rip_entry;
556 //---
557 //---typedef struct rip_packet {
558 //---   ushort          operation;              //1=request, 2=response
559 //---   rip_entry       rip[50];
560 //---} rip_packet;
561 //---
562 //---
563 //---void  ipx_find_all_servers()
564 //---{
565 //---   int i;
566 //---   rip_packet * rp;
567 //---   assert(ipx_installed);
568 //---
569 //---   ipx_change_default_socket( 0x0453 );
570 //---   //      ipx_change_default_socket( 0x5304 );
571 //---
572 //---   // Make sure no one is already sending something
573 //---   while( packets[0].ecb.in_use )
574 //---   {
575 //---   }
576 //---   
577 //---   if (packets[0].ecb.completion_code)     {
578 //---           printf( "AAAA:Send error %d for completion code\n", packets[0].ecb.completion_code );
579 //---           //exit(1);
580 //---   }
581 //---
582 //---   rp = (rip_packet *)&packets[0].pd;
583 //---
584 //---   // Fill in destination address
585 //---   {
586 //---           char mzero1[] = {0,0,0,1};
587 //---           char mzero[] = {0,0,0,0,0,1};
588 //---           char immediate[6];
589 //---           //memcpy( packets[0].ipx.destination.network_id, &ipx_network, 4 );
590 //---           //memcpy( packets[0].ipx.destination.node_id.address, ipx_my_node.address, 6 );
591 //---
592 //---           memcpy( packets[0].ipx.destination.network_id, mzero1, 4 );
593 //---           memcpy( packets[0].ipx.destination.node_id.address, mzero, 6 );
594 //---
595 //---           memcpy( packets[0].ipx.destination.socket_id, &ipx_socket, 2 );
596 //---           memcpy( packets[0].ipx.source.network_id, &ipx_network, 4 );
597 //---           memcpy( packets[0].ipx.source.node_id.address, ipx_my_node.address, 6 );
598 //---           memcpy( packets[0].ipx.source.socket_id, &ipx_socket, 2 );
599 //---           //memcpy( packets[0].ecb.immediate_address.address, ipx_my_node.address, 6 );
600 //---           //mzero1[3] = 1;
601 //---           //memcpy( packets[0].ipx.destination.network_id, mzero1, 4 );
602 //---           //mzero[5] = 1;
603 //---           //memcpy( packets[0].ipx.destination.node_id.address, mzero, 6 );
604 //---           //ipx_get_local_target( mzero1, mzero, immediate );
605 //---           //memcpy( packets[0].ecb.immediate_address.address, mzero, 6 );
606 //---           //memcpy( packets[0].ecb.immediate_address.address, immediate, 6 );
607 //---           //mzero[5] = 0;
608 //---   }
609 //---
610 //---   packets[0].ipx.packet_type = 1;         // RIP packet
611 //---
612 //---   // Fill in data to send
613 //---   packets[0].ecb.fragment_size = sizeof(ipx_header) + sizeof(rip_packet);
614 //---   assert( packets[0].ecb.fragment_size <= 576 );
615 //---
616 //---   rp->operation = 0;              // Request
617 //---   for (i=0;i<50; i++)     {
618 //---           rp->rip[i].network = 0xFFFFFFFF;
619 //---           rp->rip[i].nhops = 0;
620 //---           rp->rip[i].nticks = 0;
621 //---   }
622 //---
623 //---   // Send it
624 //---   ipx_send_packet( &packets[0].ecb );
625 //---
626 //---   for (i=0;i<50; i++)     {
627 //---           if ( rp->rip[i].network != 0xFFFFFFFF )
628 //---                   printf( "Network = %8x, Hops=%d, Ticks=%d\n", rp->rip[i].network, rp->rip[i].nhops, rp->rip[i].nticks );
629 //---   }
630 //---}
631 //---
632 //---