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

TCP/IP协议栈

开发平台:

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