CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2
Fork of USB_Ethernet by
pico_dhcp_client.c
00001 /********************************************************************* 00002 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. 00003 See LICENSE and COPYING for usage. 00004 00005 Authors: Frederik Van Slycken, Kristof Roelants 00006 *********************************************************************/ 00007 00008 #include "pico_dhcp_client.h" 00009 #include "pico_stack.h" 00010 #include "pico_config.h" 00011 #include "pico_device.h" 00012 #include "pico_ipv4.h" 00013 #include "pico_socket.h" 00014 00015 #ifdef PICO_SUPPORT_DHCPC 00016 00017 /*********** 00018 * structs * 00019 ***********/ 00020 00021 static uint8_t dhcp_client_mutex = 1; /* to serialize client negotations if multiple devices */ 00022 00023 struct dhcp_timer_param{ 00024 uint16_t type; 00025 struct pico_dhcp_client_cookie* cli; 00026 int valid; 00027 }; 00028 00029 struct pico_dhcp_client_cookie 00030 { 00031 uint32_t xid; 00032 uint32_t *xid_user; 00033 struct pico_ip4 address; 00034 struct pico_ip4 netmask; 00035 struct pico_ip4 gateway; 00036 struct pico_ip4 nameserver; 00037 struct pico_ip4 server_id; 00038 uint32_t lease_time; 00039 uint32_t T1; 00040 uint32_t T2; 00041 struct pico_socket* socket; 00042 int connected; 00043 struct pico_device* device; 00044 unsigned long start_time; 00045 int attempt; 00046 enum dhcp_negotiation_state state; 00047 void (*cb)(void* cli, int code); 00048 struct dhcp_timer_param* timer_param_1; 00049 struct dhcp_timer_param* timer_param_2; 00050 struct dhcp_timer_param* timer_param_lease; 00051 struct dhcp_timer_param* timer_param_retransmit; 00052 int link_added; 00053 }; 00054 00055 static int dhcp_cookies_cmp(void *ka, void *kb) 00056 { 00057 struct pico_dhcp_client_cookie *a = ka, *b = kb; 00058 if (a->xid < b->xid) 00059 return -1; 00060 else if (a->xid > b->xid) 00061 return 1; 00062 else 00063 return 0; 00064 } 00065 PICO_TREE_DECLARE(DHCPCookies, dhcp_cookies_cmp); 00066 00067 /************************* 00068 * function declarations * 00069 *************************/ 00070 static void pico_dhcp_state_machine(int type, struct pico_dhcp_client_cookie* cli, uint8_t* data, int len); 00071 static void pico_dhcp_reinitiate_negotiation(unsigned long now, void *arg); 00072 00073 //cb 00074 static void pico_dhcp_wakeup(uint16_t ev, struct pico_socket *s); 00075 static void dhcp_timer_cb(unsigned long tick, void* param); 00076 00077 //util 00078 static void pico_dhcp_retry(struct pico_dhcp_client_cookie *client); 00079 static int dhclient_send(struct pico_dhcp_client_cookie *cli, uint8_t msg_type); 00080 static int pico_dhcp_verify_and_identify_type(uint8_t* data, int len, struct pico_dhcp_client_cookie *cli); 00081 static int init_cookie(struct pico_dhcp_client_cookie* cli); 00082 static struct pico_dhcp_client_cookie* get_cookie_by_xid(uint32_t xid); 00083 static uint32_t get_xid(uint8_t* data); 00084 00085 //fsm functions 00086 static int recv_offer(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); 00087 static int recv_ack(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); 00088 static int renew(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); 00089 static int reset(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); 00090 static int retransmit(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); 00091 00092 //fsm implementation 00093 static void pico_dhcp_state_machine(int type, struct pico_dhcp_client_cookie* cli, uint8_t* data, int len); 00094 00095 /*************** 00096 * entry point * 00097 ***************/ 00098 00099 static uint32_t pico_dhcp_execute_init(struct pico_dhcp_client_cookie *cli) 00100 { 00101 if (!dhcp_client_mutex) { 00102 pico_timer_add(3000, pico_dhcp_reinitiate_negotiation, cli); 00103 return 0; 00104 } 00105 dhcp_client_mutex--; 00106 00107 if (init_cookie(cli) < 0) 00108 return -1; 00109 00110 dbg("DHCPC: cookie with xid %u\n", cli->xid); 00111 00112 if (pico_tree_insert(&DHCPCookies, cli)) { 00113 pico_err = PICO_ERR_EAGAIN; 00114 if(cli->cb != NULL) { 00115 cli->cb(cli, PICO_DHCP_ERROR); 00116 } 00117 pico_free(cli); 00118 return -1; /* Element key already exists */ 00119 } 00120 00121 if (dhclient_send(cli, PICO_DHCP_MSG_DISCOVER) < 0) 00122 return -1; 00123 00124 return 0; 00125 } 00126 00127 /* returns a pointer to the client cookie. The user should pass this pointer every time he calls a dhcp-function. This is so that we can (one day) support dhcp on multiple interfaces */ 00128 int pico_dhcp_initiate_negotiation(struct pico_device *device, void (*callback)(void *cli, int code), uint32_t *xid) 00129 { 00130 struct pico_dhcp_client_cookie *cli; 00131 00132 if(!device || !callback || !xid){ 00133 pico_err = PICO_ERR_EINVAL; 00134 return -1; 00135 } 00136 cli = pico_zalloc(sizeof(struct pico_dhcp_client_cookie)); 00137 if(!cli){ 00138 pico_err = PICO_ERR_ENOMEM; 00139 return -1; 00140 } 00141 00142 cli->device = device; 00143 cli->cb = callback; 00144 cli->xid_user = xid; 00145 *(cli->xid_user) = 0; 00146 00147 return pico_dhcp_execute_init(cli); 00148 } 00149 00150 static void pico_dhcp_reinitiate_negotiation(unsigned long now, void *arg) 00151 { 00152 struct pico_dhcp_client_cookie *cli = (struct pico_dhcp_client_cookie *) arg; 00153 00154 pico_dhcp_execute_init(cli); 00155 00156 return; 00157 } 00158 00159 /******************** 00160 * access functions * 00161 ********************/ 00162 00163 struct pico_ip4 pico_dhcp_get_address(void* cli) 00164 { 00165 return ((struct pico_dhcp_client_cookie*)cli)->address; 00166 } 00167 00168 struct pico_ip4 pico_dhcp_get_gateway(void* cli) 00169 { 00170 return ((struct pico_dhcp_client_cookie*)cli)->gateway; 00171 } 00172 00173 struct pico_ip4 pico_dhcp_get_nameserver(void* cli) 00174 { 00175 return ((struct pico_dhcp_client_cookie*)cli)->nameserver; 00176 } 00177 00178 /************* 00179 * callbacks * 00180 *************/ 00181 00182 static void pico_dhcp_wakeup(uint16_t ev, struct pico_socket *s) 00183 { 00184 uint8_t buf[DHCPC_DATAGRAM_SIZE]; 00185 int r=0; 00186 uint32_t peer; 00187 uint16_t port; 00188 int type; 00189 00190 struct pico_dhcp_client_cookie *cli; 00191 dbg("DHCPC: called dhcp_wakeup\n"); 00192 if (ev == PICO_SOCK_EV_RD) { 00193 do { 00194 r = pico_socket_recvfrom(s, buf, DHCPC_DATAGRAM_SIZE, &peer, &port); 00195 cli = get_cookie_by_xid(get_xid(buf)); 00196 if(cli == NULL) 00197 return; 00198 if (r > 0 && port == PICO_DHCPD_PORT) { 00199 type = pico_dhcp_verify_and_identify_type(buf, r, cli); 00200 pico_dhcp_state_machine(type, cli, buf, r); 00201 } 00202 } while(r>0); 00203 } 00204 } 00205 00206 static void dhcp_timer_cb(unsigned long tick, void* param) 00207 { 00208 struct dhcp_timer_param* param2 = (struct dhcp_timer_param*) param; 00209 if(param2->valid == 1){ 00210 //dbg("called timer cb on active timer type %d\n",param2->type); 00211 pico_dhcp_state_machine(param2->type, param2->cli, NULL, 0); 00212 } 00213 if(param2->cli->timer_param_1 == param){ 00214 param2->cli->timer_param_1 = NULL; 00215 } 00216 if(param2->cli->timer_param_2 == param){ 00217 param2->cli->timer_param_2 = NULL; 00218 } 00219 if(param2->cli->timer_param_lease == param){ 00220 param2->cli->timer_param_lease = NULL; 00221 } 00222 if(param2->cli->timer_param_retransmit == param){ 00223 param2->cli->timer_param_retransmit = NULL; 00224 } 00225 00226 pico_free(param); 00227 00228 } 00229 /***************** 00230 * fsm functions * 00231 *****************/ 00232 00233 static int recv_offer(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len) 00234 { 00235 struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) data; 00236 uint8_t *nextopt, opt_data[20], opt_type; 00237 int opt_len = 20; 00238 uint8_t msg_type = 0xFF; 00239 int T1_set = 0; 00240 int T2_set = 0; 00241 00242 cli->address.addr = dhdr->yiaddr; 00243 00244 opt_type = dhcp_get_next_option(dhdr->options, opt_data, &opt_len, &nextopt); 00245 while (opt_type != PICO_DHCPOPT_END) { 00246 if (opt_type == PICO_DHCPOPT_MSGTYPE) 00247 msg_type = opt_data[0]; 00248 if ((opt_type == PICO_DHCPOPT_LEASETIME) && (opt_len == 4)){ 00249 memcpy(&cli->lease_time, opt_data, 4); 00250 cli->lease_time = long_be(cli->lease_time); 00251 } 00252 if ((opt_type == PICO_DHCPOPT_RENEWALTIME) && (opt_len == 4)){ 00253 memcpy(&cli->T1, opt_data, 4); 00254 cli->T1 = long_be(cli->T1); 00255 T1_set =1; 00256 } 00257 if ((opt_type == PICO_DHCPOPT_REBINDINGTIME) && (opt_len == 4)){ 00258 memcpy(&cli->T2, opt_data, 4); 00259 cli->T2 = long_be(cli->T2); 00260 T2_set =1; 00261 } 00262 if ((opt_type == PICO_DHCPOPT_ROUTER) && (opt_len == 4)) //XXX assuming only one router will be advertised... 00263 memcpy(&cli->gateway.addr, opt_data, 4); 00264 if ((opt_type == PICO_DHCPOPT_DNS) && (opt_len == 4)) 00265 memcpy(&cli->nameserver.addr, opt_data, 4); 00266 if ((opt_type == PICO_DHCPOPT_NETMASK) && (opt_len == 4)) 00267 memcpy(&cli->netmask.addr, opt_data, 4); 00268 if ((opt_type == PICO_DHCPOPT_SERVERID) && (opt_len == 4)) 00269 memcpy(&cli->server_id.addr, opt_data, 4); 00270 if (opt_type == PICO_DHCPOPT_OPTIONOVERLOAD) 00271 dbg("DHCPC: WARNING: option overload present (not processed)"); 00272 00273 opt_len = 20; 00274 opt_type = dhcp_get_next_option(NULL, opt_data, &opt_len, &nextopt); 00275 } 00276 00277 /* default values for T1 and T2 if necessary */ 00278 if(T1_set != 1) 00279 cli->T1 = cli->lease_time >> 1; 00280 if(T2_set != 1) 00281 cli->T2 = (cli->lease_time * 875) / 1000; 00282 00283 00284 00285 if ((msg_type != PICO_DHCP_MSG_OFFER) || !cli->lease_time || !cli->netmask.addr || !cli->server_id.addr ) 00286 return 0; 00287 00288 00289 dhclient_send(cli, PICO_DHCP_MSG_REQUEST); 00290 cli->state = DHCPSTATE_REQUEST; 00291 return 1; 00292 } 00293 00294 static int recv_ack(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len) 00295 { 00296 struct pico_ip4 address = {0}; 00297 00298 if(cli->link_added == 0){ 00299 /* close the socket bound on address 0.0.0.0 */ 00300 pico_socket_close(cli->socket); 00301 cli->socket = NULL; 00302 pico_ipv4_link_del(cli->device, address); 00303 pico_ipv4_link_add(cli->device, cli->address, cli->netmask); 00304 cli->link_added = 1; 00305 } 00306 cli->state = DHCPSTATE_BOUND; 00307 00308 dbg("DHCPC: T1: %d\n",cli->T1); 00309 dbg("DHCPC: T2: %d\n",cli->T2); 00310 dbg("DHCPC: lease time: %d\n",cli->lease_time); 00311 00312 if(cli->timer_param_1) 00313 cli->timer_param_1->valid = 0; 00314 if(cli->timer_param_2) 00315 cli->timer_param_2->valid = 0; 00316 if(cli->timer_param_lease) 00317 cli->timer_param_lease->valid = 0; 00318 if(cli->timer_param_retransmit) 00319 cli->timer_param_retransmit->valid = 0; 00320 00321 00322 cli->timer_param_1 = pico_zalloc(sizeof(struct dhcp_timer_param)); 00323 if(!cli->timer_param_1){ 00324 if(cli->cb != NULL){ 00325 pico_err = PICO_ERR_ENOMEM; 00326 cli->cb(cli, PICO_DHCP_ERROR); 00327 } 00328 return 0; 00329 } 00330 cli->timer_param_2 = pico_zalloc(sizeof(struct dhcp_timer_param)); 00331 if(!cli->timer_param_2){ 00332 if(cli->cb != NULL){ 00333 pico_err = PICO_ERR_ENOMEM; 00334 cli->cb(cli, PICO_DHCP_ERROR); 00335 } 00336 return 0; 00337 } 00338 cli->timer_param_lease = pico_zalloc(sizeof(struct dhcp_timer_param)); 00339 if(!cli->timer_param_lease){ 00340 if(cli->cb != NULL){ 00341 pico_err = PICO_ERR_ENOMEM; 00342 cli->cb(cli, PICO_DHCP_ERROR); 00343 } 00344 return 0; 00345 } 00346 cli->timer_param_1->valid = 1; 00347 cli->timer_param_2->valid = 1; 00348 cli->timer_param_lease->valid = 1; 00349 00350 cli->timer_param_1->cli = cli; 00351 cli->timer_param_2->cli = cli; 00352 cli->timer_param_lease->cli = cli; 00353 00354 cli->timer_param_1->type = PICO_DHCP_EVENT_T1; 00355 cli->timer_param_2->type = PICO_DHCP_EVENT_T2; 00356 cli->timer_param_lease->type = PICO_DHCP_EVENT_LEASE; 00357 //add timer 00358 pico_timer_add(cli->T1*1000, dhcp_timer_cb, cli->timer_param_1); 00359 pico_timer_add(cli->T2*1000, dhcp_timer_cb, cli->timer_param_2); 00360 pico_timer_add(cli->lease_time*1000, dhcp_timer_cb, cli->timer_param_lease); 00361 00362 *(cli->xid_user) = cli->xid; 00363 if(cli->cb != NULL) 00364 cli->cb(cli, PICO_DHCP_SUCCESS); 00365 else 00366 dbg("DHCPC: no callback\n"); 00367 00368 dhcp_client_mutex++; 00369 cli->state = DHCPSTATE_BOUND; 00370 return 0; 00371 } 00372 00373 static int renew(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len) 00374 { 00375 uint16_t port = PICO_DHCP_CLIENT_PORT; 00376 00377 /* open and bind to currently acquired address */ 00378 if (!cli->socket){ 00379 cli->socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_wakeup); 00380 if (!cli->socket) { 00381 dbg("DHCPC: error opening socket on renew: %s\n", strerror(pico_err)); 00382 if(cli->cb != NULL) 00383 cli->cb(cli, PICO_DHCP_ERROR); 00384 return -1; 00385 } 00386 if (pico_socket_bind(cli->socket, &cli->address, &port) != 0){ 00387 dbg("DHCPC: error binding socket on renew: %s\n", strerror(pico_err)); 00388 pico_socket_close(cli->socket); 00389 if(cli->cb != NULL) 00390 cli->cb(cli, PICO_DHCP_ERROR); 00391 return -1; 00392 } 00393 } 00394 cli->state = DHCPSTATE_RENEWING; 00395 dhclient_send(cli, PICO_DHCP_MSG_REQUEST); 00396 00397 return 0; 00398 } 00399 00400 static int reset(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len) 00401 { 00402 if(cli->cb != NULL) 00403 cli->cb(cli, PICO_DHCP_RESET); 00404 //reset pretty much everything 00405 00406 if(cli->timer_param_1) 00407 cli->timer_param_1->valid = 0; 00408 if(cli->timer_param_2) 00409 cli->timer_param_2->valid = 0; 00410 if(cli->timer_param_lease) 00411 cli->timer_param_lease->valid = 0; 00412 if(cli->timer_param_retransmit) 00413 cli->timer_param_retransmit->valid = 0; 00414 00415 pico_socket_close(cli->socket); 00416 pico_ipv4_link_del(cli->device, cli->address); 00417 00418 //initiate negotiations again 00419 init_cookie(cli); 00420 pico_dhcp_retry(cli); 00421 dhclient_send(cli, PICO_DHCP_MSG_DISCOVER); 00422 00423 return 0; 00424 00425 } 00426 00427 static int retransmit(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len) 00428 { 00429 pico_dhcp_retry(cli); 00430 00431 if(cli->state == DHCPSTATE_DISCOVER) 00432 dhclient_send(cli, PICO_DHCP_MSG_DISCOVER); 00433 else if(cli->state == DHCPSTATE_RENEWING) 00434 dhclient_send(cli, PICO_DHCP_MSG_REQUEST); 00435 else 00436 dbg("DHCPC: WARNING: should not get here in state %d!\n", cli->state); 00437 00438 return 0; 00439 00440 } 00441 00442 /********************** 00443 * fsm implementation * 00444 **********************/ 00445 00446 struct dhcp_action_entry { 00447 uint16_t tcpstate; 00448 int (*offer)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); 00449 int (*ack)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); 00450 int (*nak)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); 00451 int (*timer1)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); 00452 int (*timer_lease)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); 00453 int (*timer_retransmit)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); 00454 }; 00455 00456 static struct dhcp_action_entry dhcp_fsm[] = { 00457 /* State offer ack nak timer1 timer_lease timer_retransmit*/ 00458 { DHCPSTATE_DISCOVER, recv_offer, NULL, NULL, NULL, reset, retransmit}, 00459 { DHCPSTATE_OFFER, NULL, NULL, NULL, NULL, reset, NULL}, 00460 { DHCPSTATE_REQUEST, NULL, recv_ack, reset, NULL, reset, retransmit}, 00461 { DHCPSTATE_BOUND, NULL, NULL, reset, renew, reset, NULL}, 00462 { DHCPSTATE_RENEWING, NULL, recv_ack, reset, NULL, reset, retransmit}, 00463 }; 00464 00465 00466 static void pico_dhcp_state_machine(int type, struct pico_dhcp_client_cookie* cli, uint8_t* data, int len) 00467 { 00468 dbg("DHCPC: received incoming event of type %d\n", type); 00469 switch(type){ 00470 case PICO_DHCP_MSG_OFFER: 00471 if(dhcp_fsm[cli->state].offer != NULL) 00472 dhcp_fsm[cli->state].offer(cli, data, len); 00473 break; 00474 case PICO_DHCP_MSG_ACK: 00475 if(dhcp_fsm[cli->state].ack != NULL){ 00476 dhcp_fsm[cli->state].ack(cli, data, len); 00477 } 00478 break; 00479 case PICO_DHCP_MSG_NAK: 00480 if(dhcp_fsm[cli->state].nak!= NULL){ 00481 dhcp_fsm[cli->state].nak(cli, data, len); 00482 } 00483 break; 00484 case PICO_DHCP_EVENT_T1: 00485 if(dhcp_fsm[cli->state].timer1!= NULL){ 00486 dhcp_fsm[cli->state].timer1(cli, NULL, 0); 00487 } 00488 break; 00489 case PICO_DHCP_EVENT_LEASE: 00490 if(dhcp_fsm[cli->state].timer_lease!= NULL){ 00491 dhcp_fsm[cli->state].timer_lease(cli, NULL, 0); 00492 } 00493 break; 00494 case PICO_DHCP_EVENT_RETRANSMIT: 00495 if(dhcp_fsm[cli->state].timer_retransmit!= NULL){ 00496 dhcp_fsm[cli->state].timer_retransmit(cli, NULL, 0); 00497 } 00498 break; 00499 default: 00500 dbg("DHCPC: event not supported yet!!\n"); 00501 break; 00502 } 00503 } 00504 00505 00506 /********************* 00507 * utility functions * 00508 *********************/ 00509 00510 static void pico_dhcp_retry(struct pico_dhcp_client_cookie *cli) 00511 { 00512 const int MAX_RETRY = 3; 00513 uint32_t new_xid; 00514 if (++cli->attempt > MAX_RETRY) { 00515 cli->start_time = pico_tick; 00516 cli->attempt = 0; 00517 new_xid = pico_rand(); 00518 while(get_cookie_by_xid(new_xid) != NULL){ 00519 new_xid = pico_rand(); 00520 } 00521 cli->xid = new_xid; 00522 cli->state = DHCPSTATE_DISCOVER; 00523 } 00524 } 00525 00526 static int dhclient_send(struct pico_dhcp_client_cookie *cli, uint8_t msg_type) 00527 { 00528 uint8_t buf_out[DHCPC_DATAGRAM_SIZE] = {0}; 00529 struct pico_dhcphdr *dh_out = (struct pico_dhcphdr *) buf_out; 00530 int sent = 0; 00531 int i = 0; 00532 struct pico_ip4 destination; 00533 uint16_t port = PICO_DHCPD_PORT; 00534 if(cli->state == DHCPSTATE_BOUND || cli->state == DHCPSTATE_RENEWING){ 00535 destination.addr = cli->server_id.addr; 00536 }else{ 00537 destination.addr = long_be(0xFFFFFFFF); 00538 } 00539 00540 if(cli->device->eth == NULL){ 00541 pico_err = PICO_ERR_EOPNOTSUPP; 00542 if(cli->cb != NULL){ 00543 cli->cb(cli, PICO_DHCP_ERROR); 00544 } 00545 return -1; 00546 } 00547 memcpy(dh_out->hwaddr, &cli->device->eth->mac, PICO_HLEN_ETHER); 00548 dh_out->op = PICO_DHCP_OP_REQUEST; 00549 dh_out->htype = PICO_HTYPE_ETHER; 00550 dh_out->hlen = PICO_HLEN_ETHER; 00551 dh_out->xid = cli->xid; 00552 dh_out->secs = (msg_type == PICO_DHCP_MSG_REQUEST)?0:short_be((pico_tick - cli->start_time)/1000); 00553 dh_out->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE; 00554 if (cli->state == DHCPSTATE_RENEWING) 00555 dh_out->ciaddr = cli->address.addr; 00556 00557 /* Option: msg type, len 1 */ 00558 dh_out->options[i++] = PICO_DHCPOPT_MSGTYPE; 00559 dh_out->options[i++] = 1; 00560 dh_out->options[i++] = msg_type; 00561 00562 if (( msg_type == PICO_DHCP_MSG_REQUEST) && ( cli->state != DHCPSTATE_RENEWING )) { 00563 dh_out->options[i++] = PICO_DHCPOPT_REQIP; 00564 dh_out->options[i++] = 4; 00565 dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF000000) >> 24; 00566 dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF0000) >> 16; 00567 dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF00) >> 8; 00568 dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF); 00569 dh_out->options[i++] = PICO_DHCPOPT_SERVERID; 00570 dh_out->options[i++] = 4; 00571 dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF000000) >> 24; 00572 dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF0000) >> 16; 00573 dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF00) >> 8; 00574 dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF); 00575 } 00576 00577 /* Option: req list, len 4 */ 00578 dh_out->options[i++] = PICO_DHCPOPT_PARMLIST; 00579 dh_out->options[i++] = 7; 00580 dh_out->options[i++] = PICO_DHCPOPT_NETMASK; 00581 dh_out->options[i++] = PICO_DHCPOPT_BCAST; 00582 dh_out->options[i++] = PICO_DHCPOPT_TIME; 00583 dh_out->options[i++] = PICO_DHCPOPT_ROUTER; 00584 dh_out->options[i++] = PICO_DHCPOPT_HOSTNAME; 00585 dh_out->options[i++] = PICO_DHCPOPT_RENEWALTIME; 00586 dh_out->options[i++] = PICO_DHCPOPT_REBINDINGTIME; 00587 00588 /* Option : max message size */ 00589 if( msg_type == PICO_DHCP_MSG_REQUEST || msg_type == PICO_DHCP_MSG_DISCOVER){ 00590 uint16_t dds = DHCPC_DATAGRAM_SIZE; 00591 dh_out->options[i++] = PICO_DHCPOPT_MAXMSGSIZE; 00592 dh_out->options[i++] = 2; 00593 dh_out->options[i++] = (dds & 0xFF00) >> 8; 00594 dh_out->options[i++] = (dds & 0xFF); 00595 } 00596 00597 00598 00599 dh_out->options[i] = PICO_DHCPOPT_END; 00600 sent = pico_socket_sendto(cli->socket, buf_out, DHCPC_DATAGRAM_SIZE, &destination, port); 00601 if (sent < 0) { 00602 dbg("DHCPC: sendto failed: %s\n", strerror(pico_err)); 00603 if(cli->cb != NULL) 00604 cli->cb(cli, PICO_DHCP_ERROR); 00605 } 00606 00607 00608 //resend-timer : 00609 if(cli->timer_param_retransmit != NULL) 00610 cli->timer_param_retransmit->valid=0; 00611 00612 cli->timer_param_retransmit = pico_zalloc(sizeof(struct dhcp_timer_param)); 00613 if(!cli->timer_param_retransmit){ 00614 if(cli->cb != NULL) 00615 pico_err = PICO_ERR_ENOMEM; 00616 cli->cb(cli, PICO_DHCP_ERROR); 00617 return -1; 00618 } 00619 cli->timer_param_retransmit->valid = 1; 00620 cli->timer_param_retransmit->cli = cli; 00621 cli->timer_param_retransmit->type = PICO_DHCP_EVENT_RETRANSMIT; 00622 pico_timer_add(4000, dhcp_timer_cb, cli->timer_param_retransmit); 00623 00624 return 0; 00625 } 00626 00627 //identifies type & does some preprocessing : checking if everything is valid 00628 static int pico_dhcp_verify_and_identify_type(uint8_t* data, int len, struct pico_dhcp_client_cookie *cli) 00629 { 00630 struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) data; 00631 uint8_t *nextopt, opt_data[20], opt_type; 00632 int opt_len = 20; 00633 00634 if (dhdr->xid != cli->xid) 00635 return 0; 00636 00637 if (!is_options_valid(dhdr->options, len - sizeof(struct pico_dhcphdr))) 00638 return 0; 00639 00640 if( dhdr->dhcp_magic != PICO_DHCPD_MAGIC_COOKIE) 00641 return 0; 00642 00643 opt_type = dhcp_get_next_option(dhdr->options, opt_data, &opt_len, &nextopt); 00644 while (opt_type != PICO_DHCPOPT_END) { 00645 /* parse interesting options here */ 00646 if (opt_type == PICO_DHCPOPT_MSGTYPE) { 00647 return *opt_data; 00648 } 00649 opt_len = 20; 00650 opt_type = dhcp_get_next_option(NULL, opt_data, &opt_len, &nextopt); 00651 } 00652 return 0; 00653 00654 } 00655 00656 static int init_cookie(struct pico_dhcp_client_cookie* cli) 00657 { 00658 uint8_t n = 3; 00659 uint16_t port = PICO_DHCP_CLIENT_PORT; 00660 struct pico_ip4 address, netmask; 00661 00662 address.addr = long_be(0x00000000); 00663 netmask.addr = long_be(0x00000000); 00664 00665 cli->state = DHCPSTATE_DISCOVER; 00666 cli->start_time = pico_tick; 00667 cli->attempt = 0; 00668 00669 cli->socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_wakeup); 00670 if (!cli->socket) { 00671 dbg("DHCPC: error opening socket: %s\n", strerror(pico_err)); 00672 if(cli->cb != NULL) 00673 cli->cb(cli, PICO_DHCP_ERROR); 00674 return -1; 00675 } 00676 if (pico_socket_bind(cli->socket, &address, &port) != 0){ 00677 dbg("DHCPC: error binding socket: %s\n", strerror(pico_err)); 00678 pico_socket_close(cli->socket); 00679 if(cli->cb != NULL) 00680 cli->cb(cli, PICO_DHCP_ERROR); 00681 return -1; 00682 } 00683 cli->socket->dev = cli->device; 00684 00685 if(pico_ipv4_link_add(cli->device, address, netmask) != 0){ 00686 dbg("DHCPC: error adding link: %s\n", strerror(pico_err)); 00687 if(cli->cb != NULL) 00688 cli->cb(cli, PICO_DHCP_ERROR); 00689 return -1; 00690 } 00691 00692 /* attempt to generate a correct xid 3 times, then fail */ 00693 do { 00694 cli->xid = pico_rand(); 00695 } while (!cli->xid && --n); 00696 if (!cli->xid) { 00697 if(cli->cb != NULL) 00698 cli->cb(cli, PICO_DHCP_ERROR); 00699 return -1; 00700 } 00701 00702 return 0; 00703 } 00704 00705 static struct pico_dhcp_client_cookie *get_cookie_by_xid(uint32_t xid) 00706 { 00707 struct pico_dhcp_client_cookie test = { }, *cookie = NULL; 00708 00709 if (!xid) 00710 return NULL; 00711 00712 test.xid = xid; 00713 cookie = pico_tree_findKey(&DHCPCookies, &test); 00714 if (!cookie) 00715 return NULL; 00716 else 00717 return cookie; 00718 } 00719 00720 void *pico_dhcp_get_identifier(uint32_t xid) 00721 { 00722 return (void *) get_cookie_by_xid(xid); 00723 } 00724 00725 static uint32_t get_xid(uint8_t* data) 00726 { 00727 struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) data; 00728 return dhdr->xid; 00729 } 00730 00731 #endif
Generated on Wed Jul 13 2022 02:20:45 by 1.7.2