home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / netsrcs / tiny_tcp < prev    next >
Internet Message Format  |  1986-05-16  |  46KB

  1. From geof@imagen.UUCP Thu May 15 20:13:10 1986
  2. Path: seismo!caip!topaz!ll-xn!mit-amt!mit-eddie!genrad!decvax!decwrl!sun!saber!imagen!geof
  3. From: geof@imagen.UUCP
  4. Newsgroups: net.sources
  5. Subject: TINYTCP-public domain tcp/ip implementation
  6. Message-ID: <366@imagen.UUCP>
  7. Date: 16 May 86 00:13:10 GMT
  8. Distribution: net
  9. Organization: IMAGEN Corporation, Santa Clara, CA 95052-8101
  10. Lines: 1524
  11.  
  12. #!/bin/sh
  13. : "This is a shell archive, meaning:                              "
  14. : "1. Remove everything above the #! /bin/sh line.                "
  15. : "2. Save the resulting test in a file.                          "
  16. : "3. Execute the file with /bin/sh (not csh) to create the files:"
  17. : "    README"
  18. : "    arp.c"
  19. : "    sed.c"
  20. : "    sed.h"
  21. : "    tinyftp.c"
  22. : "    tinytcp.c"
  23. : "    tinytcp.h"
  24. : "This archive created:  Thu May 15 16:43:07 PDT 1986 "
  25. echo file: README
  26. sed 's/^X//' >README << 'END-of-README'
  27. X
  28. X    TinyTcp Public Domain Release
  29. X
  30. XThe files in this release contain a simple implementation of
  31. XTCP & FTP, suitable for burning into ROM.  It is, in effect,
  32. Xa big hack put together in two or three days.  It works for
  33. Xus, though, and you might like it, too.  Warning: the code
  34. Xwas intended for a 68000, and doesn't have any byte swapping
  35. Xsupport in it.  Shouldn't be too hard to add, though.
  36. X
  37. X    - Geof Cooper
  38. X      Imagen Corporation
  39. X      [imagen!geof@decwrl.dec.com]
  40. X      April 16, 1986
  41. X
  42. XThe package requires some system support:
  43. X
  44. X    clock_ValueRough() - should be a procedure that returns the current
  45. X        value of a millisecond clock.  The procedure is called frequently,
  46. X        so that interrupts are not needed to service the clock.  Our
  47. X        implementation polls the real time timer and assumes that it is
  48. X        called frequently enough so that it doesn't miss clock ticks (Since
  49. X        the timer is only used for network timeouts, it doesn't really matter
  50. X        if it does miss clock ticks, of course).  Systems without a clock
  51. X        could probably get by with a procedure that increments a static
  52. X        variable and returns it, by adjusting the timeout constants in the
  53. X        program.
  54. X
  55. X    Network driver - some network interface  driver is needed.  A driver for a
  56. X        3Com multibus (ethernet) board is included; this board isn't made anymore
  57. X        (at least not by 3Com), so you'll probably need to write a driver for the
  58. X        board in your system.
  59. X
  60. X
  61. XGuide to source files:
  62. X
  63. X    sed.c - Simple Ethernet Driver - Driver for 3Com multibus card.  If you
  64. X            have another type of Ethernet board, you can use this driver as
  65. X            a template.
  66. X
  67. X    sed.h - header file for the above.
  68. X
  69. X    arp.c - Implementation of Address Resolution Protocol.  Note that there
  70. X            is no arp "mapping" per se.  The higher level code (tcp, in this case)
  71. X            is required to keep track of internet and ethernet addresses.
  72. X
  73. X    tinytcp.c - Implementation of TCP.
  74. X
  75. X    tinytcp.h - Header file for above, and for everything else.
  76. X
  77. X    tinyftp.c - Implementation of FTP, only allows files to be retrieved, not sent.
  78. END-of-README
  79. echo file: arp.c
  80. sed 's/^X//' >arp.c << 'END-of-arp.c'
  81. X/* 
  82. X * SAR: Simple Address Resolution Protocol Implementation
  83. X * Written by Geoffrey Cooper, September 27, 1983
  84. X * 
  85. X * This package implements a very simple version of the Plummer Address
  86. X * Resolution Protocol (RFC 826).  It allows clients to resolve Internet
  87. X * addresses into Ethernet addresses, and knows how to respond to an
  88. X * address resolution request (when the transmit buffer is free).
  89. X * 
  90. X * Routines:
  91. X * 
  92. X *  sar_CheckPacket( pb ) => 1, if ARP packet and processed, 0 otherwise
  93. X *  sar_MapIn2Eth( ina, ethap ) => 1 if did it, 0 if couldn't.
  94. X *
  95. X * Copyright (C) 1983, 1986 IMAGEN Corporation
  96. X *  "This code may be duplicated in whole or in part provided that [1] there
  97. X *   is no commercial gain involved in the duplication, and [2] that this
  98. X *   copyright notice is preserved on all copies.  Any other duplication
  99. X *   requires written notice of the author."
  100. X * 
  101. X */
  102. X#include "tinytcp.h"
  103. X
  104. Xsar_CheckPacket(ap)
  105. X    register arp_Header *ap;
  106. X{
  107. X    register arp_Header *op;
  108. X
  109. X    if ( ap->hwType != arp_TypeEther || /* have ethernet hardware, */
  110. X         ap->protType != 0x800 ||       /* and internet software, */
  111. X         ap->opcode != ARP_REQUEST ||   /* and be a resolution req. */
  112. X         ap->dstIPAddr != sin_lclINAddr /* for my addr. */
  113. X       ) return ( 0 );                  /* .... or we ignore it. */
  114. X
  115. X    /* format response. */
  116. X    op = (arp_Header *)sed_FormatPacket(ap->srcEthAddr, 0x806);
  117. X    op->hwType = arp_TypeEther;
  118. X    op->protType = 0x800;
  119. X    op->hwProtAddrLen = (sizeof(eth_HwAddress) << 8) + sizeof(in_HwAddress);
  120. X    op->opcode = ARP_REPLY;
  121. X    op->srcIPAddr = sin_lclINAddr;
  122. X    MoveW(sed_lclEthAddr, op->srcEthAddr, sizeof(eth_HwAddress));
  123. X    ap->dstIPAddr = op->srcIPAddr;
  124. X    MoveW(ap->srcEthAddr, op->dstEthAddr, sizeof(eth_HwAddress));
  125. X
  126. X    sed_Send(sizeof(arp_Header));
  127. X    
  128. X    return ( 1 );
  129. X}
  130. X
  131. X/* 
  132. X * Do an address resolution bit.
  133. X */
  134. Xsar_MapIn2Eth(ina, ethap)
  135. X    longword ina;
  136. X    eth_HwAddress *ethap;
  137. X{
  138. X    register arp_Header *op;
  139. X    extern in_HwAddress sin_lclINAddr;
  140. X    register i;
  141. X    longword endTime;
  142. X    longword rxMitTime;
  143. X
  144. X    sed_Receive( 0 );
  145. X    endTime = clock_ValueRough() + 2000;
  146. X    while ( endTime > clock_ValueRough() ) {
  147. X        op = (arp_Header *)sed_FormatPacket(&sed_ethBcastAddr[0], 0x806);
  148. X        op->hwType = arp_TypeEther;
  149. X        op->protType = 0x800;
  150. X        op->hwProtAddrLen = (sizeof(eth_HwAddress) << 8) + sizeof(in_HwAddress);
  151. X        op->opcode = ARP_REQUEST;
  152. X        op->srcIPAddr = sin_lclINAddr;
  153. X        MoveW(sed_lclEthAddr, op->srcEthAddr, sizeof(eth_HwAddress));
  154. X        op->dstIPAddr = ina;
  155. X
  156. X        /* ...and send the packet */
  157. X        sed_Send( sizeof(arp_Header) );
  158. X
  159. X        rxMitTime = clock_ValueRough() + 250;
  160. X        while ( rxMitTime > clock_ValueRough() ) {
  161. X            op = (arp_Header *)sed_IsPacket();
  162. X            if ( op ) {
  163. X                if ( sed_CheckPacket(op, 0x806) == 1 &&
  164. X                    op->protType == 0x800 &&
  165. X                    op->srcIPAddr == ina &&
  166. X                    op->opcode == ARP_REPLY ) {
  167. X                    MoveW(op->srcEthAddr, ethap, sizeof(eth_HwAddress));
  168. X                    return ( 1 );
  169. X                }
  170. X                sed_Receive(op);
  171. X            }
  172. X        }
  173. X    }
  174. X    return ( 0 );
  175. X}
  176. END-of-arp.c
  177. echo file: sed.c
  178. sed 's/^X//' >sed.c << 'END-of-sed.c'
  179. X/* 
  180. X * Ethernet Driver.
  181. X * A Very Simple set of ethernet driver primitives.  The ethernet (3com Mbus)
  182. X * interface is controlled by busy-waiting, the application is handed the
  183. X * location of on-board packet buffers, and allowed to fill in the
  184. X * transmit buffer directly.  The interface is entirely blocking.
  185. X * 
  186. X * Written March, 1986 by Geoffrey Cooper
  187. X *
  188. X * Copyright (C) 1986, IMAGEN Corporation
  189. X *  "This code may be duplicated in whole or in part provided that [1] there
  190. X *   is no commercial gain involved in the duplication, and [2] that this
  191. X *   copyright notice is preserved on all copies.  Any other duplication
  192. X *   requires written notice of the author."
  193. X * 
  194. X * Primitives:
  195. X *  sed_Init()  -- Initialize the package
  196. X *  sed_FormatPacket( destEAddr ) => location of transmit buffer
  197. X *  sed_Send( pkLength ) -- send the packet that is in the transmit buffer
  198. X *  sed_Receive( recBufLocation ) -- enable receiving packets.
  199. X *  sed_IsPacket() => location of packet in receive buffer
  200. X *  sed_CheckPacket( recBufLocation, expectedType )
  201. X *
  202. X * Global Variables:
  203. X *  sed_lclEthAddr -- Ethernet address of this host.
  204. X *  sed_ethBcastAddr -- Ethernet broadcast address.
  205. X */
  206. X
  207. X#include "tinytcp.h"
  208. X#include "sed.h"
  209. X
  210. X#define en10pages        ((en10size) >> pageshift)
  211. X
  212. Xoctet *sed_va;                          /* virtual address of ethernet card */
  213. Xeth_HwAddress sed_lclEthAddr;           /* local ethernet address */
  214. Xeth_HwAddress sed_ethBcastAddr;         /* Ethernet broadcast address */
  215. XBOOL sed_respondARPreq;                 /* controls responses to ARP req's */
  216. Xchar bufAinUse, bufBinUse;              /* tell whether bufs are in use */
  217. X
  218. X/* 
  219. X *  Initialize the Ethernet Interface, and this package.  Enable input on
  220. X * both buffers.
  221. X */
  222. Xsed_Init()
  223. X{
  224. X    int recState;
  225. X    register i, j;
  226. X
  227. X    recState = 7;                       /* == mine + broad - errors */
  228. X
  229. X    /* Map the Ethernet Interface in, and initialize sed_va */
  230. X    sed_va = (octet *)SED3CVA;        /* our virtual addr */
  231. X
  232. X    /* Map memory for 3Com board (must be 8k boundary) */
  233. X    /* INSERT CODE HERE */
  234. X    map_ethernet_board();
  235. X
  236. X    /* Reset the Ethernet controller */
  237. X    MECSR(sed_va) = RESET;
  238. X    for (i=0; i<10; i++);           /* delay a bit... */
  239. X
  240. X    /* just copy on-board ROM to on-board RAM, to use std. address */
  241. X    Move(MEAROM(sed_va), sed_lclEthAddr, 6);
  242. X    Move(sed_lclEthAddr, MEARAM(sed_va), 6);
  243. X    
  244. X    MECSR(sed_va) |= AMSW;        /* and tell board we did it */
  245. X
  246. X    /*
  247. X     * and initialize the exported variable which gives the Eth broadcast
  248. X     * address, for everyone else to use. 
  249. X     */
  250. X    for (i=0; i<3; i++) sed_ethBcastAddr[i] = 0xFFFF;
  251. X    
  252. X    /* accept packets addressed for us and broadcast packets */
  253. X
  254. X    MECSR(sed_va) = (MECSR(sed_va)&~PA) | recState;
  255. X
  256. X    /* declare both buffers in use... */
  257. X    bufAinUse = bufBinUse = TRUE;
  258. X
  259. X}
  260. X
  261. X/* 
  262. X * Format an ethernet header in the transmit buffer, and say where it is.
  263. X * Note that because of the way the 3Com interface works, we need to know
  264. X * how long the packet is before we know where to put it.  The solution is
  265. X * that we format the packet at the BEGINNING of the transmit buffer, and
  266. X * later copy it (carefully) to where it belongs.  Another hack would be
  267. X * to be inefficient about the size of the packet to be sent (always send
  268. X * a larger ethernet packet than you need to, but copying should be ok for
  269. X * now.
  270. X */
  271. Xoctet *
  272. Xsed_FormatPacket( destEAddr, ethType )
  273. X        register octet *destEAddr;
  274. X{
  275. X    register octet *xMitBuf;
  276. X    
  277. X    xMitBuf = &((octet *)MEXBUF(sed_va))[-0x800];
  278. X    Move( destEAddr, xMitBuf, 6 );
  279. X    Move( sed_lclEthAddr, xMitBuf + 6, 6 );
  280. X    *((short *)(xMitBuf+12)) = ethType;
  281. X    return ( xMitBuf+14 );
  282. X}
  283. X
  284. X/*
  285. X *  Send a packet out over the ethernet.  The packet is sitting at the
  286. X * beginning of the transmit buffer.  The routine returns when the
  287. X * packet has been successfully sent.
  288. X */
  289. Xsed_Send( pkLengthInOctets )
  290. X    register int pkLengthInOctets;
  291. X{
  292. X    register octet *fromO, *toO;
  293. X    register pkLength;
  294. X    register csr;
  295. X
  296. X    pkLengthInOctets += 14;             /* account for Ethernet header */
  297. X    pkLengthInOctets = (pkLengthInOctets + 1) & (~1);
  298. X
  299. X    if (pkLengthInOctets < E10P_MIN) 
  300. X        pkLengthInOctets = E10P_MIN; /* and min. ethernet len */
  301. X
  302. X    /*  and copy the packet where it belongs */
  303. X    pkLength = pkLengthInOctets;
  304. X    fromO = &((octet *)MEXBUF(sed_va))[-0x800] + pkLength;
  305. X    toO = ((octet *)MEXBUF(sed_va));
  306. X
  307. X    while ( pkLength-- ) *--toO = *--fromO;
  308. X    
  309. X    /* send the packet */
  310. X    
  311. X    MEXHDR(sed_va) = 2048 - pkLengthInOctets;
  312. X    MECSR(sed_va) |= TBSW;
  313. X
  314. X    /* and wait until it has really been sent. */
  315. X
  316. X    for (pkLength=0; pkLength < 15; pkLength++) {
  317. X        while ( (! ((csr = MECSR(sed_va)) & JAM)) && (csr & TBSW) )
  318. X            ;
  319. X        if (csr & JAM ) {
  320. X            /* Ethernet Collision detected... */
  321. X#ifdef DEBUG
  322. X            printf("sed: JAM: MECSR=%x\n", csr);
  323. X#endif
  324. X            MEBACK(sed_va) = clock_ValueRough();
  325. X            MECSR(sed_va) |= JAM;
  326. X        } else break;
  327. X    }
  328. X    if ( pkLength == 15 ) SysBug("Go and Buy a New Ethernet Interface.");
  329. X
  330. X    /*  else we sent the packet ok. */
  331. X}
  332. X
  333. X/* 
  334. X *  Enable the Ethernet interface to receive packets from the network.  If
  335. X * the argument is zero, enable both buffers.  If the argument is nonzero,
  336. X * take it as the address of the buffer to be enabled.
  337. X */
  338. Xsed_Receive( recBufLocation )
  339. X    octet *recBufLocation;
  340. X{
  341. X    word enables = 0;
  342. X
  343. X    if (recBufLocation == 0) {
  344. X        bufAinUse = FALSE;
  345. X        bufBinUse = FALSE;
  346. X        enables = (ABSW | BBSW);
  347. X    }
  348. X    recBufLocation -= 16;
  349. X    if (recBufLocation == ((octet *)MEAHDR(sed_va))) {
  350. X        bufAinUse = FALSE;
  351. X        enables = ABSW;
  352. X        }
  353. X    if (recBufLocation == ((octet *)MEBHDR(sed_va))) {
  354. X        bufBinUse = FALSE;
  355. X        enables = BBSW;
  356. X    }
  357. X
  358. X    MECSR (sed_va) |= enables;
  359. X}
  360. X
  361. X/* 
  362. X * Test for the arrival of a packet on the Ethernet interface.  The packet may
  363. X * arrive in either buffer A or buffer B; the location of the packet is
  364. X * returned.  If no packet is returned withing 'timeout' milliseconds,
  365. X * then the routine returns zero.
  366. X * 
  367. X * Note: ignores ethernet errors.  may occasionally return something
  368. X * which was received in error.
  369. X */
  370. X
  371. Xoctet *
  372. Xsed_IsPacket()
  373. X{
  374. X    register oldStatus;
  375. X    register octet *pb;
  376. X    
  377. X    pb = 0;
  378. X    if ( ! bufAinUse && (MECSR(sed_va)&ABSW) == 0 ) 
  379. X        pb = (octet *)MEAHDR(sed_va);
  380. X    if ( ! pb && ! bufBinUse && (MECSR(sed_va)&BBSW) == 0 )
  381. X        pb = (octet *)MEBHDR(sed_va);
  382. X
  383. X    if ( pb ) {
  384. X        if ( ((octet *)pb) == ((octet *)MEAHDR(sed_va)) ) bufAinUse = 1;
  385. X        else bufBinUse = 1;
  386. X        pb += 16;                       /* get past the ethernet header */
  387. X    }
  388. X
  389. X    return ( pb );
  390. X}
  391. X
  392. X/* 
  393. X *  Check to make sure that the packet that you received was the one that
  394. X * you expected to get.
  395. X */
  396. Xsed_CheckPacket( recBufLocation, expectedType )
  397. X    word *recBufLocation;
  398. X    word expectedType;
  399. X{
  400. X    register recHeader = recBufLocation[-8];
  401. X    if ( (recHeader&R_ERROR) != 0 ||
  402. X         (recHeader&R_OFFSET) < E10P_MIN ) {
  403. X         return ( -1 );
  404. X    }
  405. X    if ( recBufLocation[-1] != expectedType ) {
  406. X        return ( 0 );
  407. X    }
  408. X    return (1);
  409. X}
  410. END-of-sed.c
  411. echo file: sed.h
  412. sed 's/^X//' >sed.h << 'END-of-sed.h'
  413. X/* 
  414. X *  Header file for very simple ethernet driver, based on 3Com Multibus
  415. X *  board.
  416. X *
  417. X * Copyright (C) 1986, IMAGEN Corporation
  418. X *  "This code may be duplicated in whole or in part provided that [1] there
  419. X *   is no commercial gain involved in the duplication, and [2] that this
  420. X *   copyright notice is preserved on all copies.  Any other duplication
  421. X *   requires written notice of the author."
  422. X */
  423. X
  424. X#define    en10size        (8*1024)    /* size of interface memory */
  425. X#define    en10pages    ((en10size) >> pageshift)
  426. X#define E10P_MIN    60              /* Minimum Ethernet packet size */
  427. X
  428. X/* 
  429. X * The position of the 3Com interface in virtual memory.  If we're
  430. X * Running the bootloader function, then it must be in the last 8k
  431. X * of virtual addresses.
  432. X */
  433. X#ifdef BOOTLOADER
  434. X#define SED3CVA vm_3ComAdr /* hack, only need pb68.h if bootloader */
  435. X#endif
  436. X#ifndef SED3CVA
  437. X#define SED3CVA 0x1c000
  438. X#endif
  439. X
  440. X/* 10Mb Ethernet interface addresses */
  441. X
  442. X#define    MECSR(eth_va)    *(word*)(((octet *) eth_va) + 0x0)
  443. X#define    MEBACK(eth_va)    *(word*)(((octet *) eth_va) + 0x2)
  444. X#define    MEAROM(eth_va)    (word*)(((octet *) eth_va) + 0x400)
  445. X#define    MEARAM(eth_va)    (word*)(((octet *) eth_va) + 0x600)
  446. X#define    MEXHDR(eth_va)    *(word*)(((octet *) eth_va) + 0x800)
  447. X#define    MEXBUF(eth_va)    (word*)(((octet *) eth_va) + 0x1000)
  448. X#define    MEAHDR(eth_va)    (word*)(((octet *) eth_va) + 0x1000)
  449. X#define    MEBHDR(eth_va)    (word*)(((octet *) eth_va) + 0x1800)
  450. X
  451. X/* control/status register fields */
  452. X
  453. X#define    BBSW        0x8000    /* Buffer B belongs to Network */
  454. X#define    ABSW        0x4000    /* Buffer A belongs to Network */
  455. X#define    TBSW        0x2000    /* Transmit buffer belongs to Network */
  456. X#define    JAM        0x1000    /* Set when transmit collision */
  457. X#define    AMSW        0x0800    /* 
  458. X#define    RBBA        0x0400    /* Oldest received packet is in B */
  459. X/*#define    UNUSED        0x0200 */
  460. X#define    RESET        0x0100    /* Reset the controller */
  461. X#define    BINT        0x0080    /* Interrupt when BBSW=>0 (packet in B) */
  462. X#define    AINT        0x0040    /* Interrupt when ABSW=>0 (packet in A) */
  463. X#define    TINT        0x0020    /* Interrupt when TBSW=>0 (transmit done) */
  464. X#define    JINT        0x0010    /* Enable interrupts when JAM=>1 */
  465. X#define    PA        0x000F    /* Which packets should be received? */
  466. X#define INTENABLS    0x00F0
  467. X
  468. X/*
  469. X * Receiver Header Fields: 
  470. X * The receiver header is the first (short) word of the receive buffer.  It
  471. X * includes such information as how big the packet is, whether it was a
  472. X * broadcast, whether there was an error in receiving it, etc.
  473. X */
  474. X
  475. X#define    R_FCS        0x8000    /* fcs error */
  476. X#define    R_BCAST        0x4000    /* packet was NOT a broadcast */
  477. X#define    R_RANGE        0x2000    /* range error (size of pkt?) */
  478. X#define    R_MATCH        0x1000    /* packet is multicast (i.e., address
  479. X                   received is not that of the interface) */
  480. X#define    R_FRAME        0x0800    /* framing error */
  481. X#define    R_ERROR        0x8800    /* was there any error */
  482. X#define    R_OFFSET    0x07FF    /* packet length + 1 word */
  483. X
  484. Xextern octet *sed_FormatPacket(), *sed_WaitPacket();
  485. X
  486. X#ifdef BOOTLOADER
  487. X#define ConsPrintf printf
  488. X#endif
  489. END-of-sed.h
  490. echo file: tinyftp.c
  491. sed 's/^X//' >tinyftp.c << 'END-of-tinyftp.c'
  492. X/*
  493. X * tinyftp.c - user ftp built on tinytcp.c
  494. X *
  495. X * Written March 31, 1986 by Geoffrey Cooper
  496. X *
  497. X * Copyright (C) 1986, IMAGEN Corporation
  498. X *  "This code may be duplicated in whole or in part provided that [1] there
  499. X *   is no commercial gain involved in the duplication, and [2] that this
  500. X *   copyright notice is preserved on all copies.  Any other duplication
  501. X *   requires written notice of the author."
  502. X */
  503. X#include "tinytcp.h"
  504. X
  505. Xtcp_Socket ftp_ctl, ftp_data, ftp_data2;
  506. Xbyte ftp_cmdbuf[120];
  507. Xint ftp_cmdbufi;
  508. X
  509. Xbyte ftp_outbuf[80];
  510. Xint ftp_outbufix, ftp_outbuflen;
  511. X    
  512. Xshort ftp_rcvState;
  513. X#define ftp_StateGETCMD     0       /* get a command from the user */
  514. X#define ftp_StateIDLE       1       /* idle connection */
  515. X#define ftp_StateINCOMMAND  2       /* command sent, awaiting response */
  516. X#define ftp_StateRCVRESP    3       /* received response, need more data */
  517. X
  518. Xchar *ftp_script[7];
  519. Xint ftp_scriptline;
  520. Xchar ftp_retrfile[80];
  521. XBOOL ftp_echoMode;
  522. X
  523. Xftp_ctlHandler(s, dp, len)
  524. X    tcp_Socket *s;
  525. X    byte *dp;
  526. X    int len;
  527. X{
  528. X    byte c, *bp, data[80];
  529. X    int i;
  530. X
  531. X    if ( dp == 0 ) {
  532. X        tcp_Abort(&ftp_data);
  533. X        return;
  534. X    }
  535. X
  536. X    do {
  537. X        i = len;
  538. X        if ( i > sizeof data ) i = sizeof data;
  539. X        MoveW(dp, data, i);
  540. X        len -= i;
  541. X        bp = data;
  542. X        while ( i-- > 0 ) {
  543. X            c = *bp++;
  544. X            if ( c != '\r' ) {
  545. X                if ( c == '\n' ) {
  546. X                    ftp_cmdbuf[ftp_cmdbufi] = 0;
  547. X                    ftp_commandLine();
  548. X                    ftp_cmdbufi = 0;
  549. X                } else if ( ftp_cmdbufi < (sizeof ftp_cmdbuf)-1 ) {
  550. X                    ftp_cmdbuf[ftp_cmdbufi++] = c;
  551. X                }
  552. X            }
  553. X        }
  554. X    } while ( len > 0 );
  555. X}
  556. X
  557. Xftp_commandLine()
  558. X{
  559. X    printf("> %s\n", ftp_cmdbuf);
  560. X    switch(ftp_rcvState) {
  561. X     case ftp_StateIDLE:
  562. X        if ( ftp_cmdbuf[3] == '-' )
  563. X            ftp_rcvState = ftp_StateRCVRESP;
  564. X        break;
  565. X
  566. X     case ftp_StateINCOMMAND:
  567. X        if ( ftp_cmdbuf[3] == '-' )
  568. X            ftp_rcvState = ftp_StateRCVRESP;
  569. X     case ftp_StateRCVRESP:
  570. X        if ( ftp_cmdbuf[3] == ' ' )
  571. X            ftp_rcvState = ftp_StateIDLE;
  572. X        break;
  573. X    }
  574. X}
  575. X
  576. Xftp_Abort()
  577. X{
  578. X    tcp_Abort(&ftp_ctl);
  579. X    tcp_Abort(&ftp_data);
  580. X}
  581. X
  582. X
  583. Xftp_application()
  584. X{
  585. X    char *s;
  586. X    char *dp;
  587. X    int i;
  588. X
  589. X    i = -1;
  590. X    if ( isina() ) {
  591. X        i = busyina() & 0177;
  592. X#ifdef DEBUG
  593. X        if ( i == ('D' & 037) ) SysBug("Pause to DDT");
  594. X#endif
  595. X        if ( i == ('C' & 037) ) {
  596. X            printf("Closing...\n");
  597. X            tcp_Close(&ftp_ctl);
  598. X        }
  599. X    }
  600. X
  601. X    switch (ftp_rcvState) {
  602. X      case ftp_StateGETCMD:
  603. X getcmd:if ( i != -1 ) {
  604. X            ftp_outbuf[ftp_outbuflen] = 0;
  605. X            switch (i) {
  606. X                case 'H' & 037:
  607. X                case 0177:
  608. X                    if ( ftp_outbuflen > 0 ) {
  609. X                        ftp_outbuflen--;
  610. X                        printf("\010 \010");
  611. X                    }
  612. X                    break;
  613. X
  614. X                case 'R' & 037:
  615. X                    if ( ftp_echoMode )
  616. X                        printf("\nFtpCmd> %s", ftp_outbuf);
  617. X                    break;
  618. X
  619. X                case 033:
  620. X                    ftp_echoMode = ! ftp_echoMode;
  621. X                    break;
  622. X
  623. X                case '\r':
  624. X                case '\n':
  625. X                    busyouta('\n');
  626. X                    dp = &ftp_outbuf[ftp_outbuflen];
  627. X                    goto docmd;
  628. X
  629. X                default:
  630. X                    if ( i >= ' ' && ftp_outbuflen < sizeof ftp_outbuf ) {
  631. X                        ftp_outbuf[ftp_outbuflen++] = i;
  632. X                        if ( ftp_echoMode ) busyouta(i);
  633. X                    }
  634. X            }
  635. X        }
  636. X        break;
  637. X
  638. X      case ftp_StateIDLE:
  639. X        if ( ftp_scriptline < 0 ) {
  640. X            ftp_rcvState = ftp_StateGETCMD;
  641. X            ftp_echoMode = true;
  642. X            ftp_outbuflen = 0;
  643. X            printf("FtpCmd> ");
  644. X            goto getcmd;
  645. X        }
  646. X        s = ftp_script[ftp_scriptline];
  647. X        if ( s == NIL )
  648. X            break;
  649. X        ftp_scriptline++;
  650. X        printf("%s\n", s);
  651. X        dp = ftp_outbuf;
  652. X        while ( *dp++ = *s++ ) ;
  653. X        dp--;
  654. X docmd: *dp++ = '\r';
  655. X        *dp++ = '\n';
  656. X        ftp_outbuflen = dp - ftp_outbuf;
  657. X        ftp_outbufix = 0;
  658. X        ftp_rcvState = ftp_StateINCOMMAND;
  659. X        /* fall through */
  660. X    case ftp_StateINCOMMAND:
  661. X        i = ftp_outbuflen - ftp_outbufix;
  662. X        if ( i > 0 ) {
  663. X            i = tcp_Write(&ftp_ctl, &ftp_outbuf[ftp_outbufix], i);
  664. X            ftp_outbufix += i;
  665. X            tcp_Flush(&ftp_ctl);
  666. X        }
  667. X        /* fall through */
  668. X    case ftp_StateRCVRESP:
  669. X        break;
  670. X    }
  671. X
  672. X}
  673. X
  674. Xftp(host, fn, dataHandler)
  675. X    in_HwAddress host;
  676. X    char *fn;
  677. X    procref dataHandler;
  678. X{
  679. X    word port;
  680. X    char filecmd[80];
  681. X
  682. X    port = (sed_lclEthAddr[2] + clock_ValueRough()) | 0x8000;
  683. X
  684. X    if ( fn ) {
  685. X        /* set up the script for this session */
  686. X        ftp_script[0] = "user foo";
  687. X        ftp_script[1] = "pass foo";
  688. X        ftp_script[2] = "type i";
  689. X        sprintf(filecmd, "retr %s", fn);
  690. X        ftp_script[3] = filecmd;
  691. X        ftp_script[4] = "quit";
  692. X        ftp_script[5] = 0;
  693. X        ftp_scriptline = 0;
  694. X    } else {
  695. X        ftp_scriptline = -1;        /* interactive mode */
  696. X        ftp_echoMode = true;
  697. X    }
  698. X
  699. X    /* set up state variables */
  700. X    ftp_rcvState = ftp_StateRCVRESP;
  701. X    ftp_cmdbufi = 0;
  702. X    tcp_Listen(&ftp_data, port, dataHandler, 0);
  703. X    tcp_Open(&ftp_ctl, port, host, 21, ftp_ctlHandler);
  704. X    tcp(ftp_application);
  705. X}
  706. END-of-tinyftp.c
  707. echo file: tinytcp.c
  708. sed 's/^X//' >tinytcp.c << 'END-of-tinytcp.c'
  709. X/*
  710. X * tinytcp.c - Tiny Implementation of the Transmission Control Protocol
  711. X *
  712. X * Written March 28, 1986 by Geoffrey Cooper, IMAGEN Corporation.
  713. X *
  714. X * This code is a small implementation of the TCP and IP protocols, suitable
  715. X * for burning into ROM.  The implementation is bare-bones and represents
  716. X * two days' coding efforts.  A timer and an ethernet board are assumed.  The
  717. X * implementation is based on busy-waiting, but the tcp_handler procedure
  718. X * could easily be integrated into an interrupt driven scheme.
  719. X *
  720. X * IP routing is accomplished on active opens by broadcasting the tcp SYN
  721. X * packet when ARP mapping fails.  If anyone answers, the ethernet address
  722. X * used is saved for future use.  This also allows IP routing on incoming
  723. X * connections.
  724. X * 
  725. X * The TCP does not implement urgent pointers (easy to add), and discards
  726. X * segments that are received out of order.  It ignores the received window
  727. X * and always offers a fixed window size on input (i.e., it is not flow
  728. X * controlled).
  729. X *
  730. X * Special care is taken to access the ethernet buffers only in word
  731. X * mode.  This is to support boards that only allow word accesses.
  732. X *
  733. X * Copyright (C) 1986, IMAGEN Corporation
  734. X *  "This code may be duplicated in whole or in part provided that [1] there
  735. X *   is no commercial gain involved in the duplication, and [2] that this
  736. X *   copyright notice is preserved on all copies.  Any other duplication
  737. X *   requires written notice of the author."
  738. X */
  739. X
  740. X#include "tinytcp.h"
  741. X
  742. X/*
  743. X * Local IP address
  744. X */
  745. Xin_HwAddress sin_lclINAddr;
  746. X
  747. X/*
  748. X * IP identification numbers
  749. X */
  750. Xint tcp_id;
  751. X
  752. Xtcp_Socket *tcp_allsocs;
  753. X
  754. X/* Timer definitions */
  755. X#define tcp_RETRANSMITTIME 1000     /* interval at which retransmitter is called */
  756. X#define tcp_LONGTIMEOUT 31000       /* timeout for opens */
  757. X#define tcp_TIMEOUT 10000           /* timeout during a connection */
  758. X
  759. X#ifdef DEBUG
  760. X/* 
  761. X * Primitive logging facility
  762. X */
  763. X#define tcp_LOGPACKETS 1        /* log packet headers */
  764. Xword tcp_logState;
  765. X#endif
  766. X
  767. X/*
  768. X * Initialize the tcp implementation
  769. X */
  770. Xtcp_Init()
  771. X{
  772. X    extern eth_HwAddress sed_lclEthAddr;
  773. X
  774. X    /* initialize ethernet interface */
  775. X    sed_Init();
  776. X
  777. X    tcp_allsocs = NIL;
  778. X#ifdef DEBUG
  779. X    tcp_logState = 0;
  780. X#endif
  781. X    tcp_id = 0;
  782. X
  783. X    /* hack - assume the network number */
  784. X    sin_lclINAddr = 0x7d000000 + (*((longword *)&sed_lclEthAddr[1]) & 0xFFFFFF);
  785. X}
  786. X
  787. X/*
  788. X * Actively open a TCP connection to a particular destination.
  789. X */
  790. Xtcp_Open(s, lport, ina, port, datahandler)
  791. X    tcp_Socket *s;
  792. X    in_HwAddress ina;
  793. X    word lport, port;
  794. X    procref datahandler;
  795. X{
  796. X    extern eth_HwAddress sed_ethBcastAddr;
  797. X
  798. X    s->state = tcp_StateSYNSENT;
  799. X    s->timeout = tcp_LONGTIMEOUT;
  800. X    if ( lport == 0 ) lport = clock_ValueRough();
  801. X    s->myport = lport;
  802. X    if ( ! sar_MapIn2Eth(ina, &s->hisethaddr[0]) ) {
  803. X        printf("tcp_Open of 0x%x: defaulting ethernet address to broadcast\n", ina);
  804. X        Move(&sed_ethBcastAddr[0], &s->hisethaddr[0], sizeof(eth_HwAddress));
  805. X    }
  806. X    s->hisaddr = ina;
  807. X    s->hisport = port;
  808. X    s->seqnum = 0;
  809. X    s->dataSize = 0;
  810. X    s->flags = tcp_FlagSYN;
  811. X    s->unhappy = true;
  812. X    s->dataHandler = datahandler;
  813. X    s->next = tcp_allsocs;
  814. X    tcp_allsocs = s;
  815. X    tcp_Send(s);
  816. X}
  817. X
  818. X/*
  819. X * Passive open: listen for a connection on a particular port
  820. X */
  821. Xtcp_Listen(s, port, datahandler, timeout)
  822. X    tcp_Socket *s;
  823. X    word port;
  824. X    procref datahandler;
  825. X{
  826. X    s->state = tcp_StateLISTEN;
  827. X    if ( timeout == 0 ) s->timeout = 0x7ffffff; /* forever... */
  828. X    else s->timeout = timeout;
  829. X    s->myport = port;
  830. X    s->hisport = 0;
  831. X    s->seqnum = 0;
  832. X    s->dataSize = 0;
  833. X    s->flags = 0;
  834. X    s->unhappy = 0;
  835. X    s->dataHandler = datahandler;
  836. X    s->next = tcp_allsocs;
  837. X    tcp_allsocs = s;
  838. X}
  839. X
  840. X/*
  841. X * Send a FIN on a particular port -- only works if it is open
  842. X */
  843. Xtcp_Close(s)
  844. X    tcp_Socket *s;
  845. X{
  846. X    if ( s->state == tcp_StateESTAB || s->state == tcp_StateSYNREC ) {
  847. X        s->flags = tcp_FlagACK | tcp_FlagFIN;
  848. X        s->state = tcp_StateFINWT1;
  849. X        s->unhappy = true;
  850. X    }
  851. X}
  852. X
  853. X/*
  854. X * Abort a tcp connection
  855. X */
  856. Xtcp_Abort(s)
  857. X    tcp_Socket *s;
  858. X{
  859. X    if ( s->state != tcp_StateLISTEN && s->state != tcp_StateCLOSED ) {
  860. X        s->flags = tcp_FlagRST | tcp_FlagACK;
  861. X        tcp_Send(s);
  862. X    }
  863. X    s->unhappy = 0;
  864. X    s->dataSize = 0;
  865. X    s->state = tcp_StateCLOSED;
  866. X    s->dataHandler(s, 0, -1);
  867. X    tcp_Unthread(s);
  868. X}
  869. X
  870. X/*
  871. X * Retransmitter - called periodically to perform tcp retransmissions
  872. X */
  873. Xtcp_Retransmitter()
  874. X{
  875. X    tcp_Socket *s;
  876. X    BOOL x;
  877. X
  878. X    for ( s = tcp_allsocs; s; s = s->next ) {
  879. X        x = false;
  880. X        if ( s->dataSize > 0 || s->unhappy ) {
  881. X            tcp_Send(s);
  882. X            x = true;
  883. X        }
  884. X        if ( x || s->state != tcp_StateESTAB )
  885. X            s->timeout -= tcp_RETRANSMITTIME;
  886. X        if ( s->timeout <= 0 ) {
  887. X            if ( s->state == tcp_StateTIMEWT ) {
  888. X                printf("Closed.    \n");
  889. X                s->state = tcp_StateCLOSED;
  890. X                s->dataHandler(s, 0, 0);
  891. X                tcp_Unthread(s);
  892. X            } else {
  893. X                printf("Timeout, aborting\n");
  894. X                tcp_Abort(s);
  895. X            }
  896. X        }
  897. X    }
  898. X}
  899. X
  900. X/*
  901. X * Unthread a socket from the socket list, if it's there 
  902. X */
  903. Xtcp_Unthread(ds)
  904. X    tcp_Socket *ds;
  905. X{
  906. X    tcp_Socket *s, **sp;
  907. X
  908. X    sp = &tcp_allsocs;
  909. X    for (;;) {
  910. X        s = *sp;
  911. X        if ( s == ds ) {
  912. X            *sp = s->next;
  913. X            break;
  914. X        }
  915. X        if ( s == NIL ) break;
  916. X        sp = &s->next;
  917. X    }
  918. X}
  919. X
  920. X/*
  921. X * busy-wait loop for tcp.  Also calls an "application proc"
  922. X */
  923. Xtcp(application)
  924. X    procref application;
  925. X{
  926. X    in_Header *ip;
  927. X    longword timeout, start;
  928. X    int x;
  929. X
  930. X    sed_Receive(0);
  931. X
  932. X    timeout = 0;
  933. X    while ( tcp_allsocs ) {
  934. X        start = clock_ValueRough();
  935. X        ip = sed_IsPacket();
  936. X        if ( ip == NIL ) {
  937. X            if ( clock_ValueRough() > timeout ) {
  938. X                tcp_Retransmitter();
  939. X                timeout = clock_ValueRough() + tcp_RETRANSMITTIME;
  940. X            }
  941. X
  942. X            application();
  943. X
  944. X            continue;
  945. X        }
  946. X
  947. X        if ( sed_CheckPacket(ip, 0x806) == 1 ) {
  948. X            /* do arp */
  949. X            sar_CheckPacket(ip);
  950. X
  951. X        } else if ( sed_CheckPacket(ip, 0x800) == 1 ) {
  952. X            /* do IP */
  953. X            if ( ip->destination == sin_lclINAddr &&
  954. X                 in_GetProtocol(ip) == 6 &&
  955. X                 checksum(ip, in_GetHdrlenBytes(ip)) == 0xFFFF ) {
  956. X                tcp_Handler(ip);
  957. X            }
  958. X        }
  959. X        /* recycle buffer */
  960. X        sed_Receive(ip);
  961. X
  962. X        x = clock_ValueRough() - start;
  963. X        timeout -= x;
  964. X    }
  965. X
  966. X    return ( 1 );
  967. X}
  968. X
  969. X/*
  970. X * Write data to a connection.
  971. X * Returns number of bytes written, == 0 when connection is not in
  972. X * established state.
  973. X */
  974. Xtcp_Write(s, dp, len)
  975. X    tcp_Socket *s;
  976. X    byte *dp;
  977. X    int len;
  978. X{
  979. X    int x;
  980. X
  981. X    if ( s->state != tcp_StateESTAB ) len = 0;
  982. X    if ( len > (x = tcp_MaxData - s->dataSize) ) len = x;
  983. X    if ( len > 0 ) {
  984. X        Move(dp, &s->data[s->dataSize], len);
  985. X        s->dataSize += len;
  986. X        tcp_Flush(s);
  987. X    }
  988. X
  989. X    return ( len );
  990. X}
  991. X
  992. X/*
  993. X * Send pending data
  994. X */
  995. Xtcp_Flush(s)
  996. X    tcp_Socket *s;
  997. X{
  998. X    if ( s->dataSize > 0 ) {
  999. X        s->flags |= tcp_FlagPUSH;
  1000. X        tcp_Send(s);
  1001. X    }
  1002. X}
  1003. X
  1004. X/*
  1005. X * Handler for incoming packets.
  1006. X */
  1007. Xtcp_Handler(ip)
  1008. X    in_Header *ip;
  1009. X{
  1010. X    tcp_Header *tp;
  1011. X    tcp_PseudoHeader ph;
  1012. X    int len;
  1013. X    byte *dp;
  1014. X    int x, diff;
  1015. X    tcp_Socket *s;
  1016. X    word flags;
  1017. X
  1018. X    len = in_GetHdrlenBytes(ip);
  1019. X    tp = (tcp_Header *)((byte *)ip + len);
  1020. X    len = ip->length - len;
  1021. X
  1022. X    /* demux to active sockets */
  1023. X    for ( s = tcp_allsocs; s; s = s->next )
  1024. X        if ( s->hisport != 0 &&
  1025. X             tp->dstPort == s->myport &&
  1026. X             tp->srcPort == s->hisport &&
  1027. X             ip->source == s->hisaddr ) break;
  1028. X    if ( s == NIL ) {
  1029. X        /* demux to passive sockets */
  1030. X        for ( s = tcp_allsocs; s; s = s->next )
  1031. X            if ( s->hisport == 0 && tp->dstPort == s->myport ) break;
  1032. X    }
  1033. X    if ( s == NIL ) {
  1034. X#ifdef DEBUG
  1035. X        if ( tcp_logState & tcp_LOGPACKETS ) tcp_DumpHeader(ip, tp, "Discarding");
  1036. X#endif
  1037. X        return;
  1038. X    }
  1039. X
  1040. X#ifdef DEBUG
  1041. X    if ( tcp_logState & tcp_LOGPACKETS )
  1042. X        tcp_DumpHeader(ip, tp, "Received");
  1043. X#endif
  1044. X
  1045. X    /* save his ethernet address */
  1046. X    MoveW(&((((eth_Header *)ip) - 1)->source[0]), &s->hisethaddr[0], sizeof(eth_HwAddress));
  1047. X
  1048. X    ph.src = ip->source;
  1049. X    ph.dst = ip->destination;
  1050. X    ph.mbz = 0;
  1051. X    ph.protocol = 6;
  1052. X    ph.length = len;
  1053. X    ph.checksum = checksum(tp, len);
  1054. X    if ( checksum(&ph, sizeof ph) != 0xffff )
  1055. X         printf("bad tcp checksum, received anyway\n");
  1056. X
  1057. X    flags = tp->flags;
  1058. X    if ( flags & tcp_FlagRST ) {
  1059. X        printf("connection reset\n");
  1060. X        s->state = tcp_StateCLOSED;
  1061. X        s->dataHandler(s, 0, -1);
  1062. X        tcp_Unthread(s);
  1063. X        return;
  1064. X    }
  1065. X
  1066. X    switch ( s->state ) {
  1067. X
  1068. X    case tcp_StateLISTEN:
  1069. X        if ( flags & tcp_FlagSYN ) {
  1070. X            s->acknum = tp->seqnum + 1;
  1071. X            s->hisport = tp->srcPort;
  1072. X            s->hisaddr = ip->source;
  1073. X            s->flags = tcp_FlagSYN | tcp_FlagACK;
  1074. X            tcp_Send(s);
  1075. X            s->state = tcp_StateSYNREC;
  1076. X            s->unhappy = true;
  1077. X            s->timeout = tcp_TIMEOUT;
  1078. X            printf("Syn from 0x%x#%d (seq 0x%x)\n", s->hisaddr, s->hisport, tp->seqnum);
  1079. X        }
  1080. X        break;
  1081. X
  1082. X    case tcp_StateSYNSENT:
  1083. X        if ( flags & tcp_FlagSYN ) {
  1084. X            s->acknum++;
  1085. X            s->flags = tcp_FlagACK;
  1086. X            s->timeout = tcp_TIMEOUT;
  1087. X            if ( (flags & tcp_FlagACK) && tp->acknum == (s->seqnum + 1) ) {
  1088. X                printf("Open\n");
  1089. X                s->state = tcp_StateESTAB;
  1090. X                s->seqnum++;
  1091. X                s->acknum = tp->seqnum + 1;
  1092. X                s->unhappy = false;
  1093. X            } else {
  1094. X                s->state = tcp_StateSYNREC;
  1095. X            }
  1096. X        }
  1097. X        break;
  1098. X
  1099. X    case tcp_StateSYNREC:
  1100. X        if ( flags & tcp_FlagSYN ) {
  1101. X            s->flags = tcp_FlagSYN | tcp_FlagACK;
  1102. X            tcp_Send(s);
  1103. X            s->timeout = tcp_TIMEOUT;
  1104. X            printf(" retransmit of original syn\n");
  1105. X        }
  1106. X        if ( (flags & tcp_FlagACK) && tp->acknum == (s->seqnum + 1) ) {
  1107. X            s->flags = tcp_FlagACK;
  1108. X            tcp_Send(s);
  1109. X            s->seqnum++;
  1110. X            s->unhappy = false;
  1111. X            s->state = tcp_StateESTAB;
  1112. X            s->timeout = tcp_TIMEOUT;
  1113. X            printf("Synack received - connection established\n");
  1114. X        }
  1115. X        break;
  1116. X
  1117. X    case tcp_StateESTAB:
  1118. X        if ( (flags & tcp_FlagACK) == 0 ) return;
  1119. X        /* process ack value in packet */
  1120. X        diff = tp->acknum - s->seqnum;
  1121. X        if ( diff > 0 ) {
  1122. X            Move(&s->data[diff], &s->data[0], diff);
  1123. X            s->dataSize -= diff;
  1124. X            s->seqnum += diff;
  1125. X        }
  1126. X        s->flags = tcp_FlagACK;
  1127. X        tcp_ProcessData(s, tp, len);
  1128. X        break;
  1129. X
  1130. X    case tcp_StateFINWT1:
  1131. X        if ( (flags & tcp_FlagACK) == 0 ) return;
  1132. X        diff = tp->acknum - s->seqnum - 1;
  1133. X        s->flags = tcp_FlagACK | tcp_FlagFIN;
  1134. X        if ( diff == 0 ) {
  1135. X            s->state = tcp_StateFINWT2;
  1136. X            s->flags = tcp_FlagACK;
  1137. X            printf("finack received.\n");
  1138. X        }
  1139. X        tcp_ProcessData(s, tp, len);
  1140. X        break;
  1141. X
  1142. X    case tcp_StateFINWT2:
  1143. X        s->flags = tcp_FlagACK;
  1144. X        tcp_ProcessData(s, tp, len);
  1145. X        break;
  1146. X
  1147. X    case tcp_StateCLOSING:
  1148. X        if ( tp->acknum == (s->seqnum + 1) ) {
  1149. X            s->state = tcp_StateTIMEWT;
  1150. X            s->timeout = tcp_TIMEOUT;
  1151. X        }
  1152. X        break;
  1153. X
  1154. X    case tcp_StateLASTACK:
  1155. X        if ( tp->acknum == (s->seqnum + 1) ) {
  1156. X            s->state = tcp_StateCLOSED;
  1157. X            s->unhappy = false;
  1158. X            s->dataSize = 0;
  1159. X            s->dataHandler(s, 0, 0);
  1160. X            tcp_Unthread(s);
  1161. X            printf("Closed.    \n");
  1162. X        } else {
  1163. X            s->flags = tcp_FlagACK | tcp_FlagFIN;
  1164. X            tcp_Send(s);
  1165. X            s->timeout = tcp_TIMEOUT;
  1166. X            printf("retransmitting FIN\n");
  1167. X        }
  1168. X        break;
  1169. X
  1170. X    case tcp_StateTIMEWT:
  1171. X        s->flags = tcp_FlagACK;
  1172. X        tcp_Send(s);
  1173. X    }
  1174. X}
  1175. X
  1176. X/*
  1177. X * Process the data in an incoming packet.
  1178. X * Called from all states where incoming data can be received: established,
  1179. X * fin-wait-1, fin-wait-2
  1180. X */
  1181. Xtcp_ProcessData(s, tp, len)
  1182. X    tcp_Socket *s;
  1183. X    tcp_Header *tp;
  1184. X    int len;
  1185. X{
  1186. X    int diff, x;
  1187. X    word flags;
  1188. X    byte *dp;
  1189. X
  1190. X    flags = tp->flags;
  1191. X    diff = s->acknum - tp->seqnum;
  1192. X    if ( flags & tcp_FlagSYN ) diff--;
  1193. X    x = tcp_GetDataOffset(tp) << 2;
  1194. X    dp = (byte *)tp + x;
  1195. X    len -= x;
  1196. X    if ( diff >= 0 ) {
  1197. X        dp += diff;
  1198. X        len -= diff;
  1199. X        s->acknum += len;
  1200. X        s->dataHandler(s, dp, len);
  1201. X        if ( flags & tcp_FlagFIN ) {
  1202. X            s->acknum++;
  1203. X#ifdef DEBUG
  1204. X            printf("consumed fin.\n");
  1205. X#endif
  1206. X            switch(s->state) {
  1207. X              case tcp_StateESTAB:
  1208. X                /* note: skip state CLOSEWT by automatically closing conn */
  1209. X                x = tcp_StateLASTACK;
  1210. X                s->flags |= tcp_FlagFIN;
  1211. X                s->unhappy = true;
  1212. X#ifdef DEBUG
  1213. X                printf("sending fin.\n");
  1214. X#endif
  1215. X                break;
  1216. X              case tcp_StateFINWT1:
  1217. X                x = tcp_StateCLOSING;
  1218. X                break;
  1219. X              case tcp_StateFINWT2:
  1220. X                x = tcp_StateTIMEWT;
  1221. X                break;
  1222. X            }
  1223. X            s->state = x;
  1224. X        }
  1225. X    }
  1226. X    s->timeout = tcp_TIMEOUT;
  1227. X    tcp_Send(s);
  1228. X}
  1229. X
  1230. X/*
  1231. X * Format and send an outgoing segment
  1232. X */
  1233. Xtcp_Send(s)
  1234. X    tcp_Socket *s;
  1235. X{
  1236. X    tcp_PseudoHeader ph;
  1237. X    struct _pkt {
  1238. X        in_Header in;
  1239. X        tcp_Header tcp;
  1240. X        longword maxsegopt;
  1241. X    } *pkt;
  1242. X    byte *dp;
  1243. X
  1244. X    pkt = (struct _pkt *)sed_FormatPacket(&s->hisethaddr[0], 0x800);
  1245. X    dp = &pkt->maxsegopt;
  1246. X
  1247. X    pkt->in.length = sizeof(in_Header) + sizeof(tcp_Header) + s->dataSize;
  1248. X
  1249. X    /* tcp header */
  1250. X    pkt->tcp.srcPort = s->myport;
  1251. X    pkt->tcp.dstPort = s->hisport;
  1252. X    pkt->tcp.seqnum = s->seqnum;
  1253. X    pkt->tcp.acknum = s->acknum;
  1254. X    pkt->tcp.window = 1024;
  1255. X    pkt->tcp.flags = s->flags | 0x5000;
  1256. X    pkt->tcp.checksum = 0;
  1257. X    pkt->tcp.urgentPointer = 0;
  1258. X    if ( s->flags & tcp_FlagSYN ) {
  1259. X        pkt->tcp.flags += 0x1000;
  1260. X        pkt->in.length += 4;
  1261. X        pkt->maxsegopt = 0x02040578; /* 1400 bytes */
  1262. X        dp += 4;
  1263. X    }
  1264. X    MoveW(s->data, dp, s->dataSize);
  1265. X
  1266. X    /* internet header */
  1267. X    pkt->in.vht = 0x4500;   /* version 4, hdrlen 5, tos 0 */
  1268. X    pkt->in.identification = tcp_id++;
  1269. X    pkt->in.frag = 0;
  1270. X    pkt->in.ttlProtocol = (250<<8) + 6;
  1271. X    pkt->in.checksum = 0;
  1272. X    pkt->in.source = sin_lclINAddr;
  1273. X    pkt->in.destination = s->hisaddr;
  1274. X    pkt->in.checksum = ~checksum(&pkt->in, sizeof(in_Header));
  1275. X
  1276. X    /* compute tcp checksum */
  1277. X    ph.src = pkt->in.source;
  1278. X    ph.dst = pkt->in.destination;
  1279. X    ph.mbz = 0;
  1280. X    ph.protocol = 6;
  1281. X    ph.length = pkt->in.length - sizeof(in_Header);
  1282. X    ph.checksum = checksum(&pkt->tcp, ph.length);
  1283. X    pkt->tcp.checksum = ~checksum(&ph, sizeof ph);
  1284. X
  1285. X#ifdef DEBUG
  1286. X    if ( tcp_logState & tcp_LOGPACKETS )
  1287. X        tcp_DumpHeader(&pkt->in, &pkt->tcp, "Sending");
  1288. X#endif
  1289. X
  1290. X    sed_Send(pkt->in.length);
  1291. X}
  1292. X
  1293. X/*
  1294. X * Do a one's complement checksum
  1295. X */
  1296. Xchecksum(dp, length)
  1297. X    word *dp;
  1298. X    int length;
  1299. X{
  1300. X    int len;
  1301. X    longword sum;
  1302. X
  1303. X    len = length >> 1;
  1304. X    sum = 0;
  1305. X    while ( len-- > 0 ) sum += *dp++;
  1306. X    if ( length & 1 ) sum += (*dp & 0xFF00);
  1307. X    sum = (sum & 0xFFFF) + ((sum >> 16) & 0xFFFF);
  1308. X    sum = (sum & 0xFFFF) + ((sum >> 16) & 0xFFFF);
  1309. X
  1310. X    return ( sum );
  1311. X}
  1312. X
  1313. X/*
  1314. X * Dump the tcp protocol header of a packet
  1315. X */
  1316. Xtcp_DumpHeader( ip, tp, mesg )
  1317. X    in_Header *ip;
  1318. X    char *mesg;
  1319. X{
  1320. X    register tcp_Header *tp = (tcp_Header *)((byte *)ip + in_GetHdrlenBytes(ip));
  1321. X    static char *flags[] = { "FIN", "SYN", "RST", "PUSH", "ACK", "URG" };
  1322. X    int len;
  1323. X    word f;
  1324. X
  1325. X    len =  ip->length - ((tcp_GetDataOffset(tp) + in_GetHdrlen(ip)) << 2);
  1326. X    printf("TCP: %s packet:\nS: %x; D: %x; SN=%x ACK=%x W=%d DLen=%d\n",
  1327. X           mesg, tp->srcPort, tp->dstPort, tp->seqnum, tp->acknum,
  1328. X           tp->window, len);
  1329. X    printf("DO=%d, C=%x U=%d",
  1330. X           tcp_GetDataOffset(tp), tp->checksum, tp->urgentPointer);
  1331. X    /* output flags */
  1332. X    f = tp->flags;
  1333. X    for ( len = 0; len < 6; len++ )
  1334. X        if ( f & (1 << len) ) printf(" %s", flags[len]);
  1335. X    printf("\n");
  1336. X}
  1337. X
  1338. X/*
  1339. X * Move bytes from hither to yon
  1340. X */
  1341. XMove( src, dest, numbytes )
  1342. X    register byte *src, *dest;
  1343. X    register numbytes;
  1344. X{
  1345. X    if ( numbytes <= 0 ) return;
  1346. X    if ( src < dest ) {
  1347. X        src += numbytes;
  1348. X        dest += numbytes;
  1349. X        do {
  1350. X            *--dest = *--src;
  1351. X        } while ( --numbytes > 0 );
  1352. X    } else
  1353. X        do {
  1354. X             *dest++ = *src++;
  1355. X        } while ( --numbytes > 0 );
  1356. X}
  1357. END-of-tinytcp.c
  1358. echo file: tinytcp.h
  1359. sed 's/^X//' >tinytcp.h << 'END-of-tinytcp.h'
  1360. X/*
  1361. X * tinytcp.h - header file for tinytcp.c
  1362. X *
  1363. X * Copyright (C) 1986, IMAGEN Corporation
  1364. X *  "This code may be duplicated in whole or in part provided that [1] there
  1365. X *   is no commercial gain involved in the duplication, and [2] that this
  1366. X *   copyright notice is preserved on all copies.  Any other duplication
  1367. X *   requires written notice of the author."
  1368. X *
  1369. X * Note: the structures herein must guarantee that the
  1370. X *       code only performs word fetches, since the
  1371. X *       imagenether card doesn't accept byte accesses.
  1372. X */
  1373. X
  1374. X#define TRUE        1
  1375. X#define true        1
  1376. X#define FALSE       0
  1377. X#define false       0
  1378. X#define NULL        0               /* An empty value */
  1379. X#define NIL         0               /* The distinguished empty pointer */
  1380. X
  1381. X/* Useful type definitions */
  1382. Xtypedef int (*procref)();
  1383. Xtypedef short BOOL;                  /* boolean type */
  1384. X
  1385. X/* Canonically-sized data */
  1386. Xtypedef unsigned long longword;     /* 32 bits */
  1387. Xtypedef unsigned short word;        /* 16 bits */
  1388. Xtypedef unsigned char byte;         /*  8 bits */
  1389. Xtypedef byte octet;                 /*  8 bits, for TCP */
  1390. X
  1391. X#ifdef DDT
  1392. Xextern longword MsecClock();
  1393. X#define clock_ValueRough() MsecClock()
  1394. X#else
  1395. Xextern longword clock_MS;
  1396. X#define clock_ValueRough() clock_MS
  1397. X#endif
  1398. X
  1399. X/* protocol address definitions */
  1400. Xtypedef longword in_HwAddress;
  1401. Xtypedef word eth_HwAddress[3];
  1402. X
  1403. X/* The Ethernet header */
  1404. Xtypedef struct {
  1405. X    eth_HwAddress   destination;
  1406. X    eth_HwAddress   source;
  1407. X    word            type;
  1408. X} eth_Header;
  1409. X
  1410. X/* The Internet Header: */
  1411. Xtypedef struct {
  1412. X    word            vht;    /* version, hdrlen, tos */
  1413. X    word            length;
  1414. X    word            identification;
  1415. X    word            frag;
  1416. X    word            ttlProtocol;
  1417. X    word            checksum;
  1418. X    in_HwAddress    source;
  1419. X    in_HwAddress    destination;
  1420. X} in_Header;
  1421. X#define in_GetVersion(ip) (((ip)->vht >> 12) & 0xf)
  1422. X#define in_GetHdrlen(ip)  (((ip)->vht >> 8) & 0xf)
  1423. X#define in_GetHdrlenBytes(ip)  (((ip)->vht >> 6) & 0x3c)
  1424. X#define in_GetTos(ip)      ((ip)->vht & 0xff)
  1425. X
  1426. X#define in_GetTTL(ip)      ((ip)->ttlProtocol >> 8)
  1427. X#define in_GetProtocol(ip) ((ip)->ttlProtocol & 0xff)
  1428. X
  1429. X
  1430. Xtypedef struct {
  1431. X    word            srcPort;
  1432. X    word            dstPort;
  1433. X    longword        seqnum;
  1434. X    longword        acknum;
  1435. X    word            flags;
  1436. X    word            window;
  1437. X    word            checksum;
  1438. X    word            urgentPointer;
  1439. X} tcp_Header;
  1440. X
  1441. X
  1442. X#define tcp_FlagFIN     0x0001
  1443. X#define tcp_FlagSYN     0x0002
  1444. X#define tcp_FlagRST     0x0004
  1445. X#define tcp_FlagPUSH    0x0008
  1446. X#define tcp_FlagACK     0x0010
  1447. X#define tcp_FlagURG     0x0020
  1448. X#define tcp_FlagDO      0xF000
  1449. X#define tcp_GetDataOffset(tp) ((tp)->flags >> 12)
  1450. X
  1451. X/* The TCP/UDP Pseudo Header */
  1452. Xtypedef struct {
  1453. X    in_HwAddress    src;
  1454. X    in_HwAddress    dst;
  1455. X    octet           mbz;
  1456. X    octet           protocol;
  1457. X    word            length;
  1458. X    word            checksum;
  1459. X} tcp_PseudoHeader;
  1460. X
  1461. X/*
  1462. X * TCP states, from tcp manual.
  1463. X * Note: close-wait state is bypassed by automatically closing a connection
  1464. X *       when a FIN is received.  This is easy to undo.
  1465. X */
  1466. X#define tcp_StateLISTEN  0      /* listening for connection */
  1467. X#define tcp_StateSYNSENT 1      /* syn sent, active open */
  1468. X#define tcp_StateSYNREC  2      /* syn received, synack+syn sent. */
  1469. X#define tcp_StateESTAB   3      /* established */
  1470. X#define tcp_StateFINWT1  4      /* sent FIN */
  1471. X#define tcp_StateFINWT2  5      /* sent FIN, received FINACK */
  1472. X/*#define tcp_StateCLOSEWT 6    /* received FIN waiting for close */
  1473. X#define tcp_StateCLOSING 6      /* sent FIN, received FIN (waiting for FINACK) */
  1474. X#define tcp_StateLASTACK 7      /* fin received, finack+fin sent */
  1475. X#define tcp_StateTIMEWT  8      /* dally after sending final FINACK */
  1476. X#define tcp_StateCLOSED  9      /* finack received */
  1477. X
  1478. X/*
  1479. X * TCP Socket definition
  1480. X */
  1481. X#define tcp_MaxData 32              /* maximum bytes to buffer on output */
  1482. X
  1483. Xtypedef struct _tcp_socket {
  1484. X    struct _tcp_socket *next;
  1485. X    short           state;          /* connection state */
  1486. X    procref         dataHandler;    /* called with incoming data */
  1487. X    eth_HwAddress   hisethaddr;     /* ethernet address of peer */
  1488. X    in_HwAddress    hisaddr;        /* internet address of peer */
  1489. X    word            myport, hisport;/* tcp ports for this connection */
  1490. X    longword        acknum, seqnum; /* data ack'd and sequence num */
  1491. X    int             timeout;        /* timeout, in milliseconds */
  1492. X    BOOL            unhappy;        /* flag, indicates retransmitting segt's */
  1493. X    word            flags;          /* tcp flags word for last packet sent */
  1494. X    short           dataSize;       /* number of bytes of data to send */
  1495. X    byte            data[tcp_MaxData]; /* data to send */
  1496. X} tcp_Socket;
  1497. X
  1498. Xextern eth_HwAddress sed_lclEthAddr;
  1499. Xextern eth_HwAddress sed_ethBcastAddr;
  1500. Xextern in_HwAddress  sin_lclINAddr;
  1501. X
  1502. X/*
  1503. X * ARP definitions
  1504. X */
  1505. X#define arp_TypeEther  1        /* ARP type of Ethernet address *
  1506. X
  1507. X/* harp op codes */
  1508. X#define ARP_REQUEST 1
  1509. X#define ARP_REPLY   2
  1510. X
  1511. X/*
  1512. X * Arp header
  1513. X */
  1514. Xtypedef struct {
  1515. X    word            hwType;
  1516. X    word            protType;
  1517. X    word            hwProtAddrLen;  /* hw and prot addr len */
  1518. X    word            opcode;
  1519. X    eth_HwAddress   srcEthAddr;
  1520. X    in_HwAddress    srcIPAddr;
  1521. X    eth_HwAddress   dstEthAddr;
  1522. X    in_HwAddress    dstIPAddr;
  1523. X} arp_Header;
  1524. X
  1525. X/*
  1526. X * Ethernet interface:
  1527. X *   sed_WaitPacket(0) => ptr to packet (beyond eth header)
  1528. X *                          or NIL if no packet ready.
  1529. X *   sed_Receive(ptr) - reenables receive on input buffer
  1530. X *   sed_FormatPacket(ðdest, ethtype) => ptr to packet buffer
  1531. X *   sed_Send(packet_length) - send the buffer last formatted.
  1532. X */
  1533. Xbyte *sed_IsPacket(), *sed_FormatPacket();
  1534. END-of-tinytcp.h
  1535. exit
  1536.  
  1537.  
  1538.