home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / system / linux_bo / netboot.zoo / general.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-05-05  |  14.8 KB  |  587 lines

  1. #include "protocol.h"
  2. #include "bootinc.h"
  3.  
  4.  
  5. /* Originally some of this was part of NCSA Telnet.
  6.    Modifications Apr/May 1993 Jamie Honan
  7. */
  8.  
  9. unsigned char   bseed[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
  10.                 ltseed[] = {0x00, 0x00, 0xff, 0x48, 0x00, 0x00};
  11.  
  12. unsigned char   raw[RAW_LENGTH];
  13.  
  14. unsigned char
  15.                 nnmyaddr[DADDLEN],           /* my ethernet hardware
  16.                             * address */
  17.                 broadaddr[DADDLEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},    /* the broadcast address */
  18.  
  19.                 nnipnum[4],               /* my ip number */
  20. #ifdef BROADCAST0
  21.                 broadip[4] = {0, 0, 0, 0},
  22. #else
  23.                 broadip[4] = {0xff, 0xff, 0xff, 0xff},
  24. #endif
  25.                 nnserveraddr[DADDLEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff},    /* server's ethernet
  26.  
  27.                                          * hardware address */
  28.                 nnipserver[4] = {0xff, 0xff, 0xff, 0xff};    /* server's ip number */
  29.  
  30. int
  31.                 nnipident = 1;               /* ident field of outgoing ip
  32.                             * packets */
  33.  
  34. int             debug = 0;
  35.  
  36. struct pseudotcp tcps;                   /* for checksums */
  37. struct pseudotcp utcps;                   /* for checksums */
  38.  
  39. DLAYER          blankd;
  40. IPKT            blankip;
  41.  
  42. UDPKT           udpout;
  43. UDPKT           udp_rxdata;
  44.  
  45. /************************************************************************/
  46. /*  neterrstring
  47. *   returns the string associated with a particular error number
  48. */
  49. typedef struct
  50. {
  51.     int     errno;
  52.     char     *errstring;
  53. } ERRS;
  54.  
  55. static ERRS   errs[] = {
  56.     {   0 ,       "Error unknown"},
  57.     {  100,       "Network jammed, probable break in wire"},
  58.     {  101,       "Could not initialize hardware level network driver"},
  59.     {  102,       "ERROR: The conflicting machine is using the same IP number"},
  60.     {  103,       "RARP request failed, an IP number is required"},
  61.     {  300,       "Bad IP checksum"},
  62.     {  301,       "IP packet not for me"},
  63.     {  302,       "IP packet with options received"},
  64.     {  303,       "IP: unknown higher layer protocol"},
  65.     {  304,       "IP: fragmented packet received, frags not supported"},
  66.     {  400,       "TCP: bad checksum"},
  67.     {  401,       "ACK invalid for TCP syn sent"},
  68.     {  403,       "TCP in unknown state"},
  69.     {  404,       "Invalid port for TCPsend"},
  70.     {  405,       "TCP connection reset by other host"},
  71.     {  406,       "Null port specified for ackandtrans"},
  72.     {  407,       "Packet received for invalid port -- reset sent"},
  73.     {  500,       "No internal TCP ports available"},
  74.     {  501,       "Warning: Event queue filled, probably non-fatal"},
  75.     {  504,       "Local host or gateway not responding"},
  76.     {  505,       "Memory allocation error, cannot open port"},
  77.     {  506,       "Not allowed to connect to broadcast address"},
  78.     {  507,       "Reset received: syn sent, host is refusing connection"},
  79.     {  600,       "ICMP:     Echo reply"},
  80.     {  603,       "ICMP:     Destination unreachable"},
  81.     {  604,       "ICMP:     Source Quench"},
  82.     {  605,       "ICMP:     Redirect, another gateway is more efficient"},
  83.     {  608,       "ICMP:     Echo requested (ping requested)"},
  84.     {  611,       "ICMP:     Time Exceeded on Packet"},
  85.     {  612,       "ICMP:     Parameter problem in IP"},
  86.     {  613,       "ICMP:     Timestamp request"},
  87.     {  614,       "ICMP:     Timestamp reply"},
  88.     {  615,       "ICMP:     Information request"},
  89.     {  616,       "ICMP:     Information reply"},
  90.     {  630,       "ICMP:       Network Unreachable"},
  91.     {  631,       "ICMP:       Host Unreachable"},
  92.     {  632,       "ICMP:       Protocol Unreachable"},
  93.     {  633,       "ICMP:       Port Unreachable"},
  94.     {  634,       "ICMP:       Frgamentation needed and DF set"},
  95.     {  635,       "ICMP:       Source route Failed"},
  96.     {  636,       "ICMP:       Destination network unknown"},
  97.     {  637,       "ICMP:       Destination host unknown"},
  98.     {  638,       "ICMP:       Source host isolated"},
  99.     {  639,       "ICMP:       Dest network administratively prohibited"},
  100.     {  640,       "ICMP:       Dest host administratively prohibited"},
  101.     {  641,       "ICMP:       Network unreachable for type of service"},
  102.     {  642,       "ICMP:       Host unreachable for type of service"},
  103.     {  699,       "ICMP: Checksum error"},
  104.     {  700,       "Bad UDP checksum"},
  105.     {  800,       "Domain: Name request to server failed"},
  106.     {  801,       "Domain: Using default domain"},
  107.     {  802,       "Domain: name does not exist"},
  108.     {  803,       "Domain: UDP name server did not resolve the name"},
  109.     {  804,       "Domain: name server failed, unknown reason"},
  110.     {  805,       "Host machine not in configuration file"},
  111.     {  806,       "Missing IP number, requires domain lookup"},
  112.     {  900,       "Session: Cannot find or open configuration file"},
  113.     {  901,       "Session: Cannot allocate memory for processing"},
  114.     {  902,       "Session: Invalid keyword in configuration file"},
  115.     {  903,       "Session: Element too long (>200), maybe missing quote"},
  116.     {  904,       "Session: Probable missing quote marks, a field must be on one line"},
  117.     {  905,       "Session: 'name' field required before other machine entries"},
  118.     {  906,       "Session: Syntax error, invalid IP number"},
  119.     {  907,       "Session: Syntax error, Subnet mask invalid"},
  120.     {  908,       "Session: Syntax error, IP address for this PC is invalid"},
  121.     { 1000,    "Bootp: No Response from bootpd server"},
  122.     { 1001,    "Bootp: Invalid bootp packet response from server"},
  123.     { 1020,    "Tftp: No  response"},
  124.     { 1021,    "Tftp: host refused"},
  125.     { 1022,    "Tftp: protocol error"},
  126.     { 2000,    "Terminated network boot process"},
  127.     { 3000,    "Image: Not executable"},
  128.     { 3001,       "Image: header length incorrect"},
  129.     { 3002,    "Image: attempt to place data incorrectly"},
  130.     { 3003,       "Image: image record length incorrect"},
  131.     { 3004,       "Image: too much data"},
  132.     { 3005,       "Image: address overflow"},
  133.     { 3011,    "Image: parity error during extended memory transfer"},
  134.     { 3012,    "Image: interrupt error during extended memory transfer"},
  135.     { 3013,    "Image: line 20 gating error during extended memory transfer"},
  136.     {   -1,    "" }
  137.     };
  138.  
  139. static char     errspace[80];               /* room for user-defined
  140.                             * errors */
  141.  
  142. char  *
  143. neterrstring(int errno)
  144. {
  145.     int             i;
  146.     char            s[10];
  147.  
  148.     if (errno < 0)
  149.         return (errspace);
  150.     for (i = 0; errs[i].errno >= 0; i++)
  151.     {
  152.         if (errs[i].errno == errno)
  153.             return (errs[i].errstring);    /* pointer to error message  */
  154.     }
  155.     return (errs[0].errstring);    /* error unknown */
  156. }
  157.  
  158. void 
  159. netposterr(num)
  160. int             num;
  161. {
  162.     n_printf("%d  %s\n", num, neterrstring(num));
  163. }
  164.  
  165. void 
  166. n_puts(char *s)
  167. {
  168.     while (*s)
  169.     {
  170.         if (*s == '\n')
  171.             n_putchar('\r');
  172.         n_putchar(*s++);
  173.     }
  174. }
  175.  
  176. void n_putscrlf(char *s)
  177. {
  178.     n_puts(s);
  179.     n_puts("\n");
  180. }
  181.  
  182. void 
  183. etherinit(void)
  184. {
  185.     memcpy(broadaddr, bseed, DADDLEN);
  186.     memcpy(blankd.dest, broadaddr, DADDLEN);    /* some are broadcast */
  187.     memcpy(blankd.me, nnmyaddr, DADDLEN);    /* always from me */
  188.     blankd.type = EIP;    /* mostly IP packets */
  189. }
  190.  
  191. /*************************************************************************/
  192. /*
  193.  *    ipinit ()
  194.  *
  195.  *    initialize on packet to use for internet transmission -- most packets will
  196.  * be tcp/udp, so they will be initialized at a different layer, but some
  197.  * require a generic ip packet.
  198.  *
  199.  *    Also takes a guess at setting a netmask if it hasn't happened by now.
  200.  *
  201. */
  202. void 
  203. ipinit(void)
  204. {
  205.     memcpy(&blankip.d, &blankd, sizeof(DLAYER));
  206.     blankip.i.versionandhdrlen = 0x45;    /* smallest header, version 4 */
  207.     blankip.i.service = 0;    /* normal service */
  208.     blankip.i.tlen = 576;    /* no data yet, maximum size */
  209.     blankip.i.ident = 0;
  210.     blankip.i.frags = 0;    /* not a fragment of a packet */
  211.     blankip.i.ttl = 100;    /* 100 seconds should be enough */
  212.     blankip.i.protocol = PROTUDP;    /* default to UDP */
  213.     blankip.i.check = 0;    /* disable checksums for now */
  214.     memcpy(blankip.i.ipsource, nnipnum, 4);    /* my return address */
  215.     memcpy(blankip.i.ipdest, broadip, 4);    /* to ? */
  216. }
  217.  
  218. /**************************************************************************/
  219. /*
  220.  *    udpinit ()
  221.  *
  222.  *    Setup ulist for receive of udp packets
  223.  *
  224. */
  225. void 
  226. udpinit(void)
  227. {
  228.     memcpy(&udpout, &blankip, sizeof(DLAYER) + sizeof(IPLAYER));
  229.     udpout.i.protocol = PROTUDP;    /* UDP type */
  230.     utcps.z = 0;
  231.     utcps.proto = PROTUDP;
  232.     memcpy(utcps.source, nnipnum, 4);
  233. }
  234.  
  235. void 
  236. udp_reinit(void)
  237. {
  238.     /* The boot protocol has given us more specific information */
  239.  
  240.     memcpy(blankd.dest, nnserveraddr, DADDLEN);
  241.     memcpy(udpout.d.dest, nnserveraddr, DADDLEN);
  242.     memcpy(blankd.me, nnmyaddr, DADDLEN);
  243.     memcpy(udpout.d.me, nnmyaddr, DADDLEN);
  244.     memcpy(blankip.i.ipsource, nnipnum, 4);
  245.     memcpy(udpout.i.ipsource, nnipnum, 4);
  246.     memcpy(utcps.source, nnipnum, 4);
  247. }
  248.  
  249. /**************************************************************************/
  250. /*
  251. *    netinit ()
  252. *
  253. *    Handles all the initialization to bring up the network connection.
  254. *    Assumes that the configuration file has already been read up.
  255. * (called from Snetinit () )
  256. *
  257. *    Returns 0 on successful initialization.
  258. *
  259. */
  260. int 
  261. netinit(void)
  262. {
  263.     int             ret;
  264.  
  265. /*
  266. *   Initializes all buffers and hardware for data link layer.
  267. *   Machine/board dependent.
  268. */
  269.     ret = dlayerinit();
  270.     if (ret)
  271.     {
  272.         switch (ret)
  273.         {
  274.         case -10:
  275.             n_printf("Need a function for opening board!!\n");
  276.             break;
  277.  
  278.         default:
  279.             n_printf("Board initialization failed!.  Error code=%d\n", ret);
  280.             break;
  281.         }    /* end switch */
  282.         netposterr(101);
  283.         return (ret);
  284.     }
  285.     n_printf("Ethernet address %x:%x:%x:%x:%x:%x\n",
  286.         nnmyaddr[0], nnmyaddr[1], nnmyaddr[2],
  287.            nnmyaddr[3], nnmyaddr[4], nnmyaddr[5]);
  288.     return (0);
  289. }
  290.  
  291.  
  292. int 
  293. init(char *ifname)
  294. {
  295.     n_printf("Network boot. Press x to terminate.\n");
  296.     netconfig(ifname);
  297.  
  298.     if (netinit() != 0)
  299.     {    /* starts up hardware */
  300.         return (0);    /* netinit() failed */
  301.     }
  302.  
  303.     etherinit();    /* dlayer packets */
  304.     ipinit();    /* ip packets */
  305.     udpinit();    /* udp packets */
  306.     return 1;
  307. }
  308.  
  309. /*
  310. char hexbar[] = "0123456789ABCDEF";
  311.  
  312. void int2hex(char *p, int i)
  313. {
  314.     *p++ = hexbar[(i>>4) & 0xf];
  315.     *p = hexbar[i & 0xf];
  316. }
  317.  
  318.  
  319. void initbootname(char *name, unsigned char *inetad)
  320. {
  321.     int2hex(&name[0], inetad[0]);
  322.     int2hex(&name[2], inetad[1]);
  323.     int2hex(&name[4], inetad[2]);
  324.     int2hex(&name[6], inetad[3]);
  325.     name[8] = '.';
  326.     name[9] = 'i';
  327.     name[10] = '8';
  328.     name[11] = '6';
  329.     name[12] = '\0';
  330. }
  331.  
  332. */
  333. static long     next = 1;
  334.  
  335. void
  336. startrand(unsigned int seed)
  337. {
  338.     next = seed;
  339. }
  340.  
  341. int
  342. random(int mask)                   /* not really - I think %
  343.                             * limit stops it */
  344. {
  345.     next = n_lmul(next, 1103515245) + 12345;
  346.     return ((short) ((next >> 16) & mask));
  347. }
  348.  
  349. long 
  350. n_ticks(void)
  351. {
  352.     static long     lastticks = 0;
  353.     static long     baseticks = 0;
  354.     long            nowt;
  355.  
  356.     nowt = *(long far *) (MK_FP(0x40, 0x6c));
  357.  
  358.     if (nowt < lastticks)
  359.     {
  360.         /* timer wrap around */
  361.         baseticks += ((182L *  24 * 36000) / 10);
  362.          /*  I think the bios actually uses 0x1800b0 */
  363.     }
  364.     lastticks = nowt;
  365.     return (nowt + baseticks);
  366. }
  367.  
  368. long 
  369. n_secs(void)
  370. {
  371.     /* expects (long divisor) (long dividend) returns dx:ax */
  372.     return n_ldiv(n_lmul(n_ticks(), 10), 182L);
  373. }
  374.  
  375. /* This n_printf only does %x %d %s %c and %lx %ld AND %ls - special for far string
  376.    Also %p near pointer and %lp far pointer
  377.    Does \r append on \n
  378.    Only good for 8086 type machines in small model
  379.    Has special allowance in case DS != SS
  380. */
  381.  
  382. #define MAX_OUTLEN 15
  383.  
  384. static
  385. pnum(long i, int base)
  386. {
  387.     static char     obuf[MAX_OUTLEN];
  388.     char           *cp;
  389.     int             c;
  390.     int             neg;
  391.     int        v;
  392.     unsigned long    id;
  393.  
  394.     /* CARE This algorithm does not null term the string ! */
  395.  
  396.     cp = &obuf[MAX_OUTLEN];    /* looks wrong, I know */
  397.  
  398.     neg = 0;
  399.     if (i < 0)
  400.     {
  401.         if (base == 10)
  402.             i = -i;
  403.         else
  404.             i = ~i;
  405.         neg = 1;
  406.     }
  407.  
  408.     for (c = 1; c < MAX_OUTLEN; c++)
  409.     {
  410.         id = n_ldiv(i, base);
  411.         v = (int)((unsigned long)i - n_lmul(id, base));
  412.         if (neg && base != 10)
  413.             v = (~v) & (base - 1);
  414.         i = id;
  415.         *--cp = "0123456789ABCDEF"[v];
  416.         if (i == 0)
  417.             break;
  418.     }
  419.     if (neg && base == 10)
  420.         n_putchar('-');
  421.     while (c > 0)
  422.     {
  423.         n_putchar(*cp++);
  424.         c--;
  425.     }
  426. }
  427.  
  428. #define STATE_NONE    0
  429. #define STATE_PERCENT    1
  430.  
  431. void 
  432. n_printf(char *format, ...)
  433. {
  434.     int far        *ap;
  435.     char           *str;
  436.     char far       *lstr;
  437.     char            c;
  438.     int             islong;
  439.     int             state;
  440.  
  441.     ap = MK_FP(segss(), (&format));
  442.     ap++;
  443.  
  444.     state = STATE_NONE;
  445.  
  446.     for (; *format != '\0'; format++)
  447.     {
  448.         c = *format;
  449.         switch (state)
  450.         {
  451.         case STATE_NONE:
  452.             switch (c)
  453.             {
  454.             case '%':
  455.                 state = STATE_PERCENT;
  456.                 islong = 0;
  457.                 break;
  458.             case '\n':
  459.                 n_putchar('\r');
  460.                 /* FALL THROUGH */
  461.             default:
  462.                 n_putchar(*format);
  463.                 break;
  464.             }
  465.             break;
  466.  
  467.         case STATE_PERCENT:
  468.             switch (c)
  469.             {
  470.             case 'l':
  471.                 islong = 1;
  472.                 continue;
  473.             case 'd':
  474.             case 'u':
  475.             case 'x':
  476.             case 'o':
  477.                 pnum(islong ? *(long far *) ap :
  478.                      (long) *(unsigned int far *) ap,
  479.                      c == 'o' ? 8 : (c == 'x' ? 16 : 10));
  480.                 if (islong)
  481.                     ap++;
  482.                 break;
  483.             case 'p':
  484.                 if (islong)
  485.                 {
  486.                     pnum((long) *(unsigned int far *) (ap + 1), 16);
  487.                     n_putchar(':');
  488.                 }
  489.                 pnum((long) *(unsigned int far *) ap, 16);
  490.                 if (islong)
  491.                     ap++;
  492.                 break;
  493.             case 's':
  494.                 if (islong)
  495.                 {
  496.                     /* special far string extension */
  497.                     for (lstr = *(char far * far *)ap; *lstr; lstr++)
  498.                         n_putchar(*lstr);
  499.                     if (islong)
  500.                         ap++;
  501.                 }
  502.                 else
  503.                 {
  504.                     /* string should not be on stack if SS!=DS */
  505.                     for (str = (char *) *ap; *str; str++)
  506.                         n_putchar(*str);
  507.                 }
  508.                 break;
  509.             case 'c':
  510.                 n_putchar(c);
  511.                 break;
  512.             default:
  513.                 n_putchar(c);
  514.                 break;
  515.             }
  516.             state = STATE_NONE;
  517.             ap++;
  518.             break;
  519.         }
  520.     }
  521. }
  522.  
  523. static char     name[128];
  524.  
  525. int
  526. do_boot_process(char *ifname)
  527. {
  528.     int result;
  529.     
  530.     n_printf("bootp protocol.\n");
  531.     name[0] = '\0';
  532.     /* initbootname(name, &nnmyaddr[1]); */
  533.     startrand(nnmyaddr[4] ^ (short)n_ticks());
  534.     if (monitor_check() > 1)
  535.         return 1;
  536.     init(ifname);
  537.     if (debug)
  538.     {        
  539.         n_printf("\nds %x cs %x ss %x, sp %x, start_of_data %x, end_of_data %x, end_of_bss %x\n",
  540.                 segds(), segcs(), segss(), &result, &start_of_data, &end_of_data,&end_of_bss);
  541.         
  542.             n_printf("You have %lx mem\n",  n_lmul(n_mamount(), 1024));
  543.         }
  544.     result = bootp(name, sizeof(name));
  545.     n_printf("\r");
  546.     if (result)
  547.     {
  548.         netposterr(result);
  549.         dlayershut();
  550.         return 1;
  551.     }
  552.     n_printf("Local ip %d.%d.%d.%d. Server: ip %d.%d.%d.%d, Ethernet %x:%x:%x:%x:%x:%x\n",
  553.         nnipnum[0], nnipnum[1], nnipnum[2], nnipnum[3],
  554.         nnipserver[0], nnipserver[1], nnipserver[2], nnipserver[3],
  555.         nnserveraddr[0], nnserveraddr[1], nnserveraddr[2], nnserveraddr[3], nnserveraddr[4], nnserveraddr[5]);
  556.     udp_reinit();
  557.     n_printf("tftp get %s.\n", name);
  558.     result = tftp_get(name);
  559.     if (result)
  560.     {
  561.         netposterr(result);
  562.         dlayershut();
  563.         return 1;
  564.     }
  565.     dlayershut();
  566.     warp_speed_Mr_spock();    /* and they never saw him again */
  567.     return 0;
  568. }
  569.  
  570. int
  571. monitor_check()
  572. {
  573.     int c;
  574.  
  575.     while (n_kbhit())
  576.     {
  577.         c = n_getch();
  578.         if (c == 0x3 || c == 'x' || c == 'X')
  579.             return 2;
  580.         if (c == 'd' || c == 'D')
  581.             debug = debug ? 0 : 1;
  582.     }
  583.     return 0;
  584. }
  585.  
  586.  
  587.