www.pudn.com > Source_program.rar > NET.C
/* Debug option: reverse the order in which IP fragments are sent */ #define SUBFIRST 0 /* Set non-zero to transmit subframes first */ /* Debug options to drop frames on transmit or receive */ #define TXDROP 0 /* Set non-zero to drop 1-in-N transmit frames */ #define RXDROP 0 /* Set non-zero to drop 1-in-N receive frames */ /* All drivers are supported under Borland C ** Packet driver isn't supported under Visual C ** Packet and SLIP drivers aren't supported under DJGPP */ #ifdef __BORLANDC__ #define PKTD_SUPPORT 1 #else #define PKTD_SUPPORT 0 #endif #ifdef DJGPP #define SLIP_SUPPORT 0 #else #define SLIP_SUPPORT 1 #endif #include#include #include #include /* Override the default circular buffer size used in TCPFS.H */ #define _CBUFFLEN_ 0x2000 /* Buffer size: MUST be power of 2 */ #include "netutil.h" #include "net.h" #include "ether.h" #include "serpc.h" #if PKTD_SUPPORT #include "pktd.h" #else /* Dummy functions if PKTD not installed */ #define open_pktd(x) no_driver("packet") #define close_pktd(x) no_driver("packet") #define put_pktd(x, y, z) no_driver("packet") #endif #if !SLIP_SUPPORT /* Dummy functions if SLIP not installed */ #define open_slip(x, y) no_driver("SLIP") #define close_slip(x) no_driver("SLIP") #define put_slip(x, y, z) no_driver("SLIP") #define receive_slip(x) no_driver("SLIP") #endif #define SLIP_END 0xc0 /* SLIP escape codes */ #define SLIP_ESC 0xdb #define ESC_END 0xdc #define ESC_ESC 0xdd CBUFF rxpkts = {_CBUFFLEN_}; /* Rx and Tx circular packet buffers */ CBUFF txpkts = {_CBUFFLEN_}; BYTE slipbuffs[MAXCOMMS][MAXSLIP]; /* SLIP buffers */ WORD sliplens[MAXCOMMS]; /* ..and data lengths */ int netdebug; /* Flag to enable net packet display */ FILE *logfile; /* Handle for logfile */ int ndrivers; /* Number of initialised drivers */ int txfcount, rxfcount; /* Counts for 'frame drop' options */ /* Private prototypes */ WORD no_driver(char *s); void do_modem(char c); /* Get a frame from the network, return length excl. hardware header */ int get_frame(GENFRAME *gfp) { int rxlen; if ((rxlen=get_net(gfp)) > 0) /* If any packet received.. */ { if (is_ether(gfp, rxlen)) /* If Ethernet.. */ rxlen -= sizeof(ETHERHDR); /* Subtract header length */ else if (!is_slip(gfp, rxlen)) /* If not SLIP.. */ rxlen = 0; /* Discard if unrecognised */ } return(rxlen); } /* Put frame out onto the network; if sub-frame (fragment), send it as well */ int put_frame(GENFRAME *gfp, int len) { int ret=0, len1, len2; GENFRAME *sfp; len1 = gfp->g.fragoff ? gfp->g.fragoff : len; /* Get len of 2 fragments */ len2 = len - len1; sfp = (GENFRAME *)&gfp->buff[gfp->g.fragoff]; /* ..and ptr to 2nd frag */ #if SUBFIRST if (len2 > 0) /* Send sub-frame first.. */ ret = put_net(sfp, (WORD)len2); if (len1 > 0) /* ..then main frame */ ret += put_net(gfp, (WORD)len1); #else /* Or send main frame first */ if (len1 > 0) ret = put_net(gfp, (WORD)len1); if (len2 > 0) ret += put_net(sfp, (WORD)len2); #endif return(ret); } /* Open network driver ** Return driver type, which is the driver config number (1st driver is 0) ** plus flags to indicate frame type (Ethernet, SLIP etc.). Return 0 if error */ WORD open_net(char *cfgstr) { WORD dtype=0, etype, stype; int append; char *s; etype = ndrivers + DTYPE_ETHER; /* Ethernet driver type */ stype = ndrivers + DTYPE_SLIP; /* ..and SLIP driver type */ if (ndrivers >= MAXNETS) printf("ERROR: exceeded maximum number of network interfaces\n"); else if ((s = skiptoken(cfgstr, "ether")) != 0) /* Ethernet? */ { cfgstr = skippunct(s); if ((s = skiptoken(cfgstr, "snap")) != 0) /* ..with 802.3 SNAP hdr? */ { etype |= DTYPE_SNAP; cfgstr = skippunct(s); } /* Direct hardware drive? */ if ((s = skiptoken(cfgstr, "ne")) != 0) /* ..NE2000-compatible */ dtype = open_etherne(s, (WORD)(etype|DTYPE_NE)); else if ((s = skiptoken(cfgstr, "3c")) != 0)/* ..3COM 3C509 */ dtype = open_ether3c(s, (WORD)(etype|DTYPE_3C)); else if ((s = skiptoken(cfgstr, "pktd")) != 0) dtype = open_pktd(etype | DTYPE_PKTD); /* Ether Packet Driver? */ } else if ((s = skiptoken(cfgstr, "slip")) != 0) /* SLIP interface? */ { cfgstr = skippunct(s); if ((s = skiptoken(cfgstr, "pc")) != 0) /* PC ser (direct/Win32) */ dtype = open_slip(s, stype); else if ((s = skiptoken(cfgstr, "pktd")) != 0) dtype = open_pktd(stype | DTYPE_PKTD); /* Packet driver SLIP */ } if (dtype && (s=strchr(s, '>'))!=0) /* Log net Tx/Tx to file? */ { if ((append = (*++s == '>'))!=0) /* If '>>' append to file */ s++; s = skipspace(s); /* Open logfile */ printf("%s logfile '%s'\n", append ? "Appending to" : "Creating", s); if ((logfile=fopen(s, append ? "ab" : "wb"))==0) printf("ERROR: can't open logfile\n"); } if (dtype) /* Bump up driver count */ ndrivers++; return(dtype); } /* Close network driver */ void close_net(WORD dtype) { if (dtype & DTYPE_NE) /* Close NE2000-compat */ close_etherne(dtype); else if (dtype & DTYPE_3C) /* ..or 3C509 */ close_ether3c(dtype); else if (dtype == DTYPE_SLIP) /* ..or SLIP */ close_slip(dtype); else if (dtype & DTYPE_PKTD) /* ..or packet driver */ close_pktd(dtype); if (logfile) /* Close logfile */ { printf("Closing logfile\n"); if (ferror(logfile)) printf("\nERROR writing logfile\n"); fclose(logfile); logfile = 0; } } /* Dummy initialisation function for unsupported drivers */ WORD no_driver(char *s) { printf("ERROR: %s driver not included in this version\n", s); return(0); } /* Return pointer to my Ethernet addr, given driver type */ BYTE *ether_addr(WORD dtype) { BYTE *addr=(BYTE *)"-SLIP-"; if (dtype & DTYPE_NE) addr = etherne_addr(dtype); else if (dtype & DTYPE_3C) addr = ether3c_addr(dtype); #if PKTD_SUPPORT else if (dtype & DTYPE_PKTD) addr = etherpktd_addr(dtype); #endif return(addr); } /* Get frame from receive buffer, given pointer to a frame buffer. ** If driver type field in the frame buffer is non-zero, match that driver type ** If zero, match any driver type. Return data length (0 if no packet) */ WORD get_net(GENFRAME *gfp) { WORD len=0; SNAPFRAME *sfp; GENHDR gh={0,0,0}; LWORD mstim; if (buff_dlen(&rxpkts) >= sizeof(GENHDR)) { /* If frame in Rx pkt buffer.. */ buff_out(&rxpkts, (BYTE *)&gh, sizeof(gh)); /* Check frame hdr */ len = gh.len; /* ..ensure length is sensible */ if (len<1 || len>MAXFRAME) { rxpkts.out = rxpkts.trial = rxpkts.in; printf("\nERROR Rx frame buffer corrupt!\n"); printf("Frame len=%u, type=%u\n", len, gh.dtype); len = 0; } else if (gh.dtype==gfp->g.dtype || !gfp->g.dtype) { /* Driver type matches or is 0 */ buff_out(&rxpkts, gfp->buff, len); /* Store frame in buffer */ if (!gfp->g.dtype) /* If no driver type in buffer.. */ gfp->g = gh; /* ..load in complete header */ gfp->g.len = len; /* Set length in header */ if (netdebug) /* Display raw frame */ disp_frame(gfp, len, 0); if (logfile) /* Log raw frame */ { mstim = mstime(); fwrite("GET ", 1, 4, logfile); fwrite(&mstim, 1, 4, logfile); fwrite(gfp, 1, len+sizeof(GENHDR), logfile); } if (gfp->g.dtype&DTYPE_ETHER && /* If Ethernet frame.. */ gfp->buff[MACLEN*2] < 6) /* ..and Pcol less than 600h */ { /* ..might be 802.3 SNAP */ sfp = (SNAPFRAME *)gfp->buff; if (len>sizeof(SNAPHDR) && sfp->s.lsap==0xaaaa) { /* If so, convert to DIX */ len -= sizeof(SNAPHDR); memmove(&sfp->e.ptype, &sfp->s.ptype, len); } gfp->g.len = len; /* Re-set length in header */ } } else { /* Wrong driver type: discard pkt */ buff_out(&rxpkts, 0, len); len = 0; } #if RXDROP if (++txfcount % RXDROP == 0) { printf(" Rx frame dropped for debug\n"); len = 0; } #endif } return(len); } /* Put packet onto network, given length */ WORD put_net(GENFRAME *gfp, WORD len) { WORD dtype; SNAPFRAME *sfp; LWORD mstim; #if TXDROP if (++txfcount % TXDROP == 0) { printf(" Tx frame dropped for debug\n"); return(len); } #endif dtype = gfp->g.dtype; len = mini(len, getframe_maxlen(gfp)); /* Truncate if too big */ gfp->g.len = len; if (dtype&DTYPE_SNAP && len+sizeof(SNAPHDR)<=MAXFRAME) { /* If 802.3 SNAP.. */ sfp = (SNAPFRAME *)gfp->buff; /* Make room for new header */ memmove(&sfp->s.ptype, &sfp->e.ptype, len); len += sizeof(SNAPHDR); /* Set for 802.3 802.2 & SNAP */ sfp->e.ptype = swapw((WORD)(len-sizeof(ETHERHDR))); sfp->s.lsap = 0xaaaa; sfp->s.ctrl = 3; memset(sfp->s.oui, 0, 3); } if (dtype & DTYPE_PKTD) /* If pkt drvr, send direct */ len = put_pktd(dtype, gfp->buff, len); else if (dtype & DTYPE_ETHER) /* If an Ethernet frame.. */ { /* ..check space in pkt buffer.. */ if (buff_freelen(&txpkts) >= len+sizeof(GENHDR)) buff_in(&txpkts, (BYTE *)gfp, (WORD)(len+sizeof(GENHDR))); } else if (dtype & DTYPE_SLIP) /* Send SLIP direct to driver */ len = put_slip(gfp->buff, len, dtype); else len = 0; if (netdebug) disp_frame(gfp, len, 1); if (len>0 && logfile) { mstim = mstime(); fwrite("PUT ", 1, 4, logfile); fwrite(&mstim, 1, 4, logfile); fwrite(gfp, 1, gfp->g.len+sizeof(GENHDR), logfile); } return(len); } /* Poll the given network interface to keep it alive */ void poll_net(WORD dtype) { if (dtype & DTYPE_NE) poll_etherne(dtype); else if (dtype & DTYPE_3C) poll_ether3c(dtype); else if (dtype & DTYPE_SLIP) receive_slip(dtype); } /* Rx upcall from network driver; store a received frame, return 0 if no room ** If buffer pointer is null, only check if the required space is available ** Beware: this function may be called by an interrupt handler */ WORD receive_upcall(WORD dtype, void *buff, WORD len) { static GENHDR gh; /* Static for BC 4.5 interrupts! */ len = minw(len, MAXFRAME); /* Truncate to max size */ if (len>0 && buff_freelen(&rxpkts) >= len+sizeof(GENHDR)) { /* If space in circ buffer..*/ if (buff) { gh.len = len; /* Store general frame hdr */ gh.dtype = dtype; buff_in(&rxpkts, (BYTE *)&gh, sizeof(gh)); buff_in(&rxpkts, buff, len); /* ..and frame */ } } else /* If no space, discard frame */ len = 0; return(len); } /* Tx upcall from network driver; get frame for Tx, return len or 0 if none */ WORD transmit_upcall(WORD dtype, void *buff, WORD maxlen) { WORD len=0; GENHDR gh; if (buff_dlen(&txpkts) >=4) { buff_try(&txpkts, (BYTE *)&gh, sizeof(gh)); /* Check frame hdr */ len = minw(gh.len, maxlen); /* Truncate as necessary */ if (gh.dtype==dtype) /* If frame type matches..*/ { buff_out(&txpkts, 0, sizeof(GENHDR)); /* ..remove hdr from buff */ buff_out(&txpkts, buff, len); /* .. and also the frame */ if (len < gh.len) /* .. discard overbytes */ buff_out(&txpkts, 0, (WORD)(gh.len-len)); } else /* If wrong driver type */ { buff_retry(&txpkts, sizeof(gh)); /* ..push header back */ len = 0; } } return(len); } /* Open Ethernet hardware driver, given config string. Return frame type */ WORD open_etherne(char *str, WORD dtype) { char *s; WORD addr; /* Address value in hex */ addr = (WORD)strtoul(skippunct(str), &s, 16); if (!addr || !init_etherne(dtype, addr)) dtype = 0; return(dtype); } /* Open Ethernet hardware driver, given config string. Return frame type */ WORD open_ether3c(char *str, WORD dtype) { char *s; WORD addr; /* Address value in hex */ addr = (WORD)strtoul(skippunct(str), &s, 16); if (!addr || !init_ether3c(dtype, addr)) dtype = 0; return(dtype); } #if SLIP_SUPPORT /* Initialise SLIP link */ WORD open_slip(char *str, WORD dtype) { int com, lite; long baud; char *s; WORD ret=0; selectuart(dtype & NETNUM_MASK); lite = (strstr(str, "litelink") != 0); if ((s = strstr(str, "com")) != 0) { com = (int)strtoul(s+3, &s, 10); /* COM port number */ baud = strtoul(skippunct(s), &s, 10); /* Initialise hardware.. */ if ((com>=1 || com<=9) && setuart(com, baud, 0)) { ret = dtype; if (lite) litelink(baud); } } return(ret); } /* Shut down SLIP link */ void close_slip(WORD dtype) { selectuart(dtype & NETNUM_MASK); clearuart(); } /* Get a packet from the SLIP link into Rx buffer, return frame count */ int receive_slip(WORD dtype) { WORD w; static WORD lastw=0; int count=0, chan; static int modem=0; BYTE *slipbuff; selectuart(chan = dtype & NETNUM_MASK); slipbuff = slipbuffs[chan]; while ((w = rxchar()) != NOCHAR) /* While Rx chars available.. */ { if (lastw == SLIP_ESC) /* Last char was Escape? */ { lastw = 0; w = w==ESC_END ? SLIP_END : w==ESC_ESC ? SLIP_ESC : w; } else if (w == SLIP_ESC) /* This char is Escape? */ { lastw = SLIP_ESC; w = NOCHAR; } else if (w == SLIP_END) /* No escape; maybe End? */ { w = NOCHAR; if (sliplens[chan] > 0) /* Do upcall to save packet */ receive_upcall(dtype, slipbuff, sliplens[chan]); sliplens[chan] = lastw = modem = 0; count = 1; } if (sliplens[chan]==0 && !modem) /* If start of new message.. */ modem = (w=='A' || w=='+'); /* ..check if start of modem cmd */ if (w!=NOCHAR && modem) /* If in modem mode.. */ do_modem((char)w); /* ..send char to modem handler */ else if (w!=NOCHAR && sliplens[chan]