dhcpboot.c

来自「完整的Bell实验室的嵌入式文件系统TFS」· C语言 代码 · 共 1,232 行 · 第 1/3 页

C
1,232
字号
            *dhcpOptions++ = 1;            *dhcpOptions++ = DHCPDISCOVER;            dhcpOptions = dhcpLoadShellVarOpts(dhcpOptions);            *dhcpOptions++ = 0xff;                /* Calculate ip and udp lengths after all DHCP options are loaded             * so that the size is easily computed based on the value of the             * dhcpOptions pointer.  Apparently, the minimum size of the             * options space is 64 bytes, we determined this simply because             * the DHCP server we are using complains if the size is smaller.             * Also, NULL out the space that is added to get a minimum option             * size of 64 bytes,              */            optlen = dhcpOptions - dhcpOptionsBase;            if (optlen < 64) {                memset(dhcpOptions,0,64-optlen);                optlen = 64;            }            uh_ulen = sizeof(struct Udphdr)+sizeof(struct dhcphdr)+optlen;            tu->uh_ulen = ecs(uh_ulen);        }    }    ti->ip_len = ecs(sizeof(struct ip) + uh_ulen);    ipChksum(ti);   /* Compute checksum of ip hdr */    udpChksum(ti);  /* Compute UDP checksum */    if (bootp) {        DHCPState = BOOTPSTATE_REQUEST;        sendBuffer(BOOTPSIZE);    }    else {        DHCPState = DHCPSTATE_SELECT;        sendBuffer(DHCPSIZE+optlen);    }    if (EtherVerbose & SHOW_DHCP)        printf("  %s startup (%d elapsed secs)\n",            bootp ? "BOOTP" : "DHCP",seconds);    return(0);}/* SendDHCPRequest() *  The DHCP request is broadcast back with the "server identifier" option *  set to indicate which server has been selected (in case more than one *  has offered). */intSendDHCPRequest(dhdr)struct  dhcphdr *dhdr;{    uchar   *op;    struct  dhcphdr *dhcpdata;    struct  ether_header *te;    struct  ip *ti;    struct  Udphdr *tu;    int     optlen;    uchar   *dhcpOptions, *dhcpOptionsBase;    ushort  uh_ulen;    ulong   cookie;    if (EtherVerbose & SHOW_DHCP)        printf("  DHCP request\n");    te = (struct ether_header *) getXmitBuffer();    memcpy((char *)&te->ether_shost,BinEnetAddr,6);    memcpy((char *)&te->ether_dhost,BroadcastAddr,6);    te->ether_type = ecs(ETHERTYPE_IP);    ti = (struct ip *) (te + 1);    ti->ip_vhl = IP_HDR_VER_LEN;    ti->ip_tos = 0;    ti->ip_id = 0;    ti->ip_off = ecs(0x4000);   /* No fragmentation allowed */    ti->ip_ttl = UDP_TTL;    ti->ip_p = IP_UDP;    memset((char *)&ti->ip_src.s_addr,0,4);    memset((char *)&ti->ip_dst.s_addr,0xff,4);    tu = (struct Udphdr *) (ti + 1);    tu->uh_sport = ecs(DhcpClientPort);    tu->uh_dport = ecs(DhcpServerPort);    dhcpdata = (struct dhcphdr *)(tu+1);    dhcpdata->op = DHCPBOOTP_REQUEST;    dhcpdata->htype = 1;    dhcpdata->hlen = 6;    dhcpdata->hops = 0;    DHCPElapsedSecs += 1;   /* Not accurate */    dhcpdata->seconds = ecs(DHCPElapsedSecs);    /* Use the same xid for the request as was used for the discover...     * (rfc2131 section 4.4.1)     */    memcpy((char *)&dhcpdata->transaction_id,(char *)&dhdr->transaction_id,4);    dhcpdata->flags = dhdr->flags;    memset((char *)&dhcpdata->client_ip,0,4);    memcpy((char *)&dhcpdata->your_ip,(char *)&dhdr->your_ip,4);    memset((char *)&dhcpdata->server_ip,0,4);    memset((char *)&dhcpdata->router_ip,0,4);    cookie = ecl(STANDARD_MAGIC_COOKIE);    memcpy((char *)&dhcpdata->magic_cookie,(char *)&cookie,4);    memcpy(dhcpdata->client_macaddr,BinEnetAddr,6);    dhcpOptionsBase = (uchar *)(dhcpdata+1);    dhcpOptions = dhcpOptionsBase;    *dhcpOptions++ = DHCPOPT_MESSAGETYPE;    *dhcpOptions++ = 1;    *dhcpOptions++ = DHCPREQUEST;    *dhcpOptions++ = DHCPOPT_SERVERID;      /* Server id ID */    *dhcpOptions++ = 4;    op = DhcpGetOption(DHCPOPT_SERVERID,dhdr+1);    if (op)        memcpy(dhcpOptions,op+2,4);    else        memset(dhcpOptions,0,4);    dhcpOptions+=4;    *dhcpOptions++ = DHCPOPT_REQUESTEDIP;       /* Requested IP */    *dhcpOptions++ = 4;    memcpy(dhcpOptions,(char *)&dhdr->your_ip,4);    dhcpOptions += 4;    dhcpOptions = dhcpLoadShellVarOpts(dhcpOptions);    *dhcpOptions++ = 0xff;    /* See note in SendDHCPDiscover() regarding the computation of the     * ip and udp lengths.     */    optlen = dhcpOptions - dhcpOptionsBase;    if (optlen < 64)        optlen = 64;    uh_ulen = sizeof(struct Udphdr) + sizeof(struct dhcphdr) + optlen;    tu->uh_ulen = ecs(uh_ulen);    ti->ip_len = ecs(sizeof(struct ip) + uh_ulen);    ipChksum(ti);       /* Compute checksum of ip hdr */    udpChksum(ti);      /* Compute UDP checksum */    DHCPState = DHCPSTATE_REQUEST;    sendBuffer(DHCPSIZE+optlen);    return(0);}/* randomDhcpStartupDelay(): *  Randomize the startup for DHCP/BOOTP (see RFC2131 Sec 4.4.1)... *  Return a value between 1 and 10 based on the last 4 bits of the  *  board's MAC address. */intrandomDhcpStartupDelay(){    int randomsec;    randomsec = (BinEnetAddr[5] & 0xf);    if (randomsec > 10)        randomsec -= 7;    else if (randomsec == 0)        randomsec = 10;    return(randomsec);}/* dhcpStateCheck(): *  Called by pollethernet() to monitor the progress of DHCPState. *  The retry rate is "almost" what is specified in the RFC... *  Refer to the RetransmitDelay() function for details. * *  Regarding timing... *  The DHCP startup may be running without an accurate measure of elapsed *  time.  The value of LoopsPerSecond is used as an approximation of *  the number of times this function must be called for one second to  *  pass (dependent on network traffic, etc...).  RetransmitDelay() is *  called to retrieve the number of seconds that must elapse prior to  *  retransmitting the last DHCP message.  The static variables in this *  function are used to keep track of that timeout. */voiddhcpStateCheck(void){    static int dhcpretry, delayloops, delaysecs;    /* If the DHCP command has been issued, it is assumed that the script     * is handling retries...     */    if (DHCPCommandIssued)        return;    /* Return, restart or fall through; depending on DHCPState... */    switch(DHCPState) {        case DHCPSTATE_NOTUSED:        case BOOTPSTATE_COMPLETE:        case DHCPSTATE_BOUND:            delayloops = 0;            return;        case DHCPSTATE_RESTART:            delayloops = 0;            DHCPStartup(0);            return;        case BOOTPSTATE_RESTART:            delayloops = 0;            BOOTPStartup(0);            return;        case DHCPSTATE_INITIALIZE:      /* Randomized delay prior to startup */        case BOOTPSTATE_INITIALIZE:     /* of the BOOTP/DHCP transaction. */            if (!delayloops) {                dhcpretry = 0;                delaysecs = randomDhcpStartupDelay();                delayloops = delaysecs * LoopsPerSecond;                if (EtherVerbose & SHOW_DHCP)                    printf("\nDHCP/BOOTP %d sec startup delay...\n",delaysecs);            }            else if ((++dhcpretry > delayloops) || (gotachar())) {                DHCPElapsedSecs = 0;                if (DHCPState & BOOTP_MODE)                    BOOTPStartup(0);                else                    DHCPStartup(0);                dhcpretry = 0;                delayloops = 0;            }            return;        default:            break;    }    /* If the DHCP or BOOTP transaction hasn't completed by the time     * the static variable dhcpretry reaches the current retransmit-delay     * point, then restart the transaction.     * Note that we only do the multiplication if delayloops is zero.  This     * just avoids the wasted processing time.     */    if (!delayloops) {        delaysecs = RetransmitDelay(DELAY_RETURN);        delayloops = delaysecs*LoopsPerSecond;        dhcpretry = 0;    }    if (++dhcpretry > delayloops) {        DHCPElapsedSecs += delaysecs;        if (DHCPState & BOOTP_MODE)            BOOTPStartup(DHCPElapsedSecs);        else            DHCPStartup(DHCPElapsedSecs);        if (EtherVerbose & SHOW_DHCP)            printf("  DHCP/BOOTP retry (%d secs)\n",delaysecs);        dhcpretry = 0;        delayloops = 0;        RetransmitDelay(DELAY_INCREMENT);    }}/* xidCheck(): *  Common function used for DHCP and BOOTP to verify incoming transaction *  id... */intxidCheck(char *id,int bootp){    if (memcmp(id,(char *)&DHCPTransactionId,4)) {        if (EtherVerbose & SHOW_DHCP) {            printf("%s ignored: unexpected transaction id.\n",                bootp ? "BOOTP":"DHCP");        }        return(-1);    }    return(0);}intloadBootFile(int bootp){#if INCLUDE_TFTP    char    bfile[TFSNAMESIZE+TFSINFOSIZE+32];    char    *flags, *info, *icomma, *fcomma, *argv[2];    char    *bootfile, *tftpsrvr;    ulong   addr;    /* If both bootfile and server-ip are specified, then boot it.     * The name of the file must contain information that tells the monitor     * what type of file it is, so the first 'comma' extension is used as     * the flag field (if it is a valid flag set) and the second 'comma'     * extension is used as the info field.     */    bootfile = getenv("BOOTFILE");    tftpsrvr = getenv("BOOTSRVR");    if (bootfile && tftpsrvr) {        int tftpworked;        addr = getAppRamStart();        info = "";        flags = "e";        strncpy(bfile,bootfile,sizeof(bfile));        fcomma = strchr(bfile,',');        if (fcomma) {            icomma = strchr(fcomma+1,',');            if (icomma) {                *icomma = 0;                info = icomma+1;            }            *fcomma = 0;            if (tfsctrl(TFS_FATOB,(long)(fcomma+1),0) != 0)                flags = fcomma+1;        }        /* Since we are about to transition to TFTP, match TFTP's         * verbosity to the verbosity currently set for DHCP...         */        if (EtherVerbose & SHOW_DHCP)            EtherVerbose |= SHOW_TFTP;        /* If the TFTP transfer succeeds, attempt to run the boot file;         * if the TFTP transfer fails, then re-initialize the tftp state         * and set the DHCP state such that dhcpStateCheck() will         * cause the handshake to start over again...         */        tftpworked = tftpGet(addr,tftpsrvr,"octet",bfile,bfile,flags,info);        if (tftpworked) {            EtherVerbose = 0;            argv[0] = bfile;            argv[1] = 0;            tfsrun(argv,0);        }        else {            tftpInit();            RetransmitDelay(DELAY_INIT_DHCP);            EtherVerbose &= ~SHOW_TFTP;            if (bootp)                DHCPState = BOOTPSTATE_RESTART;            else                DHCPState = DHCPSTATE_RESTART;        }    }    else        EtherVerbose &= ~(SHOW_DHCP|DHCP_VERBOSE);#endif    return(0);}/* processBOOTP(): *  A subset of processDHCP(). *  We get here from processDHCP, because it detects that the current *  value of DHCPState is BOOTPSTATE_REQUEST. */intprocessBOOTP(ehdr,size)struct ether_header *ehdr;ushort size;{    struct  ip *ihdr;    struct  Udphdr *uhdr;    struct  bootphdr *bhdr;    ulong   ip, temp_ip, cookie;    uchar   buf[16], *op;    printMem((uchar *)ehdr,size);    ihdr = (struct ip *)(ehdr + 1);    uhdr = (struct Udphdr *)((char *)ihdr + IP_HLEN(ihdr));    bhdr = (struct bootphdr *)(uhdr+1);    /* Verify incoming transaction id matches the previous outgoing value: */    if (xidCheck((char *)&bhdr->transaction_id,1) < 0)        return(-1);    /* If bootfile is nonzero, store it into BOOTFILE shell var: */    if (bhdr->bootfile[0])        DhcpSetEnv("BOOTFILE",bhdr->bootfile);    /* Assign IP "server_ip" to the BOOTSRVR shell var (if non-zero): */    memcpy((char *)&temp_ip,(char *)&bhdr->server_ip,4);    if (temp_ip)        DhcpSetEnv("BOOTSRVR",IpToString(temp_ip,buf));    /* Assign IP "router_ip" to the RLYAGNT shell var (if non-zero): */    memcpy((char *)&temp_ip,(char *)&bhdr->router_ip,4);    if (temp_ip)        DhcpSetEnv("RLYAGNT",IpToString(temp_ip,buf));    /* Assign IP address loaded in "your_ip" to the IPADD shell var: */    memcpy(BinIpAddr,(char *)&bhdr->your_ip,4);    memcpy((char *)&temp_ip,(char *)&bhdr->your_ip,4);    DhcpSetEnv("IPADD",IpToString(temp_ip,buf));    /* If STANDARD_MAGIC_COOKIE exists, then process options... */    memcpy((char *)&cookie,(char *)bhdr->vsa,4);    if (cookie == ecl(STANDARD_MAGIC_COOKIE)) {        /* Assign subnet mask option to NETMASK shell var (if found): */        op = DhcpGetOption(DHCPOPT_SUBNETMASK,&bhdr->vsa[4]);        if (op) {            memcpy((char *)&ip,op+2,4);            DhcpSetEnv("NETMASK",IpToString(ip,buf));        }        /* Assign first router option to GIPADD shell var (if found): */        /* (the router option can have multiple entries, and they are */        /* supposed to be in order of preference, so use the first one) */        op = DhcpGetOption(DHCPOPT_ROUTER,&bhdr->vsa[4]);        if (op) {            memcpy((char *)&ip,op+2,4);            DhcpSetEnv("GIPADD",IpToString(ip,buf));        }    }    DhcpBootpDone(1,(struct dhcphdr *)bhdr,        size - ((int)((int)&bhdr->vsa - (int)ehdr)));    DHCPState = BOOTPSTATE_COMPLETE;    /* Call loadBootFile() which will then kick off a tftp client     * transfer if both BOOTFILE and BOOTSRVR shell variables are     * loaded; otherwise, we are done.     */

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?