PCBOOTP.C
上传用户:sunrenlu
上传日期:2022-06-13
资源大小:1419k
文件大小:16k
源码类别:

操作系统开发

开发平台:

DOS

  1. /*
  2.  *
  3.  *   BOOTP - Boot Protocol (RFC 854)
  4.  *
  5.  *   These extensions get called if _bootphost is set to an IP address or
  6.  *   to 0xffffffff.
  7.  *
  8.  *   Version
  9.  *
  10.  *   0.5 : Oct 29, 2001 : J. Toman - fixed DHCP packet size and moved DHCP
  11.  *                                   lifetime variable so it doesn't clobber
  12.  *                                   results from the server
  13.  *   0.4 : May 11, 1999 : S. Lawson - added DHCP
  14.  *   0.3 : Feb  1, 1992 : J. Dent - patched up various things
  15.  *   0.2 : May 22, 1991 : E.J. Sutcliffe - added RFC_1048 vendor fields
  16.  *   0.1 : May  9, 1991 : E. Engelke - made part of the library
  17.  *   0.0 : May  3, 1991 : E. Engelke - original program as an application
  18.  *
  19.  */
  20. #include <copyright.h>
  21. #include <stdio.h>
  22. #include <wattcp.h>
  23. #include <mem.h>
  24. #include <bootp.h>
  25. #include <conio.h>
  26. #include <string.h> // S. Lawson
  27. /* global variables */
  28. longword _bootphost = 0xffffffffL;
  29. longword _dhcphost = 0xffffffffL;       // S. Lawson
  30. word _bootptimeout = 30;
  31. word _bootpon = 0;
  32. static longword dhcp_life;         // S. Lawson
  33. static char dhcp_seen, dhcp_bind; // S. Lawson
  34. static char got_ns, got_gw, got_cy; // S. Lawson
  35. static udp_Socket bsock; // S. Lawson
  36. // S. Lawson - we now use these
  37. char *getdomainname( char *name, int length );
  38. char *setdomainname( char *string );
  39. char *sethostname( char *name );
  40. #define VM_RFC1048 0x63825363L /* I think this is correct */
  41. /*
  42.  * _dobootpc - Checks global variables _bootptimeout, _bootphost
  43.  *             if no host specified, the broadcast address
  44.  *             returns 0 on success and sets ip address
  45.  */
  46. int _dobootp( void )
  47. {
  48. // S. Lawson - moved    udp_Socket bsock;
  49.     extern char defaultdomain[]; // S. Lawson - in pcconfig.c
  50.     longword sendtimeout, bootptimeout;
  51.     word magictimeout;
  52.     word len, templen;
  53.     struct bootp sendbootp;     /* outgoing data */
  54.     struct bootp _bootp;        /* incoming data */
  55.     int status;
  56.     longword xid;
  57.     unsigned char *p ,*t;       // R. Whitby - uncomment *t
  58.     longword *l;        // S. Lawson
  59. /*
  60.     const char dhcp_opt[]={DHCP_VN_TYPE,1,DHCP_TY_REQ,DHCP_VN_OPTS,6,1,
  61.                            3,6,42,12,15,0}; */  /* S. Lawson - keep even! */
  62. /*    const char dhcp_opt[]={DHCP_VN_OPTS,6,1,3,6,42,12,15,0}; */ /* Shaun Jackman 2000/3/10 */
  63.     const char dhcp_opt[]={DHCP_VN_OPTS,6,1,3,6,42,12,15}; /* Michael Temari 2002/1/17, keep even */
  64. //    if ( _pktdevclass == PD_SLIP ) return( -1 );
  65.     /* We must get Waterloo TCP to use IP address 0 for sending */
  66.     xid = set_timeout(1);   /* random... well, actually time based */
  67.     my_ip_addr = 0;
  68.     dhcp_seen=dhcp_bind=0;       // S. Lawson
  69.     got_ns=got_gw=got_cy=0; // S. Lawson
  70.     dhcp_life = 0L;                             // JCT
  71.     if (!udp_open( &bsock, IPPORT_BOOTPC, _bootphost, IPPORT_BOOTPS, NULL )) {
  72. outs("nrUnable to resolve bootp servernr");
  73. return( -1 );
  74.     }
  75.     bootptimeout = set_timeout( _bootptimeout );
  76.     // magictimeout = (xid & 7) + 7;  /* between 7 and 14 seconds */
  77.     magictimeout = ((word)(xid & 7)) + 7;/* JCT forced to word, 7-14 s */
  78.     memset( &sendbootp, 0, sizeof( struct bootp ));
  79.     sendbootp.bp_op = BOOTREQUEST;
  80.     sendbootp.bp_htype = _pktdevclass;
  81.     /* Copy into position the Magic Number used by Bootp */
  82.     /* avoid static storage and pushf/call assembler instructions */
  83.     *(longword *)(&sendbootp.bp_vend) = intel(VM_RFC1048);
  84.     // S. Lawson - append DHCPDISCOVER to vendor field.  I'm expecting that
  85.     // a BOOTP server configured with this machines MAC address will simply
  86.     // ignore it and answer anyway, possibly a bad assumption?
  87.     p=&sendbootp.bp_vend[4];
  88.     *p++=DHCP_VN_TYPE;
  89.     *p++=1;
  90.     *p++=DHCP_TY_DSC;
  91.     *p=255;
  92.     if (_pktdevclass == PD_ETHER) sendbootp.bp_hlen = 6;
  93.     sendbootp.bp_xid = xid;
  94.     sendbootp.bp_secs = intel16( 1 );
  95. //    movmem( &_eth_addr, &sendbootp.bp_chaddr, sizeof(eth_address));
  96. // 94.11.19 ??
  97.     movmem( &_eth_addr, sendbootp.bp_chaddr, sizeof(eth_address));
  98.     while ( 1 ) {
  99. sock_fastwrite( (sock_type*)&bsock, (byte *)&sendbootp, sizeof( struct bootp ));
  100. sendbootp.bp_secs = intel16( intel16( sendbootp.bp_secs ) + magictimeout );      /* for next time */
  101.         sendtimeout = set_timeout( magictimeout += ((word)(xid >> 5)) & 7 );  // JCT
  102. while ( !chk_timeout( sendtimeout )) {
  103.     if (chk_timeout( bootptimeout))
  104. goto give_up;
  105.     kbhit();
  106.     sock_tick( (sock_type*)&bsock, &status );
  107.     status = status;    /* get rid of warning */
  108.     if ((len = sock_dataready( (sock_type*)&bsock)) != 0 ) {
  109. /* got a response, lets consider it */
  110. templen = sock_fastread( (sock_type*)&bsock, (byte *)&_bootp, sizeof( struct bootp ));
  111. // S. Lawson - vendor area increased (bootp: 64, dhcp: 312)
  112. // if ( templen < sizeof( struct bootp )) {
  113. /*
  114.  *              if ( templen < sizeof( struct bootp ) - (312-64) ) {
  115.  * JCT that's not right size either
  116.  */
  117.                 if ( templen < sizeof( struct bootp ) - 312 ) {
  118.                    /* too small, not a bootp packet */
  119.                     memset( &_bootp, 0, sizeof( struct bootp ));
  120.     continue;
  121. }
  122. /* we must see if this is for us */
  123. if (_bootp.bp_xid != sendbootp.bp_xid) {
  124.     memset( &_bootp, 0, sizeof( struct bootp ));
  125.     continue;
  126. }
  127. /* we must have found it */
  128. my_ip_addr = intel( _bootp.bp_yiaddr );
  129. // S. Lawson - just in case
  130. if (!my_ip_addr) {
  131.   outs("Rejecting zero addressrn");
  132.   memset( &_bootp, 0, sizeof( struct bootp ));
  133.   continue;
  134. }
  135. dhcp_seen = 0;          // S. Lawson
  136.                 /* dhcp_life=0L;  wrong place */  // S. Lawson
  137. if ( intel( *(longword*)(&_bootp.bp_vend)) == VM_RFC1048 ) {
  138.     /*RFC1048 complient BOOTP vendor field */
  139.     /* Based heavily on NCSA Telnet BOOTP */
  140.     p = &_bootp.bp_vend[4]; /* Point just after vendor field */
  141. // S. Lawson - vendor area increased for dhcp (bootp: 64, dhcp: 312)
  142. //     while ((*p!=255) && (p <= &_bootp.bp_vend[63])) {
  143.     while ((*p!=255) && (p <= &_bootp.bp_vend[311])) {
  144. switch(*p) {
  145.   case 0: /* Nop Pad character */
  146.  p++;
  147.  break;
  148.   case 1: /* Subnet Mask */
  149.  sin_mask = intel( *(longword *)( &p[2] ));
  150.  /* and fall through */
  151.   case 2: /* Time offset */
  152.  p += *(p+1) + 2;
  153.  break;
  154.   case 3: /* gateways */
  155.   /* only add first */
  156.   if (!got_gw)   // S. Lawson
  157.      _arp_add_gateway( NULL,
  158. intel( *(longword*)(&p[2])));
  159.   p +=*(p+1)+2;
  160.   got_gw=1; // S. Lawson
  161.   break;
  162.   /* and fall through */
  163.   case 4: /*time servers */
  164.   /* fall through */
  165.   case 5: /* IEN=116 name server */
  166.  p +=*(p+1)+2;
  167.  break;
  168.   case 6: /* Domain Name Servers (BIND) */
  169. if (!got_ns)  // S. Lawson
  170.                                 //for ( len = 0; len < *(p+1) ; len += 4 )
  171.                                 // JCT make promotion to int explicit
  172.                                 for ( len = 0 ; len < (int)*(p+1) ; len += 4 )
  173.     _add_server( &_last_nameserver,
  174. MAX_NAMESERVERS, def_nameservers,
  175.     intel( *(longword*)(&p[2+len])));
  176. got_ns=1; // S. Lawson
  177. /* and fall through */
  178.   case 7: /* log server */
  179.  p += *(p+1)+2;
  180.  break;
  181.   case 8: /* cookie server */
  182.  if (!got_cy)  // S. Lawson
  183.                                    // for ( len = 0; len < *(p+1) ; len += 4 )
  184.                                    // JCT make promotion to int explicit
  185.                                    for ( len = 0 ;  len < (int)*(p+1); len += 4 )
  186.      _add_server( &_last_cookie, MAX_COOKIES,
  187. _cookie, intel( *(longword*)(&p[2+len])));
  188.   /* and fall through */
  189.   p +=*(p+1)+2;
  190.   got_cy=1; // S. Lawson
  191.   break;
  192.   case 9: /* lpr server */
  193.   case 10: /* impress server */
  194.   case 11: /* rlp server */
  195.    p +=*(p+1)+2;
  196.    break;
  197. #ifdef NOTUSED // R. Whitby - handle bootp/dhcp setting of domain name too
  198.   case 12: /* Client Hostname */
  199.   movmem( &p[2] , _hostname, MAX_STRING );
  200. /* bootpfix - 94.09.30 mdurkin@tsoft.net */
  201.        /* hostname field is *not* null terminated; need to use
  202.     length byte.  Extra bytes used to be tacked on the
  203.     end, usually just a single 0xFF char (the end tag).
  204.     Technically should also probably make the
  205.     _hostname buffer 256 chars long so we'll never
  206.     truncate the name arbitrarily... see CMU bootpd. */
  207.   if( *(p+1) < MAX_STRING ) {
  208.       _hostname[ *(p+1) ] = '';
  209.   } else _hostname[ MAX_STRING - 1 ] = '';
  210.   p += *(p+1)+2;
  211.   break;
  212. #else
  213.   case 12: /* Client Hostname */
  214.   len = *(++p);
  215.   movmem(p+1, p, len); *(p+len) = 0;
  216.   if ((t = strchr((char *)p, '.')) != 0) {
  217.      *t++ = 0;
  218.      if (!getdomainname(NULL, 0)) {
  219. strncpy(defaultdomain, (char *)t, MAX_STRING);
  220. defaultdomain[MAX_STRING-1] = 0;
  221. setdomainname(defaultdomain);
  222.      }
  223.   }
  224.   strncpy(_hostname, (char *)p, MAX_STRING);
  225.   _hostname[MAX_STRING-1] = 0;
  226.   sethostname(_hostname);
  227.   p += len+1;
  228.   break;
  229.   case 15: /* Client Domain */
  230.   len = *(++p);
  231.   if (!getdomainname(NULL, 0)) {
  232.      movmem(p+1, p, len); *(p+len) = 0;
  233.      strncpy(defaultdomain, (char *)p, MAX_STRING);
  234.      defaultdomain[MAX_STRING-1] = 0;
  235.      setdomainname(defaultdomain);
  236.   }
  237.   p += len+1;
  238.   break;
  239. #endif
  240.   // S. Lawson - handle DHCP type
  241.   case DHCP_VN_TYPE:
  242.   dhcp_seen=1;
  243.   if (!dhcp_bind) {
  244.      if (*(p+2)!=DHCP_TY_OFR) my_ip_addr=0L;
  245.   } else {
  246.      if (*(p+2)!=DHCP_TY_ACK) my_ip_addr=0L;
  247.   }
  248.   p += *(p+1)+2;
  249.   break;
  250.   // S. Lawson - handle server id
  251.   case DHCP_VN_SRVRID:
  252.   _dhcphost=intel(*(longword*)(&p[2]));
  253.   p += *(p+1)+2;
  254.   break;
  255.   // S. Lawson - handle lease expiration time
  256.   case DHCP_VN_T2TIME:
  257.   dhcp_life=intel(*(longword*)(&p[2]));
  258.   p += *(p+1)+2;
  259.   break;
  260.   case 255:
  261.    break;
  262.   default:
  263.    p +=*(p+1)+2;
  264.    break;
  265. } /* end of switch */
  266.      } /* end of while */
  267. }/* end of RFC_1048 if */
  268. if (dhcp_seen && my_ip_addr==0L) continue;  // S. Lawson
  269. if (!dhcp_seen || dhcp_bind)                // S. Lawson
  270.    goto give_up;
  271. // S. Lawson - append DHCPREQUEST and server/offered IP
  272. // addresses to vendor field.  We should get get a DHCPACK
  273. // in response
  274. dhcp_bind=1;
  275. p=&sendbootp.bp_vend[4];
  276. *p++=DHCP_VN_TYPE;
  277. *p++=1;
  278. *p++=DHCP_TY_REQ;
  279. movmem(dhcp_opt,p,sizeof(dhcp_opt));
  280. p+=sizeof(dhcp_opt);
  281. *p++=DHCP_VN_REQIP;
  282. *p++=4;
  283. l=(longword *) p, *l++=intel(my_ip_addr), p=(char *) l;
  284. *p++=DHCP_VN_SRVRID;
  285. *p++=4;
  286. l=(longword *) p, *l++=intel(_dhcphost), p=(char *) l;
  287. *p=255;
  288. my_ip_addr=0L;
  289. break;
  290.     }
  291. }
  292.     }
  293. give_up:
  294.     sock_close( (sock_type *)&bsock );
  295.     return (my_ip_addr == 0 );  /* return 0 on success */
  296. sock_err:
  297.     /* major network error if UDP fails */
  298.     sock_close( (sock_type *)&bsock );
  299.     return( -1 );
  300. }
  301. // S. Lawson - countdown the DHCP lease, renew or expire it as needed (mostly
  302. //             copied from above and trimmed down alot)
  303. int dhcp_expired(void) {
  304.    static char nested=false;
  305.    static char expired=false;
  306.    static char sockopen=false;
  307.    static longword timeout;
  308.    static longword xid=0;
  309.    static longword seconds=0, renew=0;
  310.    longword ltime;
  311.    word len;
  312.    char acknak; // -1 NAK, 0 unseen, 1 ACK
  313.    struct bootp _bootp;
  314.    unsigned char *p;
  315.    longword *l;
  316.    // once expired, stop talking
  317.    if (expired) return true;
  318.    // skip if nested, not dhcp, or the lease is permanent
  319.    if (nested || !dhcp_bind || dhcp_life==0xFFFFFFFFL) return false;
  320.    nested=true; // avoid tcp_tick() recursion
  321.    // on first pass, init the renewal time and start the timer
  322.    if (seconds==0) {
  323.       renew=dhcp_life>>1; // renew at 1/2 lifetime
  324.       if ((seconds=renew)>3600) seconds=3600;
  325.       timeout=set_timeout((int) seconds);
  326.       nested=false;
  327.       return false;
  328.    }
  329.    // if the bootp socket is open, check for a response
  330.    if (sockopen && (len = sock_dataready( (sock_type*)&bsock)) != 0 ) {
  331.      memset( &_bootp, 0, sizeof( struct bootp ));
  332.      len = sock_fastread( (sock_type*)&bsock, (byte *)&_bootp, sizeof( struct bootp ));
  333.      // (312-64) gives size of original bootp packet - struct bigger for dhcp
  334.      // if ( len >= sizeof( struct bootp ) - (312-64) &&
  335.      // JCT this is wrong size, fixed as
  336.      if ( len >= sizeof( struct bootp) - 312 &&
  337.   _bootp.bp_xid == xid &&
  338.   my_ip_addr == intel( _bootp.bp_yiaddr ) &&
  339.   intel( *(longword*)(&_bootp.bp_vend)) == VM_RFC1048 ) {
  340.        acknak=0;
  341.        ltime=0;
  342.        p=&_bootp.bp_vend[4];
  343.        while (*p!=255 && p<=&_bootp.bp_vend[311]) {
  344.  switch(*p) {
  345.    case 0:  /* Nop Pad character */
  346.      p++;
  347.      break;
  348.    case DHCP_VN_TYPE:   /* DHCP type */
  349.      if (*(p+2)==DHCP_TY_ACK) acknak=1;
  350.      if (*(p+2)==DHCP_TY_NAK) acknak=-1;
  351.      p += *(p+1)+2;
  352.      break;
  353.    case DHCP_VN_T2TIME: /* expiration time */
  354.      ltime=intel(*(longword*)(&p[2]));
  355.      p += *(p+1)+2;
  356.      break;
  357.    default:
  358.      p +=*(p+1)+2;
  359.      break;
  360.  } /* end of switch */
  361.        } /* end of while */
  362.        if (acknak==(char)-1) {                        // NAK!
  363.  dhcp_life=renew=seconds=0; //   fall through and expire
  364.        } else if (acknak==1 && ltime) { // ACK!
  365.  sock_close((sock_type*)&bsock);
  366.  sockopen=false;
  367.  dhcp_life=ltime;
  368.  renew=dhcp_life>>1; //   renew at 1/2 lifetime
  369.  if ((seconds=renew)>3600) seconds=3600;
  370.          timeout=set_timeout((int)seconds);
  371.  nested=false;
  372.  return false;
  373.        }
  374.      }
  375.    }
  376.    // count down the timeout till it expires
  377.    if (!chk_timeout(timeout)) {
  378.       nested=false;
  379.       return false;
  380.    }
  381.    // keep counting every hour (or less) till renewal time
  382.    renew-=seconds;
  383.    dhcp_life-=seconds;
  384.    if (renew>0) {
  385.       if ((seconds=renew)>3600) seconds=3600;
  386.       timeout=set_timeout((int) seconds);
  387.       nested=false;
  388.       return false;
  389.    }
  390.    // expire if dhcp_life gets below 2 seconds
  391.    if (dhcp_life<2) {
  392.       outs("nrDHCP lease expired, network disablednr");
  393.       if (sockopen) {
  394.  sock_close((sock_type*)&bsock);
  395.  sockopen=false;
  396.       }
  397.       // we really should should terminate all connections here
  398.       expired=true;
  399.       nested=false;
  400.       return true;
  401.    }
  402.    // send out a DHCPREQUEST to renew the lease and restart timer
  403.    if (!sockopen && !udp_open( &bsock, IPPORT_BOOTPC, _dhcphost, IPPORT_BOOTPS, NULL )) {
  404.      outs("nrUnable to resolve dhcp servernr");
  405.    } else {
  406.      sockopen=true;
  407.      memset( &_bootp, 0, sizeof( struct bootp ));
  408.      _bootp.bp_op = BOOTREQUEST;
  409.      _bootp.bp_htype = _pktdevclass;
  410.      if (_pktdevclass == PD_ETHER) _bootp.bp_hlen = 6;
  411.      _bootp.bp_ciaddr=intel(my_ip_addr);
  412.      if (xid==0) xid=intel(my_ip_addr);
  413.      _bootp.bp_xid = ++xid;
  414.      _bootp.bp_secs = intel16( 1 );
  415.      *(longword *)(&_bootp.bp_vend) = intel(VM_RFC1048);
  416.      p=&_bootp.bp_vend[4];
  417.      *p++=DHCP_VN_TYPE;
  418.      *p++=1;
  419.      *p++=DHCP_TY_REQ;
  420.      *p++=0;
  421.      *p++=DHCP_VN_REQIP;
  422.      *p++=4;
  423.      l=(longword *) p, *l++=intel(my_ip_addr), p=(char *) l;
  424.      *p++=DHCP_VN_SRVRID;
  425.      *p++=4;
  426.      l=(longword *) p, *l++=intel(_dhcphost), p=(char *) l;
  427.      *p=255;
  428.      movmem( &_eth_addr, _bootp.bp_chaddr, sizeof(eth_address));
  429.      sock_fastwrite( (sock_type*)&bsock, (byte *)&_bootp, sizeof( struct bootp ));
  430.    }
  431.    renew=dhcp_life>>1; // renew at 1/2 lifetime
  432.    if ((seconds=renew)>3600) seconds=3600;
  433.    timeout=set_timeout((int)seconds);
  434.    nested=false;
  435.    return false;
  436. }