00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035 #include <stdio.h>
00036 #include <string.h>
00037 #include <uip_arp.h>
00038 #include "contiki.h"
00039 #include "contiki-net.h"
00040 #include "dhcps.h"
00041
00042 struct dhcp_msg {
00043 uint8_t op, htype, hlen, hops;
00044 uint8_t xid[4];
00045 uint16_t secs, flags;
00046 uint8_t ciaddr[4];
00047 uint8_t yiaddr[4];
00048 uint8_t siaddr[4];
00049 uint8_t giaddr[4];
00050 uint8_t chaddr[16];
00051 #ifndef UIP_CONF_DHCP_LIGHT
00052 uint8_t sname[64];
00053 uint8_t file[128];
00054 #endif
00055 uint8_t options[312];
00056 } CC_BYTE_ALIGNED;
00057
00058 #define BOOTP_BROADCAST 0x8000
00059
00060 #define DHCP_REQUEST 1
00061 #define DHCP_REPLY 2
00062 #define DHCP_HTYPE_ETHERNET 1
00063 #define DHCP_HLEN_ETHERNET 6
00064 #define DHCP_MSG_LEN 236
00065
00066 #define DHCPS_SERVER_PORT 67
00067 #define DHCPS_CLIENT_PORT 68
00068
00069 #define DHCPDISCOVER 1
00070 #define DHCPOFFER 2
00071 #define DHCPREQUEST 3
00072 #define DHCPDECLINE 4
00073 #define DHCPACK 5
00074 #define DHCPNAK 6
00075 #define DHCPRELEASE 7
00076 #define DHCPINFORM 8
00077
00078 #define DHCP_OPTION_SUBNET_MASK 1
00079 #define DHCP_OPTION_ROUTER 3
00080 #define DHCP_OPTION_DNS_SERVER 6
00081 #define DHCP_OPTION_REQ_IPADDR 50
00082 #define DHCP_OPTION_LEASE_TIME 51
00083 #define DHCP_OPTION_MSG_TYPE 53
00084 #define DHCP_OPTION_SERVER_ID 54
00085 #define DHCP_OPTION_REQ_LIST 55
00086 #define DHCP_OPTION_END 255
00087
00088
00089
00090 #define LEASE_FLAGS_ALLOCATED 0x01
00091 #define LEASE_FLAGS_VALID 0x02
00092
00093
00094
00095 static const struct dhcps_config *config;
00096
00097
00098 static uint8_t *
00099 find_option(uint8_t option)
00100 {
00101 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00102 uint8_t *optptr = &m->options[4];
00103 uint8_t *end = (uint8_t*)uip_appdata + uip_datalen();
00104 while(optptr < end && *optptr != DHCP_OPTION_END) {
00105 if(*optptr == option) {
00106 return optptr;
00107 }
00108 optptr += optptr[1] + 2;
00109 }
00110 return NULL;
00111 }
00112
00113 static const uint8_t magic_cookie[4] = {99, 130, 83, 99};
00114
00115 static int
00116 check_cookie(void)
00117 {
00118 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00119 return memcmp(m->options, magic_cookie, 4) == 0;
00120 }
00121
00122
00123 static struct dhcps_client_lease *
00124 lookup_lease_mac(const uint8_t *chaddr, uint8_t hlen)
00125 {
00126 struct dhcps_client_lease *lease = config->leases;
00127 struct dhcps_client_lease *end = config->leases + config->num_leases;
00128 while(lease != end) {
00129 if (lease->flags & LEASE_FLAGS_VALID
00130 && memcmp(lease->chaddr, chaddr, hlen) == 0) {
00131 return lease;
00132 }
00133 lease++;
00134 }
00135 return NULL;
00136 }
00137
00138 static struct dhcps_client_lease *
00139 lookup_lease_ip(const uip_ipaddr_t *ip)
00140 {
00141 struct dhcps_client_lease *lease = config->leases;
00142 struct dhcps_client_lease *end = config->leases + config->num_leases;
00143 while(lease != end) {
00144 if (uip_ipaddr_cmp(&lease->ipaddr, ip)) {
00145 return lease;
00146 }
00147 lease++;
00148 }
00149 return NULL;
00150 }
00151
00152 static struct dhcps_client_lease *
00153 find_free_lease(void)
00154 {
00155 struct dhcps_client_lease *found = NULL;
00156 struct dhcps_client_lease *lease = config->leases;
00157 struct dhcps_client_lease *end = config->leases + config->num_leases;
00158 while(lease != end) {
00159 if (!(lease->flags & LEASE_FLAGS_VALID)) return lease;
00160 if (!(lease->flags & LEASE_FLAGS_ALLOCATED)) found = lease;
00161 lease++;
00162 }
00163 return found;
00164 }
00165
00166 struct dhcps_client_lease *
00167 init_lease(struct dhcps_client_lease *lease,
00168 const uint8_t *chaddr, uint8_t hlen)
00169 {
00170 if (lease) {
00171 memcpy(lease->chaddr, chaddr, hlen);
00172 lease->flags = LEASE_FLAGS_VALID;
00173 }
00174 return lease;
00175 }
00176
00177
00178 static struct dhcps_client_lease *
00179 choose_address()
00180 {
00181 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00182 struct dhcps_client_lease *lease;
00183 lease = lookup_lease_mac(m->chaddr, m->hlen);
00184 if (lease) {
00185 return lease;
00186 }
00187 {
00188 uint8_t *opt;
00189 opt = find_option(DHCP_OPTION_REQ_IPADDR);
00190 if (opt && (lease = lookup_lease_ip((uip_ipaddr_t*)&opt[2]))
00191 && !(lease->flags & LEASE_FLAGS_ALLOCATED)) {
00192 return init_lease(lease, m->chaddr,m->hlen);
00193 }
00194 }
00195 lease = find_free_lease();
00196 if (lease) {
00197 return init_lease(lease, m->chaddr,m->hlen);
00198 }
00199 return NULL;
00200 }
00201
00202 static struct dhcps_client_lease *
00203 allocate_address()
00204 {
00205 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00206 struct dhcps_client_lease *lease;
00207 lease = lookup_lease_mac(m->chaddr, m->hlen);
00208 if (!lease) {
00209 uint8_t *opt;
00210 opt = find_option(DHCP_OPTION_REQ_IPADDR);
00211 if (!(opt && (lease = lookup_lease_ip((uip_ipaddr_t*)&opt[2]))
00212 && !(lease->flags & LEASE_FLAGS_ALLOCATED))) {
00213 return NULL;
00214 }
00215 }
00216 lease->lease_end = clock_seconds()+config->default_lease_time;
00217 lease->flags |= LEASE_FLAGS_ALLOCATED;
00218 return lease;
00219 }
00220
00221 static struct dhcps_client_lease *
00222 release_address()
00223 {
00224 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00225 struct dhcps_client_lease *lease;
00226 lease = lookup_lease_mac(m->chaddr, m->hlen);
00227 if (!lease) {
00228 return NULL;
00229 }
00230 lease->flags &= ~LEASE_FLAGS_ALLOCATED;
00231 return lease;
00232 }
00233
00234
00235 static uint8_t *
00236 add_msg_type(uint8_t *optptr, uint8_t type)
00237 {
00238 *optptr++ = DHCP_OPTION_MSG_TYPE;
00239 *optptr++ = 1;
00240 *optptr++ = type;
00241 return optptr;
00242 }
00243
00244 static uint8_t *
00245 add_server_id(uint8_t *optptr)
00246 {
00247 *optptr++ = DHCP_OPTION_SERVER_ID;
00248 *optptr++ = 4;
00249 memcpy(optptr, &uip_hostaddr, 4);
00250 return optptr + 4;
00251 }
00252
00253 static uint8_t *
00254 add_lease_time(uint8_t *optptr)
00255 {
00256 uint32_t lt;
00257 *optptr++ = DHCP_OPTION_LEASE_TIME;
00258 *optptr++ = 4;
00259 lt = UIP_HTONL(config->default_lease_time);
00260 memcpy(optptr, <, 4);
00261 return optptr + 4;
00262 }
00263
00264
00265 static uint8_t *
00266 add_end(uint8_t *optptr)
00267 {
00268 *optptr++ = DHCP_OPTION_END;
00269 return optptr;
00270 }
00271
00272 static uint8_t *
00273 add_config(uint8_t *optptr)
00274 {
00275 if (config->flags & DHCP_CONF_NETMASK) {
00276 *optptr++ = DHCP_OPTION_SUBNET_MASK;
00277 *optptr++ = 4;
00278 memcpy(optptr, &config->netmask, 4);
00279 optptr += 4;
00280 }
00281 if (config->flags & DHCP_CONF_DNSADDR) {
00282 *optptr++ = DHCP_OPTION_DNS_SERVER;
00283 *optptr++ = 4;
00284 memcpy(optptr, &config->dnsaddr, 4);
00285 optptr += 4;
00286 }
00287 if (config->flags & DHCP_CONF_DEFAULT_ROUTER) {
00288 *optptr++ = DHCP_OPTION_ROUTER;
00289 *optptr++ = 4;
00290 memcpy(optptr, &config->default_router, 4);
00291 optptr += 4;
00292 }
00293 return optptr;
00294 }
00295
00296 static void
00297 create_msg(CC_REGISTER_ARG struct dhcp_msg *m)
00298 {
00299 m->op = DHCP_REPLY;
00300
00301
00302
00303 m->hops = 0;
00304 m->secs = 0;
00305 memcpy(m->siaddr, &uip_hostaddr, 4);
00306 m->sname[0] = '\0';
00307 m->file[0] = '\0';
00308 memcpy(m->options, magic_cookie, sizeof(magic_cookie));
00309 }
00310
00311 static uip_ipaddr_t any_addr;
00312 static uip_ipaddr_t bcast_addr;
00313
00314
00315 static void
00316 send_offer(struct uip_udp_conn *conn, struct dhcps_client_lease *lease)
00317 {
00318 u8_t *end;
00319 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00320
00321 create_msg(m);
00322 memcpy(&m->yiaddr, &lease->ipaddr,4);
00323
00324 end = add_msg_type(&m->options[4], DHCPOFFER);
00325 end = add_server_id(end);
00326 end = add_lease_time(end);
00327 end = add_config(end);
00328 end = add_end(end);
00329 uip_ipaddr_copy(&conn->ripaddr, &bcast_addr);
00330 uip_send(uip_appdata, (int)(end - (u8_t *)uip_appdata));
00331 }
00332
00333 static void
00334 send_ack(struct uip_udp_conn *conn, struct dhcps_client_lease *lease)
00335 {
00336 u8_t *end;
00337 uip_ipaddr_t ciaddr;
00338 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00339
00340 create_msg(m);
00341 memcpy(&m->yiaddr, &lease->ipaddr,4);
00342
00343 end = add_msg_type(&m->options[4], DHCPACK);
00344 end = add_server_id(end);
00345 end = add_lease_time(end);
00346 end = add_config(end);
00347 end = add_end(end);
00348 memcpy(&ciaddr, &lease->ipaddr,4);
00349 uip_ipaddr_copy(&conn->ripaddr, &bcast_addr);
00350 uip_send(uip_appdata, (int)(end - (u8_t *)uip_appdata));
00351 printf("ACK\n");
00352 }
00353 static void
00354 send_nack(struct uip_udp_conn *conn)
00355 {
00356 u8_t *end;
00357 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00358
00359 create_msg(m);
00360 memset(&m->yiaddr, 0, 4);
00361
00362 end = add_msg_type(&m->options[4], DHCPNAK);
00363 end = add_server_id(end);
00364 end = add_end(end);
00365
00366 uip_ipaddr_copy(&conn->ripaddr, &bcast_addr);
00367 uip_send(uip_appdata, (int)(end - (u8_t *)uip_appdata));
00368 printf("NACK\n");
00369 }
00370
00371
00372 PROCESS(dhcp_server_process, "DHCP server");
00373
00374
00375 PROCESS_THREAD(dhcp_server_process, ev , data)
00376 {
00377 static struct uip_udp_conn *conn;
00378 static struct uip_udp_conn *send_conn;
00379 static struct dhcps_client_lease *lease;
00380 PROCESS_BEGIN();
00381 printf("DHCP server starting\n");
00382 uip_ipaddr(&any_addr, 0,0,0,0);
00383 uip_ipaddr(&bcast_addr, 255,255,255,255);
00384 conn = udp_new(&any_addr, UIP_HTONS(DHCPS_CLIENT_PORT), NULL);
00385 if (!conn) goto exit;
00386 send_conn = udp_new(&bcast_addr, UIP_HTONS(DHCPS_CLIENT_PORT), NULL);
00387 if (!send_conn) goto exit;
00388
00389 uip_udp_bind(conn, UIP_HTONS(DHCPS_SERVER_PORT));
00390 uip_udp_bind(send_conn, UIP_HTONS(DHCPS_SERVER_PORT));
00391 while(1) {
00392 PROCESS_WAIT_EVENT();
00393 if(ev == tcpip_event) {
00394 if (uip_newdata()) {
00395 struct dhcp_msg *m = (struct dhcp_msg *)uip_appdata;
00396 struct uip_udpip_hdr *header = (struct uip_udpip_hdr *)&uip_buf[UIP_LLH_LEN];
00397
00398 if (m->op == DHCP_REQUEST && check_cookie() && m->hlen <= MAX_HLEN) {
00399 uint8_t *opt = find_option(DHCP_OPTION_MSG_TYPE);
00400 if (opt) {
00401 uint8_t mtype = opt[2];
00402 if (opt[2] == DHCPDISCOVER) {
00403 printf("Discover\n");
00404 lease = choose_address();
00405 if (lease) {
00406 lease->lease_end = clock_seconds()+config->default_lease_time;
00407 tcpip_poll_udp(send_conn);
00408 PROCESS_WAIT_EVENT_UNTIL(uip_poll());
00409 send_offer(conn,lease);
00410 }
00411 } else {
00412 uint8_t *opt = find_option(DHCP_OPTION_SERVER_ID);
00413 if (!opt || uip_ipaddr_cmp((uip_ipaddr_t*)&opt[2], &uip_hostaddr)) {
00414 if (mtype == DHCPREQUEST) {
00415 printf("Request\n");
00416 lease = allocate_address();
00417 tcpip_poll_udp(send_conn);
00418 PROCESS_WAIT_EVENT_UNTIL(uip_poll());
00419 if (!lease) {
00420 send_nack(send_conn);
00421 } else {
00422 send_ack(send_conn,lease);
00423 }
00424 } else if (mtype == DHCPRELEASE) {
00425 printf("Release\n");
00426 release_address();
00427 } else if (mtype == DHCPDECLINE) {
00428 printf("Decline\n");
00429 } else if (mtype == DHCPINFORM) {
00430 printf("Inform\n");
00431 }
00432 }
00433 }
00434 }
00435 }
00436 }
00437 } else if (uip_poll()) {
00438
00439 }
00440 }
00441 exit:
00442 printf("DHCP server exiting\n");
00443 PROCESS_END();
00444 }
00445
00446 void
00447 dhcps_init(const struct dhcps_config *conf)
00448 {
00449 config = conf;
00450 process_start(&dhcp_server_process,NULL);
00451 }