home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / msk316src.zip / MSNBTP.C < prev    next >
C/C++ Source or Header  |  2000-11-01  |  20KB  |  575 lines

  1. /* File MSNBTP.C
  2.  * Bootp requestor
  3.  *
  4.  * Copyright (C) 1991, University of Waterloo.
  5.  *    Copyright (C) 1982, 1999, Trustees of Columbia University in the 
  6.  *    City of New York.  The MS-DOS Kermit software may not be, in whole 
  7.  *    or in part, licensed or sold for profit as a software product itself,
  8.  *    nor may it be included in or distributed with commercial products
  9.  *    or otherwise distributed by commercial concerns to their clients 
  10.  *    or customers without written permission of the Office of Kermit 
  11.  *    Development and Distribution, Columbia University.  This copyright 
  12.  *    notice must not be removed, altered, or obscured.
  13.  *
  14.  * Original version created by Erick Engelke of the University of
  15.  *  Waterloo, Waterloo, Ontario, Canada.
  16.  * Rewritten and extended for MS-DOS Kermit by Joe R. Doupnik, 
  17.  *  Utah State University, jrd@cc.usu.edu, jrd@usu.Bitnet.
  18.  *
  19.  * Last edit
  20.  * 31 Oct 2000 v3.16
  21.  *
  22.  *   BOOTP - Boot and DHCP Protocols, RFCs 951, 1048, 1395, 1531, 1541, 1533
  23.  *   and successors 2131 and 2132.
  24.  */
  25.  
  26. #include "msntcp.h"
  27. #include "msnlib.h"
  28.  
  29. /*
  30.  * structure for send and receives
  31.  */
  32. typedef struct bootp {
  33.     byte     bp_op;        /* packet op code / message type. */
  34.     byte     bp_htype;    /* hardware address type, 1 = Ethernet */
  35.     byte     bp_hlen;    /* hardware address len, eg '6' for Ethernet*/
  36.     byte     bp_hops;    /* client sets to zero, optionally used by
  37.                    gateways in cross-gateway booting. */
  38.     longword bp_xid;    /* transaction ID, a random number */
  39.     word     bp_secs;    /* filled in by client, seconds elapsed since
  40.                    client started trying to boot. */
  41.     word     bp_flags;    /* DHCP flags */
  42.     longword bp_ciaddr;    /* client IP address filled in by client */
  43.                 /*  if known */
  44.     longword bp_yiaddr;    /* 'your' (client) IP address
  45.                    filled by server if client doesn't know */
  46.     longword bp_siaddr;    /* server IP address returned in bootreply */
  47.     longword bp_giaddr;    /* gateway IP address,
  48.                    used in optional cross-gateway booting. */
  49.     byte     bp_chaddr[16];    /* client hardware address, filled by client */
  50.     byte     bp_sname[64];    /* optional server host name, null terminated*/
  51.  
  52.     byte     bp_file[128];    /* boot file name, null terminated string
  53.                    'generic' name or null in bootrequest,
  54.                    fully qualified directory-path
  55.                    name in bootreply. */
  56.     byte     bp_vend[64+248]; /* 64 vendor-specific area + 248 DHCP */
  57. };
  58.  
  59. /* UDP port numbers, server and client */
  60. #define    IPPORT_BOOTPS    67
  61. #define    IPPORT_BOOTPC    68
  62.  
  63. /* bootp.bp_op */
  64. #define BOOTREQUEST     1
  65. #define BOOTREPLY    2
  66.  
  67. /* DHCP values from RFC 1531, RFC 1533 et seq. */
  68. /* Command codes, option type 53, single octet of data */
  69. #define    DHCPDISCOVER   1
  70. #define    DHCPOFFER      2
  71. #define    DHCPREQUEST    3
  72. #define    DHCPDECLINE    4
  73. #define    DHCPACK           5
  74. #define    DHCPNAK           6
  75. #define    DHCPRELEASE    7
  76. #define DHCPINFORM     8
  77. #define DHCPRENEWING    100
  78.  
  79. /* DHCP command code, 53 decimal */
  80. #define DHCP_COMMAND    53
  81. #define OPTION_SERVERID 54
  82. #define OPTION_END    255
  83.  
  84. #define VM_RFC1048   0x63538263L    /* magic cookie for BOOTP */
  85. #define BOOTPTIMEOUT 30            /* seconds timeout to do bootup */
  86.  
  87. static longword DHCP_server_IP;        /* IP of DHCP server */
  88. static long DHCP_lease, DHCP_renewal, DHCP_rebind;
  89. static byte DHCP_state;
  90. static longword xid;            /* opaque msg ident */
  91. static use_RFC2131;            /* Use RFC2131 REQUESTs */
  92.  
  93. /* Values for request_busy word */
  94. #define REQ_IDLE 0            /* have not sent datagram yet */
  95. #define REQ_SENT 1            /* have sent datagram */
  96. #define REQ_BUSY 4            /* request() has not exited yet */
  97. int request_busy = REQ_IDLE;        /* DHCP request() lock */
  98.  
  99. /* global variables */
  100. longword bootphost = 0xffffffffL;    /* broadcast IP */
  101.  
  102. byte hostname[MAX_STRING+1] = {0};    /* our fully qualified IP name */
  103. extern word arp_hardware, MAC_len;    /* media details from msnpdi.asm */
  104. extern byte kdomain[];            /* our IP domain string */
  105. extern byte kbtpserver[];        /* IP of responding server */
  106. extern    eth_address eth_addr;        /* six byte array */
  107. extern    byte kdebug;            /* general debugging kind control */
  108. extern  char tcpflag;            /* from msntni.asm, 2 if doing Int 8*/
  109. extern    byte bootmethod;        /* which boot techinque to try */
  110.  
  111. static int status;            /* return value from request() */
  112. static longword master_timeout;        /* hard shutdown grace interval */
  113. static longword sendtimeout;        /* timeout between sends */
  114. static longword readtimeout;        /* timeout for reading */
  115. static word magictimeout = 1;        /* current read timeout interval */
  116. struct bootp bootppkt, *bp = &bootppkt;    /* Bootp/DHCP structure */
  117. static udp_Socket bsock;        /* UDP socket structure */
  118.  
  119. static int request(void);        /* send request, decode reply */
  120. static void decode(struct bootp *, int);    /* decode Options */
  121. static int notdhcp(struct bootp *, int);    /* detect DHCP pkt */
  122. static int tasksr(void);        /* task level send/receive */
  123. static int bootptick(void);        /* worker for tasksr */
  124.  
  125. /*
  126.  * do_bootp - Do Bootp or DHCP negotiations.
  127.  *             returns 0 on success and sets ip address
  128.  */
  129.  
  130. int 
  131. do_bootp()
  132. {
  133.     outs("\r\n Requesting a ");
  134.     if (bootmethod == BOOT_BOOTP)
  135.         outs("Bootp server ");
  136.     else    outs("DHCP server ");
  137.  
  138.     bootphost = 0xffffffffL;    /* broadcast IP */
  139.     my_ip_addr = 0L;        /* init our IP address to unknown */
  140.     DHCP_server_IP = 0L;        /* DHCP server IP address, 0 = none */
  141.     DHCP_lease = 0L;        /* no lease expiration */
  142.     DHCP_state = DHCPDISCOVER;    /* discover a DHCP server */
  143.     request_busy = REQ_IDLE;    /* request() lock, unlock it */
  144.     master_timeout = 0;        /* kill hard shutdown timer */
  145.     kbtpserver[0] = 0;        /* found server's IP address */
  146.     xid = htonl(set_timeout(0));    /* set xid as tod in Bios ticks */
  147.     if (tasksr() == -1)        /* do send receives */
  148.         return (-1);        /* fail */
  149.  
  150.     if (DHCP_server_IP == 0L)    /* no DHCP response, use Bootp */
  151.         {
  152.         bootmethod = BOOT_BOOTP;
  153.         return (my_ip_addr != 0? 0: -1); /* -1 for fail, 0 for succ */
  154.         }
  155.  
  156.                     /* DHCP negotiations, continued */
  157.     DHCP_lease = 0L;        /* no lease expiration, yet */
  158.     bootmethod = BOOT_DHCP;
  159.     DHCP_state = DHCPREQUEST;    /* set conditions for request() */
  160.     xid++;        /* change id tag so competing responses are ignored */
  161.     use_RFC2131 = 1;        /* use revision RFC2131 of DHCP */
  162.     if (tasksr() == -1)        /* do send receives */
  163.         return (-1);        /* fail */
  164.     if (DHCP_state == DHCPNAK    /* if Request refused */
  165.         && use_RFC2131)        /* and we used new style request */
  166.         {
  167.         use_RFC2131 = 0;    /* try again with RFC1541 style */
  168.         DHCP_state = DHCPREQUEST; /* set conditions for request() */
  169.         if (tasksr() == -1)        /* do send receives */
  170.             return (-1);        /* fail */
  171.         }
  172.  
  173.     use_RFC2131 = 1;        /* reset for next attempt */
  174.     if (DHCP_state != DHCPACK)
  175.         return (-1);        /* failure to negotiate DHCP */
  176.     bootphost = DHCP_server_IP;    /* only now remember server */
  177.     return (my_ip_addr != 0? 0: -1); /* -1 for failure, 0 for success */
  178. }
  179.  
  180. /* Run at task level, not from Int 8. Do timed send and receives, with
  181.    checking for aborts by Control-C and net failure. Calls tcp_tick()
  182.    to read fresh packets.
  183. */
  184. int
  185. tasksr(void)
  186. {
  187.             /* send/process DHCP REQUEST and ACK*/
  188.         sendtimeout = set_timeout(BOOTPTIMEOUT);
  189.         magictimeout = 1;
  190.         bootptick();        /* check for aborts, do send/receive*/
  191.         while (request_busy != REQ_IDLE)
  192.             status = bootptick();
  193.         if (status == -1)
  194.             return (-1);        /* fail */
  195. }
  196.  
  197. /* worker for tasksr(). Does its work minus the timed retries. */
  198. int
  199. bootptick(void)
  200. {
  201.     /* if not running from Int 8 background tick, check keyboard */
  202.     if (tcpflag != 2 && chkcon() != 0)    /* Control-C abort */
  203.         {
  204.         outs(" Canceled by user");
  205.         sock_close(&bsock);
  206.         request_busy = REQ_IDLE;    /* done */
  207.         return (-1);            /* failing status */
  208.         }
  209.  
  210.     /* if no data yet and not running from Int 8 background tick */
  211.     if (bsock.rdatalen == 0 && tcpflag != 2 &&
  212.         bsock.sisopen == SOCKET_OPEN) 
  213.         if (tcp_tick(&bsock) == 0)        /* read packets */
  214.             {        /* major network error if UDP fails */
  215.             outs(" Network troubles, quitting");
  216.             sock_close(&bsock);
  217.             request_busy = REQ_IDLE;    /* unlock access */
  218.             return (-1);            /* fail */
  219.             }
  220.     return (request());            /* do send/receives */
  221. }
  222.  
  223. /* Request Bootp/DHCP information and decode responses
  224.    This can be called at task level by do_bootp(), and at Int 8 background
  225.    level via DHCP_refresh(). To prevent reentrancy problems request_busy sets
  226.    the REQ_BUSY bit. To keep state on whether we need to transmit or receive
  227.    bit REQ_SENT is used to say have transmitted so instead do receive code.
  228.    Flag byte tcpflag value of 2 (from msntni.asm) means we are running from
  229.    Int 8 and may not do calls to the Bios or DOS and we must be fast.
  230. */
  231. static int
  232. request(void)
  233. {
  234.     int reply_len;
  235.  
  236. /* if have sent datagram and receive waiting has time to go, then receive */    
  237.  
  238.     request_busy |= REQ_BUSY;    /* say we have entered request() */
  239.  
  240.     if (request_busy & REQ_SENT && chk_timeout(readtimeout) != TIMED_OUT)
  241.         goto inprogress;    /* not timed out reading */
  242.  
  243.     if (chk_timeout(sendtimeout) == TIMED_OUT) /* sent for too long */
  244.         {            /* failed attempt, no respondent */
  245.         sock_close(&bsock);
  246.         request_busy = REQ_IDLE;
  247.         return (-1);                /* fail */
  248.         }
  249.  
  250.     memset((byte *)bp, 0, sizeof(struct bootp));
  251.  
  252.     bp->bp_op = BOOTREQUEST;
  253.     bp->bp_htype = (byte)(arp_hardware & 0xff); /* hardware type */
  254.     bcopy(eth_addr, bp->bp_chaddr, MAC_len); /* hardware address */
  255.     bp->bp_hlen = (byte) MAC_len;        /* length of MAC address */
  256.     bp->bp_xid = xid;            /* identifier, opaque */
  257.     bp->bp_ciaddr = htonl(my_ip_addr);    /* client IP identifier */
  258.     *(long *)&bp->bp_vend[0] = VM_RFC1048;    /* magic cookie longword */
  259.     bp->bp_vend[4] = OPTION_END;        /* end of Options, BOOTP */
  260.  
  261.     if (bootmethod == BOOT_DHCP)        /* DHCP details */
  262.         {
  263.         bp->bp_vend[4] = DHCP_COMMAND;    /* option, DHCP command */
  264.         bp->bp_vend[5] = 1;        /* length of value */
  265.         bp->bp_vend[6] = DHCPREQUEST;    /* Request data */
  266.         bp->bp_vend[7] = OPTION_END;    /* end of Options */
  267.         if (DHCP_state == DHCPDISCOVER)    /* if first probe */
  268.             {
  269.             bp->bp_flags = htons(1); /* set DHCP Broadcast bit */
  270.             bp->bp_vend[6] = DHCPDISCOVER; /* DHCP server discov*/
  271.             }
  272.         if (DHCP_state == DHCPREQUEST)    /* if Request, not Renewal */
  273.             {
  274.             bp->bp_vend[7] = OPTION_SERVERID; /* server id */
  275.             bp->bp_vend[8] = 4;        /* length of value */
  276.             *(long *)&bp->bp_vend[9] = htonl(DHCP_server_IP);
  277.             bp->bp_vend[13] = OPTION_END;    /* end of Options */
  278.             if (use_RFC2131)      /* if not using RFC1541 */
  279.                 {
  280.                 bp->bp_ciaddr = 0; /* no client identifier */
  281.                 bp->bp_vend[13] = 50;    /* Requested IP Addr*/
  282.                 bp->bp_vend[14] = 4;    /* length of value */
  283.                         /* our IP address goes here */
  284.                 *(long *)&bp->bp_vend[15] = htonl(my_ip_addr);
  285.                 bp->bp_vend[19] = OPTION_END;
  286.                 }
  287.             my_ip_addr = 0;     /* now forget IP from DISCOVER */
  288.             }
  289.         }
  290.  
  291.     if (bsock.sisopen == SOCKET_OPEN) 
  292.         sock_close(&bsock);            /* just in case */
  293.     if (udp_open(&bsock, IPPORT_BOOTPC, bootphost, IPPORT_BOOTPS) == 0)
  294.         {
  295.         request_busy = REQ_IDLE;        /* clear lock */
  296.         sock_close(&bsock);
  297.                return (-1);                /* fail */
  298.         }
  299.  
  300.         /* send only bootp length requests, accept DHCP replies */
  301.                         /* send datagram */
  302.     bsock.rdatalen = 0;            /* clear old received data */
  303.     sock_write(&bsock, (byte *)bp, sizeof(struct bootp) - 248);
  304.     readtimeout = set_timeout(magictimeout++); /* receiver timeout */
  305.     if (magictimeout > 8)
  306.         magictimeout = 8;        /* truncate waits */
  307.     if (bootmethod == BOOT_BOOTP || DHCP_state == DHCPDISCOVER)
  308.         outs(".");            /* progress indicator */
  309.     request_busy = REQ_SENT;        /* exiting but not done */
  310.     return (-1);            /* next call does reading thread */
  311.  
  312. inprogress:            /* here we read UDP responses */
  313.  
  314.     reply_len = sock_fastread(&bsock, (byte *)bp, 
  315.                         sizeof(struct bootp));
  316.  
  317.     if ((reply_len < sizeof(struct bootp) - 248) || /* too short */
  318.         (bp->bp_xid != xid) ||            /* not our ident */
  319.         (bp->bp_yiaddr == 0) ||        /* no IP address for us */
  320.         (*(long *)&bp->bp_vend != VM_RFC1048) ||    /* wrong vendor id */
  321.         (bootmethod == BOOT_DHCP && DHCP_state != DHCPDISCOVER &&
  322.             (DHCP_server_IP != ntohl(bp->bp_siaddr) ||
  323.             notdhcp(bp, reply_len))) )
  324.             /* no DHCP server IP, no DHCP msg */
  325.         {
  326.         request_busy = REQ_SENT;         /* not done yet */
  327.         return (-1);        /* not a required DHCP response */
  328.         }
  329.  
  330.     decode(bp, reply_len);        /* extract response data */
  331.  
  332.     if (my_ip_addr == 0L)        /* if first time through */
  333.         {
  334.         my_ip_addr = ntohl(bp->bp_yiaddr); /* bootp header */
  335.         if (DHCP_server_IP == 0)     /* if no DHCP server addr */
  336.             ntoa(kbtpserver, ntohl(bp->bp_siaddr)); /* bootp */
  337.         else
  338.             ntoa(kbtpserver, DHCP_server_IP); /* decode() swaps */
  339.         }
  340.     sock_close(&bsock);
  341.     request_busy = REQ_IDLE;        /* done processing */
  342.     return (my_ip_addr != 0? 0: -1); /* -1 for fail, 0 for success */
  343. }
  344.  
  345. /* Return zero if reply contains a DHCP Command, else return non-zero */
  346. static int
  347. notdhcp(struct bootp * bp, int reply_len)
  348. {
  349.     byte *p, *q;
  350.  
  351.     p = &bp->bp_vend[4];        /* Point just after magic cookie */
  352.     q = &bp->bp_op + reply_len;    /* end of all possible vendor data */
  353.  
  354.     while (*p != 255 && (q - p) > 0)
  355.         switch(*p)
  356.         {
  357.                 case 0:         /* Nop Pad character */
  358.                     p++;
  359.                     break;
  360.         case 53:        /* DHCP Command from server */
  361.             return (0);
  362.         case 255:        /* end of options */
  363.             return(1);
  364.         default:
  365.               p += *(p+1) + 2; /* skip other options */
  366.             break;
  367.                   }
  368.     return(1);
  369. }
  370.  
  371. /* Decode Bootp/DHCP Options from received packet */
  372. static void
  373. decode(struct bootp * bp, int reply_len)
  374. {
  375.     byte *p, *q;
  376.     word len;
  377.     longword tempip;
  378.     extern word arp_last_gateway;    /* in msnarp.c */
  379.     extern int last_nameserver;    /* in msndns.c */
  380.  
  381.     p = &bp->bp_vend[4];        /* Point just after magic cookie */
  382.     q = &bp->bp_op + reply_len;    /* end of all possible vendor data */
  383.  
  384.     while (*p != 255 && (q - p) > 0)
  385.         switch(*p)
  386.         {
  387.                 case 0: /* Nop Pad character */
  388.                     p++;
  389.                     break;
  390.         case 1: /* Subnet Mask */
  391.             sin_mask = ntohl(*(longword *)(&p[2]));
  392.             p += *(p+1) + 2;
  393.             break;
  394.         case 3: /* gateways */
  395.             arp_last_gateway = 0;         /* clear old values */
  396.             for (len = 0; len < *(p+1); len += 4)
  397.               arp_add_gateway(NULL,ntohl(*(longword*)(&p[2+len])));
  398.             p += *(p+1) + 2;
  399.             break;
  400.         case 6: /* Domain Name Servers (BIND) */
  401.             last_nameserver = 0;        /* clear old values */
  402.             for (len = 0; len < *(p+1); len += 4)
  403.                 add_server(&last_nameserver, MAX_NAMESERVERS,
  404.             def_nameservers, ntohl(*(longword*)(&p[2 + len])));
  405.             p += *(p+1) + 2;
  406.             break;
  407.         case 12: /* our hostname, hopefully complete */
  408.             bcopyff(p+2, hostname, (int)(p[1] & 0xff));
  409.             hostname[(int)(p[1] & 0xff)] = '\0';
  410.             p += *(p+1) + 2;
  411.             break;
  412.         case 15: /* RFC-1395, Domain Name tag */
  413.             bcopyff(p+2, kdomain, (int)(p[1] & 0xff));
  414.             kdomain[(int)(p[1] & 0xff)] = '\0';
  415.             p += *(p+1) + 2;
  416.             break;
  417.  
  418.         case 51:    /* DHCP Offer lease time, seconds */
  419.             if (p[1] == 4)
  420.                 {
  421.                 DHCP_lease = ntohl(*(longword*)(&p[2]));
  422.                 if (DHCP_lease == -1L)    /* -1 is infinite */
  423.                     DHCP_lease = 0;    /* no timeout */
  424.                 else
  425.                     {
  426.                     if (DHCP_lease > 0x0ffffL)
  427.                         DHCP_lease = 0x0ffffL;
  428.  
  429.                     DHCP_lease = set_timeout((int)(0xffff 
  430.                         & DHCP_lease));
  431.                     }
  432.                 /* below: safety if server does not state */
  433.                 if (DHCP_renewal == 0L)
  434.                     DHCP_renewal = DHCP_lease;
  435.                 if (DHCP_rebind == 0L)
  436.                     DHCP_rebind = DHCP_lease;
  437.                 }
  438.             p += *(p+1) + 2;
  439.             break;
  440.  
  441.         case 53:    /* DHCP Command from server */
  442.             DHCP_state = p[2];    /* Command, to local state */
  443.             p += *(p+1) + 2;
  444.             break;
  445.         case 54:    /* DHCP server IP address */
  446.             if (p[1] == 4)
  447.                 if (tempip = *(longword*)(&p[2]))
  448.                     DHCP_server_IP = ntohl(tempip);
  449.             p += *(p+1) + 2;
  450.             break;
  451.         case 58:    /* DHCP lease renewal time (T1) */
  452.             if (p[1] == 4)
  453.                 {
  454.                 DHCP_renewal = ntohl(*(longword*)(&p[2]));
  455.                 if (DHCP_renewal == -1L)
  456.                     DHCP_renewal = 0;    /* no timeout */
  457.                 else
  458.                      {
  459.                      if (DHCP_renewal > 0x0ffffL)
  460.                         DHCP_lease = 0x0ffffL;
  461.                      DHCP_renewal = set_timeout((int)(0xffff & 
  462.                         DHCP_renewal));
  463.                      }
  464.                 }
  465.             p += *(p+1) + 2;
  466.             break;
  467.         case 59:    /* DHCP rebind time (T2) */
  468.             if (p[1] == 4)
  469.                 {
  470.                 DHCP_rebind = ntohl(*(long*)(&p[2]));
  471.                 if (DHCP_rebind > 0x0ffffL)
  472.                     DHCP_rebind = 0x0ffffL;
  473.                 DHCP_lease = DHCP_rebind =
  474.                 set_timeout((int)(0xffff & DHCP_rebind));
  475.                 }
  476.             p += *(p+1) + 2;
  477.             break;
  478.  
  479.         case 255:    /* end of options */
  480.             break;
  481.         default:
  482.               p += *(p+1) + 2;
  483.             break;
  484.                   }             /* end of switch */
  485. }
  486.  
  487. /* Release DHCP granted IP information. Skip if DHCP ACK has not been
  488.    received or if lease time is infinite (to help Novell's DHCP v2.0
  489.    from clobbering itself with erasure of permanent assignments).
  490. */
  491. void
  492. end_bootp(void)
  493. {
  494.     longword wait;
  495.  
  496.     if (bootmethod != BOOT_DHCP)
  497.         return;                /* not using DHCP */
  498.  
  499.     if (DHCP_lease == 0)            /* infinite lease */
  500.         return;
  501.  
  502.     memset((byte *)bp, 0, sizeof(struct bootp));
  503.  
  504.     udp_open(&bsock, IPPORT_BOOTPC, bootphost, IPPORT_BOOTPS);
  505.     bp->bp_op = BOOTREQUEST;
  506.     bp->bp_htype = (byte)(arp_hardware & 0xff);
  507.     bcopy(eth_addr, bp->bp_chaddr, MAC_len);
  508.     bp->bp_hlen = (byte) MAC_len;        /* length of MAC address */
  509.     bp->bp_xid = ++xid;
  510.     *(long *)&bp->bp_vend[0] = VM_RFC1048;    /* magic cookie longword */
  511.     bp->bp_vend[4] = DHCP_COMMAND;    /* option, DHCP command */
  512.     bp->bp_vend[5] = 1;        /* length of value */
  513.     bp->bp_vend[6] = DHCPRELEASE;    /* value, release DHCP server */
  514.     bp->bp_vend[7] = OPTION_SERVERID; /* server identification */
  515.     bp->bp_vend[8] = 4;        /* length of IP address */
  516.     *(long *)&bp->bp_vend[9] = htonl(DHCP_server_IP);
  517.     bp->bp_vend[13] = OPTION_END;    /* end of options */
  518.  
  519.     sock_write(&bsock, (byte *)bp, sizeof(struct bootp) - 248);
  520.     wait = set_ttimeout(1);        /* one Bios clock tick */
  521.     while (chk_timeout(wait) != TIMED_OUT) ;    /* pause */
  522.                             /* repeat */
  523.     sock_write(&bsock, (byte *)bp, sizeof(struct bootp) - 248);
  524.     sock_close(&bsock);
  525.  
  526.      DHCP_server_IP = 0L;        /* DHCP server IP address, 0 = none */
  527.     DHCP_lease = 0L;        /* no lease expiration */
  528.     DHCP_state = DHCPDISCOVER;
  529.     my_ip_addr = 0L;        /* lose our IP address too */
  530. }
  531.  
  532. /* Renew DHCP lease on our IP address. Skip if lease is infinite and if
  533.    renewal has not timed out. DHCP_renewal is Bios time of day when renewal
  534.    is needed; DHCP_lease is Bios time of day of lease (0 means infinite).
  535. */
  536. int
  537. DHCP_refresh()
  538. {
  539.     longword temp;
  540.  
  541.     if (request_busy & REQ_BUSY)
  542.         return (0);            /* request() not exited yet */
  543.     if (DHCP_lease == 0 ||            /* infinite lease */
  544.         chk_timeout(DHCP_renewal) != TIMED_OUT)
  545.         return (0);            /* nothing to do yet */
  546.     if (master_timeout)            /* shutting down hard */
  547.         if (chk_timeout(master_timeout) == TIMED_OUT)
  548.             return (-1);        /* fail, shuts down stack */
  549.         else
  550.             return (0);        /* still in grace interval */
  551.  
  552.     DHCP_state = DHCPRENEWING;        /* set new state */
  553.     sendtimeout = set_timeout(BOOTPTIMEOUT); /* sending timeout limit */
  554.     magictimeout = 1;            /* one second */
  555.     status = request();            /* send and read replies */
  556.     if (request_busy != REQ_IDLE)
  557.         return (0);            /* not done yet */
  558.  
  559.     if (status == 0)            /* if success */
  560.         {
  561.         if (DHCP_lease == 0 ||        /* infinite lease */
  562.         chk_timeout(DHCP_renewal) != TIMED_OUT) /* lease renewed */
  563.             return (0);        /* success, lease renewed */
  564.         }
  565.  
  566.     outs("\r\n Failed to renew DHCP IP address lease");
  567.     outs("\r\n Shutting down TCP/IP system in ");
  568.     temp = DHCP_lease - set_ttimeout(0);    /* ticks from now */
  569.     temp = ourldiv(temp, 18);        /* ticks to seconds */
  570.     outdec((word)temp & 0xffff);
  571.     outs(" seconds!\7\r\n");
  572.     master_timeout = DHCP_lease;        /* set master shutdown */
  573.     return (0);                /* stay alive for now */
  574. }
  575.