⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 p16_dhcp.c

📁 一个由PIC单片机组成的Web服务器源码
💻 C
字号:
/* DHCP functions for PICmicro Web server - Copyright (c) Iosoft Ltd 2001
**
** This source code is only licensed for distribution in the Iosoft ChipWeb
** package, and the purchaser of that package is granted the non-exclusive
** right to use the software for personal experimentation only, provided
** that this copyright notice is retained. All other rights are retained by
** Iosoft Ltd.
**
** Redistribution of this source code is not permitted. Binary images derived
** from the source code may only be redistributed if a commercial license is
** obtained; see www.iosoft.co.uk or email license@iosoft.co.uk
**
** The software is supplied 'as-is' for development purposes, without warranty
** of any kind, either expressed or implied, including, but not limited to,
** the implied warranties of merchantability and fitness for purpose.
** In no event will Iosoft Ltd. be liable for damages, including any general,
** special, incidental or consequential damages arising out of the use or
** inability to use the software, including, but not limited to, loss or
** corruption of data, or losses sustained by the developer or third parties,
** or failure of the software to operate with any other software or systems.
** This license shall be governed by the laws of England. */

#define DHCP_INIT  0            // DHCP states: initial
#define DHCP_DISCOVER   1       //              discovery in progress
#define DHCP_OFFER      2       //              offer received OK
#define DHCP_REQUEST    3       //              sending request
#define DHCP_DECLINE    4       //              declining request
#define DHCP_ACK        5       //              acknowledge
#define DHCP_NAK        6       //              negative ack
#define DHCP_RELEASE    7       //              release bound addr
#define DHCP_INFORM     8       //              info to server
#define DHCP_RENEWING   0x13    // Additional states: renewing
#define DHCP_REBINDING  0x23    //                    rebinding
#define DHCP_BOUND      0x30    //                    bound OK

#define DHCP_TYPE_MASK  0x0f    // Mask value to get msg type from state

#define DHCP_DISCTIME (SECTICKS * 5) // Delay between DHCP discovery requests
#define LEASE_MINSECS 60    // Minimum lease renewal time in seconds (16-bit)
#define LEASE_MAXSECS 43200 // Maximum lease renewal time in seconds (16-bit)
#define DHCP_MAXDISCTICKS (SECTICKS*120)

BYTE dhcp_state=0;              // Current DHCP state
WORD dhcp_delticks;             // Current delay tick count
WORD dhcp_secticks;             // ..and seconds tick counter
WORD dhcp_deltickval;           // Current delay value (in ticks)
WORD dhcp_delbaseval;           // Base value for delay (in ticks)
WORD dhcp_secs;                 // Seconds counter
WORD lease_secs;                // Lease time (in seconds)
WORD renew_secs;                // Renewal time (in seconds)
LWORD dhcp_newip;               // IP address offered
LWORD xid;                      // DHCP transaction ID
BYTE dhcp_hosteth[MACLEN];      // DHCP host Ethernet addr
LWORD dhcp_hostip;              // DHCP host IP addr

LWORD leasetime, newip;

SEPARATED void dhcp_tx(BYTE state);
void put_nulls(BYTE n);
WORD rand_byte(WORD val);
WORD rand_bit(WORD val);

/* Do a DHCP request, return 0 if no DHCP address available yet */
SEPARATED BOOL check_dhcp(void)
{
    WORD sernum;

    if (dhcp_state == DHCP_INIT)
    {
        myip.l = 0;
        sernum = swapw(*(WORD *)&myeth[4]);
        dhcp_secs = 0;
        timeout(&dhcp_delticks, 0);
        timeout(&dhcp_secticks, 0);
        dhcp_delbaseval = dhcp_deltickval =
            SECTICKS + (rand_byte(sernum) & 0x1f);
        xid.w[0] = sernum;
        xid.w[1] = dhcp_delbaseval;
        dhcp_state = DHCP_DISCOVER;
    }
    else if (dhcp_state==DHCP_DISCOVER || dhcp_state==DHCP_REQUEST ||
             dhcp_state==DHCP_RENEWING)
    {
        if (timeout(&dhcp_delticks, dhcp_deltickval))
        {
            checkflag = checkhi = checklo = 0;
            dhcp_tx(dhcp_state);
            if (dhcp_deltickval < DHCP_MAXDISCTICKS/2)
                dhcp_deltickval += dhcp_deltickval;
        }
    }
    if (dhcp_state==DHCP_BOUND || dhcp_state==DHCP_RENEWING)
    {
        if (timeout(&dhcp_secticks, SECTICKS))
        {
            dhcp_secs++;
            if (dhcp_secs == renew_secs)
            {
                dhcp_deltickval = dhcp_delbaseval;
                dhcp_state = DHCP_RENEWING;
            }
            else if (dhcp_secs >= lease_secs)
                dhcp_state = DHCP_INIT;
        }
        return(1);
    }
    return(0);
}

