/* $Id: ipx.c,v 1.1.1.1 2006/03/17 19:52:36 zicodxx Exp $ */ /* THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX SOFTWARE CORPORATION ("PARALLAX"). PARALLAX, IN DISTRIBUTING THE CODE TO END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS IN USING, DISPLAYING, AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE FREE PURPOSES. IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES. THE END-USER UNDERSTANDS AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. */ /* * * Routines for IPX communications, copied from d1x * */ #ifdef HAVE_CONFIG_H #include #endif #ifdef __GNUC__ #define _BORLAND_DOS_REGS 1 #define far #endif #include #include #include #include #include #include #include #include #include "pstypes.h" #include "timer.h" #include "ipx.h" #include "error.h" #include "u_dpmi.h" #include "key.h" #include "ipx_drv.h" typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned long DWORD; typedef struct local_address { ubyte address[6]; } __pack__ local_address; typedef struct net_address { BYTE network_id[4]; local_address node_id; WORD socket_id; } __pack__ net_address; typedef struct ipx_header { WORD checksum; WORD length; BYTE transport_control; BYTE packet_type; net_address destination; net_address source; } __pack__ ipx_header; typedef struct ecb_header { WORD link[2]; WORD esr_address[2]; BYTE in_use; BYTE completion_code; WORD socket_id; BYTE ipx_reserved[14]; WORD connection_id; local_address immediate_address; WORD fragment_count; WORD fragment_pointer[2]; WORD fragment_size; } __pack__ ecb_header; typedef struct packet_data { int packetnum; byte data[IPX_MAX_DATA_SIZE]; } __pack__ packet_data; typedef struct ipx_packet { ecb_header ecb; ipx_header ipx; packet_data pd; } __pack__ ipx_packet; static int ipx_packetnum = 0; #define MAX_PACKETS 64 static packet_data packet_buffers[MAX_PACKETS]; static short packet_free_list[MAX_PACKETS]; static int num_packets = 0; static int largest_packet_index = 0; static short packet_size[MAX_PACKETS]; WORD ipx_socket=0; static ubyte ipx_installed=0; WORD ipx_vector_segment; WORD ipx_vector_offset; ubyte ipx_socket_life = 0; // 0=closed at prog termination, 0xff=closed when requested. //DWORD ipx_network = 0; //local_address ipx_my_node; #define ipx_my_node (ipx_MyAddress+4) WORD ipx_num_packets=32; // 32 Ipx packets ipx_packet * packets; int neterrors = 0; ushort ipx_packets_selector; ecb_header * last_ecb=NULL; int lastlen=0; static void got_new_packet( ecb_header * ecb ); static void ipx_listen_for_packet(ecb_header * ecb ); static void free_packet( int id ) { packet_buffers[id].packetnum = -1; packet_free_list[ --num_packets ] = id; if (largest_packet_index==id) while ((--largest_packet_index>0) && (packet_buffers[largest_packet_index].packetnum == -1 )); } static int ipx_dos_get_packet_data( ubyte * data ) { int i, n, best, best_id, size; for (i=1; i -1 ) { n++; if ( best == -1 || (packet_buffers[i].packetnum ", neterrors )); if ( best_id < 0 ) return 0; size = packet_size[best_id]; memcpy( data, packet_buffers[best_id].data, size ); free_packet(best_id); return size; } #ifndef __GNUC__ unsigned int swap_short( unsigned int short ) #pragma aux swap_short parm [eax] = "xchg al,ah"; #else static inline unsigned int swap_short( unsigned int sshort ) { int __retval; asm("xchg %%ah,%%al" : "=a" (__retval) : "a" (sshort)); return __retval; } #endif static void got_new_packet( ecb_header * ecb ) { ipx_packet * p; int id; unsigned short datasize; datasize = 0; last_ecb = ecb; p = (ipx_packet *)ecb; if ( p->ecb.in_use ) { neterrors++; return; } if ( p->ecb.completion_code ) { neterrors++; return; } // Error( "Recieve error %d for completion code", p->ecb.completion_code ); if ( memcmp( &p->ipx.source.node_id, ipx_my_node, 6 ) ) { datasize=swap_short(p->ipx.length); lastlen=datasize; datasize -= sizeof(ipx_header); // Find slot to put packet in... if ( datasize > 0 && datasize <= sizeof(packet_data) ) { if ( num_packets >= MAX_PACKETS ) { //printf( 1, "IPX: Packet buffer overrun!!!\n" ); neterrors++; return; } id = packet_free_list[ num_packets++ ]; if (id > largest_packet_index ) largest_packet_index = id; packet_size[id] = datasize-sizeof(int); packet_buffers[id].packetnum = p->pd.packetnum; if ( packet_buffers[id].packetnum < 0 ) { neterrors++; return; } memcpy( packet_buffers[id].data, p->pd.data, packet_size[id] ); } else { neterrors++; return; } } // Repost the ecb p->ecb.in_use = 0; //ipx_listen_for_packet(&p->ecb); } /*ubyte * ipx_get_my_local_address() { return ipx_my_node.address; } ubyte * ipx_get_my_server_address() { return (ubyte *)&ipx_network; }*/ static void ipx_listen_for_packet(ecb_header * ecb ) { dpmi_real_regs rregs; ecb->in_use = 0x1d; memset(&rregs,0,sizeof(dpmi_real_regs)); rregs.ebx = 4; // Listen For Packet function rregs.esi = DPMI_real_offset(ecb); rregs.es = DPMI_real_segment(ecb); dpmi_real_int386x( 0x7A, &rregs ); } /*static void ipx_cancel_listen_for_packet(ecb_header * ecb ) { dpmi_real_regs rregs; memset(&rregs,0,sizeof(dpmi_real_regs)); rregs.ebx = 6; // IPX Cancel event rregs.esi = DPMI_real_offset(ecb); rregs.es = DPMI_real_segment(ecb); dpmi_real_int386x( 0x7A, &rregs ); } */ static void ipx_send_packet(ecb_header * ecb ) { dpmi_real_regs rregs; memset(&rregs,0,sizeof(dpmi_real_regs)); rregs.ebx = 3; // Send Packet function rregs.esi = DPMI_real_offset(ecb); rregs.es = DPMI_real_segment(ecb); dpmi_real_int386x( 0x7A, &rregs ); } typedef struct { ubyte network[4]; ubyte node[6]; ubyte local_target[6]; } __pack__ net_xlat_info; static void ipx_dos_get_local_target( ubyte * server, ubyte * node, ubyte * local_target ) { net_xlat_info * info; dpmi_real_regs rregs; // Get dos memory for call... info = (net_xlat_info *)dpmi_get_temp_low_buffer( sizeof(net_xlat_info) ); assert( info != NULL ); memcpy( info->network, server, 4 ); memcpy( info->node, node, 6 ); memset(&rregs,0,sizeof(dpmi_real_regs)); rregs.ebx = 2; // Get Local Target rregs.es = DPMI_real_segment(info); rregs.esi = DPMI_real_offset(info->network); rregs.edi = DPMI_real_offset(info->local_target); dpmi_real_int386x( 0x7A, &rregs ); // Save the local target... memcpy( local_target, info->local_target, 6 ); } static void ipx_close() { dpmi_real_regs rregs; if ( ipx_installed ) { // When using VLM's instead of NETX, the sockets don't // seem to automatically get closed, so we must explicitly // close them at program termination. ipx_installed = 0; memset(&rregs,0,sizeof(dpmi_real_regs)); rregs.edx = ipx_socket; rregs.ebx = 1; // Close socket dpmi_real_int386x( 0x7A, &rregs ); } } static int ipx_init(int socket_number) { int show_address=0; dpmi_real_regs rregs; ubyte *ipx_real_buffer; int i; // atexit(ipx_close); ipx_packetnum = 0; // init packet buffers. for (i=0; i= IPX_MAX_DATA_SIZE ) { printf( "Data too big\n" ); //added/replaced on 11/8/98 by Victor Rachels to stop crappage return; // exit(1); //end this section replacement - VR } // Make sure no one is already sending something while( packets[0].ecb.in_use ) { } if (packets[0].ecb.completion_code) { // printf( "Send error %d for completion code\n", packets[0].ecb.completion_code ); //added/replaced on 11/8/98 by Victor Rachels to stop crappage return; // exit(1); //end this section replacement - VR } // Fill in destination address if ( memcmp( network, &ipx_network, 4 ) ) memcpy( packets[0].ipx.destination.network_id, network, 4 ); else memset( packets[0].ipx.destination.network_id, 0, 4 ); memcpy( packets[0].ipx.destination.node_id.address, address, 6 ); memcpy( packets[0].ecb.immediate_address.address, immediate_address, 6 ); packets[0].pd.packetnum = ipx_packetnum++; // Fill in data to send packets[0].ecb.fragment_size = sizeof(ipx_header) + sizeof(int) + datasize; assert( datasize > 1 ); assert( packets[0].ecb.fragment_size <= 576 ); memcpy( packets[0].pd.data, data, datasize ); // Send it ipx_send_packet( &packets[0].ecb ); } /*static int ipx_change_default_socket( ushort socket_number ) { int i; WORD new_ipx_socket; dpmi_real_regs rregs; if ( !ipx_installed ) return -3; // Open a new socket memset(&rregs,0,sizeof(dpmi_real_regs)); swab( (char *)&socket_number,(char *)&new_ipx_socket, 2 ); rregs.edx = new_ipx_socket; rregs.eax = ipx_socket_life; rregs.ebx = 0; // Open socket dpmi_real_int386x( 0x7A, &rregs ); new_ipx_socket = rregs.edx & 0xFFFF; if ( rregs.eax & 0xFF ) { //printf( (1, "IPX error opening channel %d\n", socket_number-IPX_DEFAULT_SOCKET )); return -2; } for (i=1; ioperation = 0; // Request //--- for (i=0;i<50; i++) { //--- rp->rip[i].network = 0xFFFFFFFF; //--- rp->rip[i].nhops = 0; //--- rp->rip[i].nticks = 0; //--- } //--- //--- // Send it //--- ipx_send_packet( &packets[0].ecb ); //--- //--- for (i=0;i<50; i++) { //--- if ( rp->rip[i].network != 0xFFFFFFFF ) //--- printf( "Network = %8x, Hops=%d, Ticks=%d\n", rp->rip[i].network, rp->rip[i].nhops, rp->rip[i].nticks ); //--- } //---} //--- //---