123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- /*
- * Copyright (c) 2005, Swedish Institute of Computer Science
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. Neither the name of the Institute nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * This file is part of the uIP TCP/IP stack
- *
- * @(#)$Id: dhcpc.c,v 1.2 2006/06/11 21:46:37 adam Exp $
- */
- #include <stdio.h>
- #include <string.h>
- #include "uip.h"
- #include "dhcpc.h"
- #include "timer.h"
- #include "pt.h"
- #define STATE_INITIAL 0
- #define STATE_SENDING 1
- #define STATE_OFFER_RECEIVED 2
- #define STATE_CONFIG_RECEIVED 3
- static struct dhcpc_state s;
- struct dhcp_msg {
- u8_t op, htype, hlen, hops;
- u8_t xid[4];
- u16_t secs, flags;
- u8_t ciaddr[4];
- u8_t yiaddr[4];
- u8_t siaddr[4];
- u8_t giaddr[4];
- u8_t chaddr[16];
- #ifndef UIP_CONF_DHCP_LIGHT
- u8_t sname[64];
- u8_t file[128];
- #endif
- u8_t options[312];
- };
- #define BOOTP_BROADCAST 0x8000
- #define DHCP_REQUEST 1
- #define DHCP_REPLY 2
- #define DHCP_HTYPE_ETHERNET 1
- #define DHCP_HLEN_ETHERNET 6
- #define DHCP_MSG_LEN 236
- #define DHCPC_SERVER_PORT 67
- #define DHCPC_CLIENT_PORT 68
- #define DHCPDISCOVER 1
- #define DHCPOFFER 2
- #define DHCPREQUEST 3
- #define DHCPDECLINE 4
- #define DHCPACK 5
- #define DHCPNAK 6
- #define DHCPRELEASE 7
- #define DHCP_OPTION_SUBNET_MASK 1
- #define DHCP_OPTION_ROUTER 3
- #define DHCP_OPTION_DNS_SERVER 6
- #define DHCP_OPTION_REQ_IPADDR 50
- #define DHCP_OPTION_LEASE_TIME 51
- #define DHCP_OPTION_MSG_TYPE 53
- #define DHCP_OPTION_SERVER_ID 54
- #define DHCP_OPTION_REQ_LIST 55
- #define DHCP_OPTION_END 255
- static const u8_t xid[4] = {0xad, 0xde, 0x12, 0x23};
- static const u8_t magic_cookie[4] = {99, 130, 83, 99};
- /*---------------------------------------------------------------------------*/
- static u8_t *
- add_msg_type(u8_t *optptr, u8_t type)
- {
- *optptr++ = DHCP_OPTION_MSG_TYPE;
- *optptr++ = 1;
- *optptr++ = type;
- return optptr;
- }
- /*---------------------------------------------------------------------------*/
- static u8_t *
- add_server_id(u8_t *optptr)
- {
- *optptr++ = DHCP_OPTION_SERVER_ID;
- *optptr++ = 4;
- memcpy(optptr, s.serverid, 4);
- return optptr + 4;
- }
- /*---------------------------------------------------------------------------*/
- static u8_t *
- add_req_ipaddr(u8_t *optptr)
- {
- *optptr++ = DHCP_OPTION_REQ_IPADDR;
- *optptr++ = 4;
- memcpy(optptr, s.ipaddr, 4);
- return optptr + 4;
- }
- /*---------------------------------------------------------------------------*/
- static u8_t *
- add_req_options(u8_t *optptr)
- {
- *optptr++ = DHCP_OPTION_REQ_LIST;
- *optptr++ = 3;
- *optptr++ = DHCP_OPTION_SUBNET_MASK;
- *optptr++ = DHCP_OPTION_ROUTER;
- *optptr++ = DHCP_OPTION_DNS_SERVER;
- return optptr;
- }
- /*---------------------------------------------------------------------------*/
- static u8_t *
- add_end(u8_t *optptr)
- {
- *optptr++ = DHCP_OPTION_END;
- return optptr;
- }
- /*---------------------------------------------------------------------------*/
- static void
- create_msg(register struct dhcp_msg *m)
- {
- m->op = DHCP_REQUEST;
- m->htype = DHCP_HTYPE_ETHERNET;
- m->hlen = s.mac_len;
- m->hops = 0;
- memcpy(m->xid, xid, sizeof(m->xid));
- m->secs = 0;
- m->flags = HTONS(BOOTP_BROADCAST); /* Broadcast bit. */
- /* uip_ipaddr_copy(m->ciaddr, uip_hostaddr);*/
- memcpy(m->ciaddr, uip_hostaddr, sizeof(m->ciaddr));
- memset(m->yiaddr, 0, sizeof(m->yiaddr));
- memset(m->siaddr, 0, sizeof(m->siaddr));
- memset(m->giaddr, 0, sizeof(m->giaddr));
- memcpy(m->chaddr, s.mac_addr, s.mac_len);
- memset(&m->chaddr[s.mac_len], 0, sizeof(m->chaddr) - s.mac_len);
- #ifndef UIP_CONF_DHCP_LIGHT
- memset(m->sname, 0, sizeof(m->sname));
- memset(m->file, 0, sizeof(m->file));
- #endif
- memcpy(m->options, magic_cookie, sizeof(magic_cookie));
- }
- /*---------------------------------------------------------------------------*/
- static void
- send_discover(void)
- {
- u8_t *end;
- struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
- create_msg(m);
- end = add_msg_type(&m->options[4], DHCPDISCOVER);
- end = add_req_options(end);
- end = add_end(end);
- uip_send(uip_appdata, end - (u8_t *)uip_appdata);
- }
- /*---------------------------------------------------------------------------*/
- static void
- send_request(void)
- {
- u8_t *end;
- struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
- create_msg(m);
-
- end = add_msg_type(&m->options[4], DHCPREQUEST);
- end = add_server_id(end);
- end = add_req_ipaddr(end);
- end = add_end(end);
-
- uip_send(uip_appdata, end - (u8_t *)uip_appdata);
- }
- /*---------------------------------------------------------------------------*/
- static u8_t
- parse_options(u8_t *optptr, int len)
- {
- u8_t *end = optptr + len;
- u8_t type = 0;
- while(optptr < end) {
- switch(*optptr) {
- case DHCP_OPTION_SUBNET_MASK:
- memcpy(s.netmask, optptr + 2, 4);
- break;
- case DHCP_OPTION_ROUTER:
- memcpy(s.default_router, optptr + 2, 4);
- break;
- case DHCP_OPTION_DNS_SERVER:
- memcpy(s.dnsaddr, optptr + 2, 4);
- break;
- case DHCP_OPTION_MSG_TYPE:
- type = *(optptr + 2);
- break;
- case DHCP_OPTION_SERVER_ID:
- memcpy(s.serverid, optptr + 2, 4);
- break;
- case DHCP_OPTION_LEASE_TIME:
- memcpy(s.lease_time, optptr + 2, 4);
- break;
- case DHCP_OPTION_END:
- return type;
- }
- optptr += optptr[1] + 2;
- }
- return type;
- }
- /*---------------------------------------------------------------------------*/
- static u8_t
- parse_msg(void)
- {
- struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
-
- if(m->op == DHCP_REPLY &&
- memcmp(m->xid, xid, sizeof(xid)) == 0 &&
- memcmp(m->chaddr, s.mac_addr, s.mac_len) == 0) {
- memcpy(s.ipaddr, m->yiaddr, 4);
- return parse_options(&m->options[4], uip_datalen());
- }
- return 0;
- }
- /*---------------------------------------------------------------------------*/
- static
- PT_THREAD(handle_dhcp(void))
- {
- PT_BEGIN(&s.pt);
-
- /* try_again:*/
- s.state = STATE_SENDING;
- s.ticks = CLOCK_SECOND;
- do {
- send_discover();
- timer_set(&s.timer, s.ticks);
- PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
- if(uip_newdata() && parse_msg() == DHCPOFFER) {
- s.state = STATE_OFFER_RECEIVED;
- break;
- }
- if(s.ticks < CLOCK_SECOND * 60) {
- s.ticks *= 2;
- }
- } while(s.state != STATE_OFFER_RECEIVED);
-
- s.ticks = CLOCK_SECOND;
- do {
- send_request();
- timer_set(&s.timer, s.ticks);
- PT_WAIT_UNTIL(&s.pt, uip_newdata() || timer_expired(&s.timer));
- if(uip_newdata() && parse_msg() == DHCPACK) {
- s.state = STATE_CONFIG_RECEIVED;
- break;
- }
- if(s.ticks <= CLOCK_SECOND * 10) {
- s.ticks += CLOCK_SECOND;
- } else {
- PT_RESTART(&s.pt);
- }
- } while(s.state != STATE_CONFIG_RECEIVED);
-
- #if 0
- printf("Got IP address %d.%d.%d.%d\n",
- uip_ipaddr1(s.ipaddr), uip_ipaddr2(s.ipaddr),
- uip_ipaddr3(s.ipaddr), uip_ipaddr4(s.ipaddr));
- printf("Got netmask %d.%d.%d.%d\n",
- uip_ipaddr1(s.netmask), uip_ipaddr2(s.netmask),
- uip_ipaddr3(s.netmask), uip_ipaddr4(s.netmask));
- printf("Got DNS server %d.%d.%d.%d\n",
- uip_ipaddr1(s.dnsaddr), uip_ipaddr2(s.dnsaddr),
- uip_ipaddr3(s.dnsaddr), uip_ipaddr4(s.dnsaddr));
- printf("Got default router %d.%d.%d.%d\n",
- uip_ipaddr1(s.default_router), uip_ipaddr2(s.default_router),
- uip_ipaddr3(s.default_router), uip_ipaddr4(s.default_router));
- printf("Lease expires in %ld seconds\n",
- ntohs(s.lease_time[0])*65536ul + ntohs(s.lease_time[1]));
- #endif
- dhcpc_configured(&s);
-
- /* timer_stop(&s.timer);*/
- /*
- * PT_END restarts the thread so we do this instead. Eventually we
- * should reacquire expired leases here.
- */
- while(1) {
- PT_YIELD(&s.pt);
- }
- PT_END(&s.pt);
- }
- /*---------------------------------------------------------------------------*/
- void
- dhcpc_init(const void *mac_addr, int mac_len)
- {
- uip_ipaddr_t addr;
-
- s.mac_addr = mac_addr;
- s.mac_len = mac_len;
- s.state = STATE_INITIAL;
- uip_ipaddr(addr, 255,255,255,255);
- s.conn = uip_udp_new(&addr, HTONS(DHCPC_SERVER_PORT));
- if(s.conn != NULL) {
- uip_udp_bind(s.conn, HTONS(DHCPC_CLIENT_PORT));
- }
- PT_INIT(&s.pt);
- }
- /*---------------------------------------------------------------------------*/
- void
- dhcpc_appcall(void)
- {
- handle_dhcp();
- }
- /*---------------------------------------------------------------------------*/
- void
- dhcpc_request(void)
- {
- u16_t ipaddr[2];
-
- if(s.state == STATE_INITIAL) {
- uip_ipaddr(ipaddr, 0,0,0,0);
- uip_sethostaddr(ipaddr);
- /* handle_dhcp(PROCESS_EVENT_NONE, NULL);*/
- }
- }
- /*---------------------------------------------------------------------------*/
|