/* Handle an incoming DHCP datagram */
void dhcp_handler(void)
{
    BYTE code, len, type=0;

    rx_checkoff = 1;
    if (match_byte(2) &&                // Boot reply?
        skip_byte() && match_byte(6) && // 6-byte MAC address?
        skip_data(13) &&                // Skip to..
        get_lword(&newip) &&            // ..my new IP address
        skip_data(8) &&
        match_data(myeth, MACLEN) &&
        skip_data(10 + 64 + 128))
    {
        print_lcd = print_net = FALSE;
        print_serial = TRUE;
        if (match_byte(99) && match_byte(130) &&
            match_byte(83) && match_byte(99))
        {
            while (get_byte(&code) && code!=255 && get_byte(&len))
            {
                if (code==53 && len==1)     // Message type?
                    get_byte(&type);
                else if (code==51 && len==4)// Lease time?
                    get_lword(&leasetime);
                else if (code==1 && len==4 && type==DHCP_ACK)
                    get_lword(&netmask);    // Subnet mask?
                else if (code==3 && len>=4 && type==DHCP_ACK)
                    get_lword(&router_ip);  // Router IP addr?
                else
                    skip_data(len);
            }
            if (dhcp_state==DHCP_DISCOVER && type==DHCP_OFFER)
            {
                memcpy(dhcp_hosteth, host.eth.srce, MACLEN);
                dhcp_hostip.l = remip.l;
                dhcp_newip.l = newip.l;
                dhcp_deltickval = dhcp_delbaseval;
                dhcp_state = DHCP_REQUEST;
            }
            else if ((dhcp_state==DHCP_REQUEST || dhcp_state==DHCP_RENEWING) &&
                     type==DHCP_ACK)
            {
                lease_secs = LEASE_MAXSECS;
                if (leasetime.l < LEASE_MAXSECS)
                    lease_secs = leasetime.w[0];
                if (lease_secs < LEASE_MINSECS)
                    lease_secs = LEASE_MINSECS;
                renew_secs = lease_secs >> 1;
                dhcp_secs = 0;
                myip.l = dhcp_newip.l;
                disp_myip();
                put_ser("\r\n");
                dhcp_state = DHCP_BOUND;
                net_ok = 1;
            }
        }
    }
}

/* Send a DHCP message */
SEPARATED void dhcp_tx(BYTE state)
{
    BYTE n;
    WORD sernum;

    print_lcd = print_serial = FALSE;
    print_net = TRUE;
    host.eth.pcol = PCOL_IP;
    ipcol = PUDP;
    locport = DHCPCLIENT_PORT;
    remport = DHCPSERVER_PORT;
    setpos_txin(UDPIPHDR_LEN);
    put_byte(1);                        // DHCP request
    put_byte(1);                        // Ethernet h/w, 6-byte addr
    put_byte(MACLEN);
    put_byte(0);                        // Zero hop count
    put_lword(&xid);
    put_nulls(4);
    put_lword(&myip);
    put_nulls(12);
    put_data(myeth, MACLEN);            // My hardware addr
    while (txin < 236+UDPIPHDR_LEN)
        put_byte(0);                    // Rest of hostname & bootfile name
    put_byte(99);                       // DHCP magic cookie
    put_byte(130);
    put_byte(83);
    put_byte(99);

    put_byte(53);                       // DHCP message type
    put_byte(1);
    put_byte(state & DHCP_TYPE_MASK);
    put_byte(61);                       // Client ID
    put_byte(7);
    put_byte(1);                            // ..addr type 1 (Ethernet)
    put_data(myeth, MACLEN);                // ..my MAC address
    put_byte(12);                       // Host name
    print_net = 0;                          // ..get serial num string length
    sernum = swapw(*(WORD *)&myeth[4]);
    n = disp_decword(sernum);
    print_net = 1;
    put_byte(n+1);                          // ..put out length+1
    put_byte('P');                          // ..put out 'P' prefix
    disp_decword(sernum);                   // ..put out serial number
    if (state == DHCP_REQUEST)
    {                                   // If request..
        put_byte(54);                   // ..send server ID (IP addr)
        put_byte(4);
        put_lword(&dhcp_hostip);
        put_byte(50);                   // .. and requested IP addr
        put_byte(4);
        put_lword(&dhcp_newip);
    }
    put_byte(255);                      // End of DHCP options
    if (state == DHCP_RENEWING)
    {                                   // If renewing, use unicast addr
        memcpy(host.eth.srce, dhcp_hosteth, MACLEN);
        remip.l = dhcp_hostip.l;
    }
    else
    {                                   // ..otherwise use broadcast
        memset(host.eth.srce, 0xff, MACLEN);
        memset(&remip, 0xff, sizeof(remip));
    }
    udp_xmit();
    DEBUG_PUTC('D');
}

/* Put the given number of nulls into the Tx buffer */
void put_nulls(BYTE n)
{
    while (n--)
        put_byte(0);
}

/* Randomise lower 8 bits of 16-bit number */
WORD rand_byte(WORD val)
{
    BYTE n;

    for (n=0; n<8; n++)
        val = rand_bit(val);
    return(val);
}

/* Randomise l.s. bit of 16-bit number */
WORD rand_bit(WORD val)
{
    BYTE n=0;

    if (val & 0x8000) n = !n;
    if (val & 0x4000) n = !n;
    if (val & 0x1000) n = !n;
    if (val & 0x0008) n = !n;
    return(val+val+n);
}

/* EOF */

⌨️ 快捷键说明

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