Free (GPLv2) TCP/IP stack developed by TASS Belgium

Fork of PicoTCP by Daniele Lacamera

Committer:
daniele
Date:
Sat Aug 03 08:50:27 2013 +0000
Revision:
51:18637a3d071f
Parent:
29:1a47b7151851
Branch for CDC-ECM: Work in progress

Who changed what in which revision?

UserRevisionLine numberNew contents of line
daniele 29:1a47b7151851 1 /*********************************************************************
daniele 29:1a47b7151851 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
daniele 29:1a47b7151851 3 See LICENSE and COPYING for usage.
daniele 29:1a47b7151851 4
daniele 29:1a47b7151851 5 Authors: Frederik Van Slycken, Kristof Roelants
daniele 29:1a47b7151851 6 *********************************************************************/
daniele 29:1a47b7151851 7
daniele 29:1a47b7151851 8 #include "pico_dhcp_client.h"
daniele 29:1a47b7151851 9 #include "pico_stack.h"
daniele 29:1a47b7151851 10 #include "pico_config.h"
daniele 29:1a47b7151851 11 #include "pico_device.h"
daniele 29:1a47b7151851 12 #include "pico_ipv4.h"
daniele 29:1a47b7151851 13 #include "pico_socket.h"
daniele 29:1a47b7151851 14
daniele 29:1a47b7151851 15 #ifdef PICO_SUPPORT_DHCPC
daniele 29:1a47b7151851 16
daniele 29:1a47b7151851 17 /***********
daniele 29:1a47b7151851 18 * structs *
daniele 29:1a47b7151851 19 ***********/
daniele 29:1a47b7151851 20
daniele 29:1a47b7151851 21 static uint8_t dhcp_client_mutex = 1; /* to serialize client negotations if multiple devices */
daniele 29:1a47b7151851 22
daniele 29:1a47b7151851 23 struct dhcp_timer_param{
daniele 29:1a47b7151851 24 uint16_t type;
daniele 29:1a47b7151851 25 struct pico_dhcp_client_cookie* cli;
daniele 29:1a47b7151851 26 int valid;
daniele 29:1a47b7151851 27 };
daniele 29:1a47b7151851 28
daniele 29:1a47b7151851 29 struct pico_dhcp_client_cookie
daniele 29:1a47b7151851 30 {
daniele 29:1a47b7151851 31 uint32_t xid;
daniele 29:1a47b7151851 32 uint32_t *xid_user;
daniele 29:1a47b7151851 33 struct pico_ip4 address;
daniele 29:1a47b7151851 34 struct pico_ip4 netmask;
daniele 29:1a47b7151851 35 struct pico_ip4 gateway;
daniele 29:1a47b7151851 36 struct pico_ip4 nameserver;
daniele 29:1a47b7151851 37 struct pico_ip4 server_id;
daniele 29:1a47b7151851 38 uint32_t lease_time;
daniele 29:1a47b7151851 39 uint32_t T1;
daniele 29:1a47b7151851 40 uint32_t T2;
daniele 29:1a47b7151851 41 struct pico_socket* socket;
daniele 29:1a47b7151851 42 int connected;
daniele 29:1a47b7151851 43 struct pico_device* device;
daniele 29:1a47b7151851 44 unsigned long start_time;
daniele 29:1a47b7151851 45 int attempt;
daniele 29:1a47b7151851 46 enum dhcp_negotiation_state state;
daniele 29:1a47b7151851 47 void (*cb)(void* cli, int code);
daniele 29:1a47b7151851 48 struct dhcp_timer_param* timer_param_1;
daniele 29:1a47b7151851 49 struct dhcp_timer_param* timer_param_2;
daniele 29:1a47b7151851 50 struct dhcp_timer_param* timer_param_lease;
daniele 29:1a47b7151851 51 struct dhcp_timer_param* timer_param_retransmit;
daniele 29:1a47b7151851 52 int link_added;
daniele 29:1a47b7151851 53 };
daniele 29:1a47b7151851 54
daniele 29:1a47b7151851 55 static int dhcp_cookies_cmp(void *ka, void *kb)
daniele 29:1a47b7151851 56 {
daniele 29:1a47b7151851 57 struct pico_dhcp_client_cookie *a = ka, *b = kb;
daniele 29:1a47b7151851 58 if (a->xid < b->xid)
daniele 29:1a47b7151851 59 return -1;
daniele 29:1a47b7151851 60 else if (a->xid > b->xid)
daniele 29:1a47b7151851 61 return 1;
daniele 29:1a47b7151851 62 else
daniele 29:1a47b7151851 63 return 0;
daniele 29:1a47b7151851 64 }
daniele 29:1a47b7151851 65 PICO_TREE_DECLARE(DHCPCookies, dhcp_cookies_cmp);
daniele 29:1a47b7151851 66
daniele 29:1a47b7151851 67 /*************************
daniele 29:1a47b7151851 68 * function declarations *
daniele 29:1a47b7151851 69 *************************/
daniele 29:1a47b7151851 70 static void pico_dhcp_state_machine(int type, struct pico_dhcp_client_cookie* cli, uint8_t* data, int len);
daniele 29:1a47b7151851 71 static void pico_dhcp_reinitiate_negotiation(unsigned long now, void *arg);
daniele 29:1a47b7151851 72
daniele 29:1a47b7151851 73 //cb
daniele 29:1a47b7151851 74 static void pico_dhcp_wakeup(uint16_t ev, struct pico_socket *s);
daniele 29:1a47b7151851 75 static void dhcp_timer_cb(unsigned long tick, void* param);
daniele 29:1a47b7151851 76
daniele 29:1a47b7151851 77 //util
daniele 29:1a47b7151851 78 static void pico_dhcp_retry(struct pico_dhcp_client_cookie *client);
daniele 29:1a47b7151851 79 static int dhclient_send(struct pico_dhcp_client_cookie *cli, uint8_t msg_type);
daniele 29:1a47b7151851 80 static int pico_dhcp_verify_and_identify_type(uint8_t* data, int len, struct pico_dhcp_client_cookie *cli);
daniele 29:1a47b7151851 81 static int init_cookie(struct pico_dhcp_client_cookie* cli);
daniele 29:1a47b7151851 82 static struct pico_dhcp_client_cookie* get_cookie_by_xid(uint32_t xid);
daniele 29:1a47b7151851 83 static uint32_t get_xid(uint8_t* data);
daniele 29:1a47b7151851 84
daniele 29:1a47b7151851 85 //fsm functions
daniele 29:1a47b7151851 86 static int recv_offer(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
daniele 29:1a47b7151851 87 static int recv_ack(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
daniele 29:1a47b7151851 88 static int renew(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
daniele 29:1a47b7151851 89 static int reset(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
daniele 29:1a47b7151851 90 static int retransmit(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
daniele 29:1a47b7151851 91
daniele 29:1a47b7151851 92 //fsm implementation
daniele 29:1a47b7151851 93 static void pico_dhcp_state_machine(int type, struct pico_dhcp_client_cookie* cli, uint8_t* data, int len);
daniele 29:1a47b7151851 94
daniele 29:1a47b7151851 95 /***************
daniele 29:1a47b7151851 96 * entry point *
daniele 29:1a47b7151851 97 ***************/
daniele 29:1a47b7151851 98
daniele 29:1a47b7151851 99 static uint32_t pico_dhcp_execute_init(struct pico_dhcp_client_cookie *cli)
daniele 29:1a47b7151851 100 {
daniele 29:1a47b7151851 101 if (!dhcp_client_mutex) {
daniele 29:1a47b7151851 102 pico_timer_add(3000, pico_dhcp_reinitiate_negotiation, cli);
daniele 29:1a47b7151851 103 return 0;
daniele 29:1a47b7151851 104 }
daniele 29:1a47b7151851 105 dhcp_client_mutex--;
daniele 29:1a47b7151851 106
daniele 29:1a47b7151851 107 if (init_cookie(cli) < 0)
daniele 29:1a47b7151851 108 return -1;
daniele 29:1a47b7151851 109
daniele 29:1a47b7151851 110 dbg("DHCPC: cookie with xid %u\n", cli->xid);
daniele 29:1a47b7151851 111
daniele 29:1a47b7151851 112 if (pico_tree_insert(&DHCPCookies, cli)) {
daniele 29:1a47b7151851 113 pico_err = PICO_ERR_EAGAIN;
daniele 29:1a47b7151851 114 if(cli->cb != NULL) {
daniele 29:1a47b7151851 115 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 116 }
daniele 29:1a47b7151851 117 pico_free(cli);
daniele 29:1a47b7151851 118 return -1; /* Element key already exists */
daniele 29:1a47b7151851 119 }
daniele 29:1a47b7151851 120
daniele 29:1a47b7151851 121 if (dhclient_send(cli, PICO_DHCP_MSG_DISCOVER) < 0)
daniele 29:1a47b7151851 122 return -1;
daniele 29:1a47b7151851 123
daniele 29:1a47b7151851 124 return 0;
daniele 29:1a47b7151851 125 }
daniele 29:1a47b7151851 126
daniele 29:1a47b7151851 127 /* 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 */
daniele 29:1a47b7151851 128 int pico_dhcp_initiate_negotiation(struct pico_device *device, void (*callback)(void *cli, int code), uint32_t *xid)
daniele 29:1a47b7151851 129 {
daniele 29:1a47b7151851 130 struct pico_dhcp_client_cookie *cli;
daniele 29:1a47b7151851 131
daniele 29:1a47b7151851 132 if(!device || !callback || !xid){
daniele 29:1a47b7151851 133 pico_err = PICO_ERR_EINVAL;
daniele 29:1a47b7151851 134 return -1;
daniele 29:1a47b7151851 135 }
daniele 29:1a47b7151851 136 cli = pico_zalloc(sizeof(struct pico_dhcp_client_cookie));
daniele 29:1a47b7151851 137 if(!cli){
daniele 29:1a47b7151851 138 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 139 return -1;
daniele 29:1a47b7151851 140 }
daniele 29:1a47b7151851 141
daniele 29:1a47b7151851 142 cli->device = device;
daniele 29:1a47b7151851 143 cli->cb = callback;
daniele 29:1a47b7151851 144 cli->xid_user = xid;
daniele 29:1a47b7151851 145 *(cli->xid_user) = 0;
daniele 29:1a47b7151851 146
daniele 29:1a47b7151851 147 return pico_dhcp_execute_init(cli);
daniele 29:1a47b7151851 148 }
daniele 29:1a47b7151851 149
daniele 29:1a47b7151851 150 static void pico_dhcp_reinitiate_negotiation(unsigned long now, void *arg)
daniele 29:1a47b7151851 151 {
daniele 29:1a47b7151851 152 struct pico_dhcp_client_cookie *cli = (struct pico_dhcp_client_cookie *) arg;
daniele 29:1a47b7151851 153
daniele 29:1a47b7151851 154 pico_dhcp_execute_init(cli);
daniele 29:1a47b7151851 155
daniele 29:1a47b7151851 156 return;
daniele 29:1a47b7151851 157 }
daniele 29:1a47b7151851 158
daniele 29:1a47b7151851 159 /********************
daniele 29:1a47b7151851 160 * access functions *
daniele 29:1a47b7151851 161 ********************/
daniele 29:1a47b7151851 162
daniele 29:1a47b7151851 163 struct pico_ip4 pico_dhcp_get_address(void* cli)
daniele 29:1a47b7151851 164 {
daniele 29:1a47b7151851 165 return ((struct pico_dhcp_client_cookie*)cli)->address;
daniele 29:1a47b7151851 166 }
daniele 29:1a47b7151851 167
daniele 29:1a47b7151851 168 struct pico_ip4 pico_dhcp_get_gateway(void* cli)
daniele 29:1a47b7151851 169 {
daniele 29:1a47b7151851 170 return ((struct pico_dhcp_client_cookie*)cli)->gateway;
daniele 29:1a47b7151851 171 }
daniele 29:1a47b7151851 172
daniele 29:1a47b7151851 173 struct pico_ip4 pico_dhcp_get_nameserver(void* cli)
daniele 29:1a47b7151851 174 {
daniele 29:1a47b7151851 175 return ((struct pico_dhcp_client_cookie*)cli)->nameserver;
daniele 29:1a47b7151851 176 }
daniele 29:1a47b7151851 177
daniele 29:1a47b7151851 178 /*************
daniele 29:1a47b7151851 179 * callbacks *
daniele 29:1a47b7151851 180 *************/
daniele 29:1a47b7151851 181
daniele 29:1a47b7151851 182 static void pico_dhcp_wakeup(uint16_t ev, struct pico_socket *s)
daniele 29:1a47b7151851 183 {
daniele 29:1a47b7151851 184 uint8_t buf[DHCPC_DATAGRAM_SIZE];
daniele 29:1a47b7151851 185 int r=0;
daniele 29:1a47b7151851 186 uint32_t peer;
daniele 29:1a47b7151851 187 uint16_t port;
daniele 29:1a47b7151851 188 int type;
daniele 29:1a47b7151851 189
daniele 29:1a47b7151851 190 struct pico_dhcp_client_cookie *cli;
daniele 29:1a47b7151851 191 dbg("DHCPC: called dhcp_wakeup\n");
daniele 29:1a47b7151851 192 if (ev == PICO_SOCK_EV_RD) {
daniele 29:1a47b7151851 193 do {
daniele 29:1a47b7151851 194 r = pico_socket_recvfrom(s, buf, DHCPC_DATAGRAM_SIZE, &peer, &port);
daniele 29:1a47b7151851 195 cli = get_cookie_by_xid(get_xid(buf));
daniele 29:1a47b7151851 196 if(cli == NULL)
daniele 29:1a47b7151851 197 return;
daniele 29:1a47b7151851 198 if (r > 0 && port == PICO_DHCPD_PORT) {
daniele 29:1a47b7151851 199 type = pico_dhcp_verify_and_identify_type(buf, r, cli);
daniele 29:1a47b7151851 200 pico_dhcp_state_machine(type, cli, buf, r);
daniele 29:1a47b7151851 201 }
daniele 29:1a47b7151851 202 } while(r>0);
daniele 29:1a47b7151851 203 }
daniele 29:1a47b7151851 204 }
daniele 29:1a47b7151851 205
daniele 29:1a47b7151851 206 static void dhcp_timer_cb(unsigned long tick, void* param)
daniele 29:1a47b7151851 207 {
daniele 29:1a47b7151851 208 struct dhcp_timer_param* param2 = (struct dhcp_timer_param*) param;
daniele 29:1a47b7151851 209 if(param2->valid == 1){
daniele 29:1a47b7151851 210 //dbg("called timer cb on active timer type %d\n",param2->type);
daniele 29:1a47b7151851 211 pico_dhcp_state_machine(param2->type, param2->cli, NULL, 0);
daniele 29:1a47b7151851 212 }
daniele 29:1a47b7151851 213 if(param2->cli->timer_param_1 == param){
daniele 29:1a47b7151851 214 param2->cli->timer_param_1 = NULL;
daniele 29:1a47b7151851 215 }
daniele 29:1a47b7151851 216 if(param2->cli->timer_param_2 == param){
daniele 29:1a47b7151851 217 param2->cli->timer_param_2 = NULL;
daniele 29:1a47b7151851 218 }
daniele 29:1a47b7151851 219 if(param2->cli->timer_param_lease == param){
daniele 29:1a47b7151851 220 param2->cli->timer_param_lease = NULL;
daniele 29:1a47b7151851 221 }
daniele 29:1a47b7151851 222 if(param2->cli->timer_param_retransmit == param){
daniele 29:1a47b7151851 223 param2->cli->timer_param_retransmit = NULL;
daniele 29:1a47b7151851 224 }
daniele 29:1a47b7151851 225
daniele 29:1a47b7151851 226 pico_free(param);
daniele 29:1a47b7151851 227
daniele 29:1a47b7151851 228 }
daniele 29:1a47b7151851 229 /*****************
daniele 29:1a47b7151851 230 * fsm functions *
daniele 29:1a47b7151851 231 *****************/
daniele 29:1a47b7151851 232
daniele 29:1a47b7151851 233 static int recv_offer(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len)
daniele 29:1a47b7151851 234 {
daniele 29:1a47b7151851 235 struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) data;
daniele 29:1a47b7151851 236 uint8_t *nextopt, opt_data[20], opt_type;
daniele 29:1a47b7151851 237 int opt_len = 20;
daniele 29:1a47b7151851 238 uint8_t msg_type = 0xFF;
daniele 29:1a47b7151851 239 int T1_set = 0;
daniele 29:1a47b7151851 240 int T2_set = 0;
daniele 29:1a47b7151851 241
daniele 29:1a47b7151851 242 cli->address.addr = dhdr->yiaddr;
daniele 29:1a47b7151851 243
daniele 29:1a47b7151851 244 opt_type = dhcp_get_next_option(dhdr->options, opt_data, &opt_len, &nextopt);
daniele 29:1a47b7151851 245 while (opt_type != PICO_DHCPOPT_END) {
daniele 29:1a47b7151851 246 if (opt_type == PICO_DHCPOPT_MSGTYPE)
daniele 29:1a47b7151851 247 msg_type = opt_data[0];
daniele 29:1a47b7151851 248 if ((opt_type == PICO_DHCPOPT_LEASETIME) && (opt_len == 4)){
daniele 29:1a47b7151851 249 memcpy(&cli->lease_time, opt_data, 4);
daniele 29:1a47b7151851 250 cli->lease_time = long_be(cli->lease_time);
daniele 29:1a47b7151851 251 }
daniele 29:1a47b7151851 252 if ((opt_type == PICO_DHCPOPT_RENEWALTIME) && (opt_len == 4)){
daniele 29:1a47b7151851 253 memcpy(&cli->T1, opt_data, 4);
daniele 29:1a47b7151851 254 cli->T1 = long_be(cli->T1);
daniele 29:1a47b7151851 255 T1_set =1;
daniele 29:1a47b7151851 256 }
daniele 29:1a47b7151851 257 if ((opt_type == PICO_DHCPOPT_REBINDINGTIME) && (opt_len == 4)){
daniele 29:1a47b7151851 258 memcpy(&cli->T2, opt_data, 4);
daniele 29:1a47b7151851 259 cli->T2 = long_be(cli->T2);
daniele 29:1a47b7151851 260 T2_set =1;
daniele 29:1a47b7151851 261 }
daniele 29:1a47b7151851 262 if ((opt_type == PICO_DHCPOPT_ROUTER) && (opt_len == 4)) //XXX assuming only one router will be advertised...
daniele 29:1a47b7151851 263 memcpy(&cli->gateway.addr, opt_data, 4);
daniele 29:1a47b7151851 264 if ((opt_type == PICO_DHCPOPT_DNS) && (opt_len == 4))
daniele 29:1a47b7151851 265 memcpy(&cli->nameserver.addr, opt_data, 4);
daniele 29:1a47b7151851 266 if ((opt_type == PICO_DHCPOPT_NETMASK) && (opt_len == 4))
daniele 29:1a47b7151851 267 memcpy(&cli->netmask.addr, opt_data, 4);
daniele 29:1a47b7151851 268 if ((opt_type == PICO_DHCPOPT_SERVERID) && (opt_len == 4))
daniele 29:1a47b7151851 269 memcpy(&cli->server_id.addr, opt_data, 4);
daniele 29:1a47b7151851 270 if (opt_type == PICO_DHCPOPT_OPTIONOVERLOAD)
daniele 29:1a47b7151851 271 dbg("DHCPC: WARNING: option overload present (not processed)");
daniele 29:1a47b7151851 272
daniele 29:1a47b7151851 273 opt_len = 20;
daniele 29:1a47b7151851 274 opt_type = dhcp_get_next_option(NULL, opt_data, &opt_len, &nextopt);
daniele 29:1a47b7151851 275 }
daniele 29:1a47b7151851 276
daniele 29:1a47b7151851 277 /* default values for T1 and T2 if necessary */
daniele 29:1a47b7151851 278 if(T1_set != 1)
daniele 29:1a47b7151851 279 cli->T1 = cli->lease_time >> 1;
daniele 29:1a47b7151851 280 if(T2_set != 1)
daniele 29:1a47b7151851 281 cli->T2 = (cli->lease_time * 875) / 1000;
daniele 29:1a47b7151851 282
daniele 29:1a47b7151851 283
daniele 29:1a47b7151851 284
daniele 29:1a47b7151851 285 if ((msg_type != PICO_DHCP_MSG_OFFER) || !cli->lease_time || !cli->netmask.addr || !cli->server_id.addr )
daniele 29:1a47b7151851 286 return 0;
daniele 29:1a47b7151851 287
daniele 29:1a47b7151851 288
daniele 29:1a47b7151851 289 dhclient_send(cli, PICO_DHCP_MSG_REQUEST);
daniele 29:1a47b7151851 290 cli->state = DHCPSTATE_REQUEST;
daniele 29:1a47b7151851 291 return 1;
daniele 29:1a47b7151851 292 }
daniele 29:1a47b7151851 293
daniele 29:1a47b7151851 294 static int recv_ack(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len)
daniele 29:1a47b7151851 295 {
daniele 29:1a47b7151851 296 struct pico_ip4 address = {0};
daniele 29:1a47b7151851 297
daniele 29:1a47b7151851 298 if(cli->link_added == 0){
daniele 29:1a47b7151851 299 /* close the socket bound on address 0.0.0.0 */
daniele 29:1a47b7151851 300 pico_socket_close(cli->socket);
daniele 29:1a47b7151851 301 cli->socket = NULL;
daniele 29:1a47b7151851 302 pico_ipv4_link_del(cli->device, address);
daniele 29:1a47b7151851 303 pico_ipv4_link_add(cli->device, cli->address, cli->netmask);
daniele 29:1a47b7151851 304 cli->link_added = 1;
daniele 29:1a47b7151851 305 }
daniele 29:1a47b7151851 306 cli->state = DHCPSTATE_BOUND;
daniele 29:1a47b7151851 307
daniele 29:1a47b7151851 308 dbg("DHCPC: T1: %d\n",cli->T1);
daniele 29:1a47b7151851 309 dbg("DHCPC: T2: %d\n",cli->T2);
daniele 29:1a47b7151851 310 dbg("DHCPC: lease time: %d\n",cli->lease_time);
daniele 29:1a47b7151851 311
daniele 29:1a47b7151851 312 if(cli->timer_param_1)
daniele 29:1a47b7151851 313 cli->timer_param_1->valid = 0;
daniele 29:1a47b7151851 314 if(cli->timer_param_2)
daniele 29:1a47b7151851 315 cli->timer_param_2->valid = 0;
daniele 29:1a47b7151851 316 if(cli->timer_param_lease)
daniele 29:1a47b7151851 317 cli->timer_param_lease->valid = 0;
daniele 29:1a47b7151851 318 if(cli->timer_param_retransmit)
daniele 29:1a47b7151851 319 cli->timer_param_retransmit->valid = 0;
daniele 29:1a47b7151851 320
daniele 29:1a47b7151851 321
daniele 29:1a47b7151851 322 cli->timer_param_1 = pico_zalloc(sizeof(struct dhcp_timer_param));
daniele 29:1a47b7151851 323 if(!cli->timer_param_1){
daniele 29:1a47b7151851 324 if(cli->cb != NULL){
daniele 29:1a47b7151851 325 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 326 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 327 }
daniele 29:1a47b7151851 328 return 0;
daniele 29:1a47b7151851 329 }
daniele 29:1a47b7151851 330 cli->timer_param_2 = pico_zalloc(sizeof(struct dhcp_timer_param));
daniele 29:1a47b7151851 331 if(!cli->timer_param_2){
daniele 29:1a47b7151851 332 if(cli->cb != NULL){
daniele 29:1a47b7151851 333 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 334 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 335 }
daniele 29:1a47b7151851 336 return 0;
daniele 29:1a47b7151851 337 }
daniele 29:1a47b7151851 338 cli->timer_param_lease = pico_zalloc(sizeof(struct dhcp_timer_param));
daniele 29:1a47b7151851 339 if(!cli->timer_param_lease){
daniele 29:1a47b7151851 340 if(cli->cb != NULL){
daniele 29:1a47b7151851 341 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 342 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 343 }
daniele 29:1a47b7151851 344 return 0;
daniele 29:1a47b7151851 345 }
daniele 29:1a47b7151851 346 cli->timer_param_1->valid = 1;
daniele 29:1a47b7151851 347 cli->timer_param_2->valid = 1;
daniele 29:1a47b7151851 348 cli->timer_param_lease->valid = 1;
daniele 29:1a47b7151851 349
daniele 29:1a47b7151851 350 cli->timer_param_1->cli = cli;
daniele 29:1a47b7151851 351 cli->timer_param_2->cli = cli;
daniele 29:1a47b7151851 352 cli->timer_param_lease->cli = cli;
daniele 29:1a47b7151851 353
daniele 29:1a47b7151851 354 cli->timer_param_1->type = PICO_DHCP_EVENT_T1;
daniele 29:1a47b7151851 355 cli->timer_param_2->type = PICO_DHCP_EVENT_T2;
daniele 29:1a47b7151851 356 cli->timer_param_lease->type = PICO_DHCP_EVENT_LEASE;
daniele 29:1a47b7151851 357 //add timer
daniele 29:1a47b7151851 358 pico_timer_add(cli->T1*1000, dhcp_timer_cb, cli->timer_param_1);
daniele 29:1a47b7151851 359 pico_timer_add(cli->T2*1000, dhcp_timer_cb, cli->timer_param_2);
daniele 29:1a47b7151851 360 pico_timer_add(cli->lease_time*1000, dhcp_timer_cb, cli->timer_param_lease);
daniele 29:1a47b7151851 361
daniele 29:1a47b7151851 362 *(cli->xid_user) = cli->xid;
daniele 29:1a47b7151851 363 if(cli->cb != NULL)
daniele 29:1a47b7151851 364 cli->cb(cli, PICO_DHCP_SUCCESS);
daniele 29:1a47b7151851 365 else
daniele 29:1a47b7151851 366 dbg("DHCPC: no callback\n");
daniele 29:1a47b7151851 367
daniele 29:1a47b7151851 368 dhcp_client_mutex++;
daniele 29:1a47b7151851 369 cli->state = DHCPSTATE_BOUND;
daniele 29:1a47b7151851 370 return 0;
daniele 29:1a47b7151851 371 }
daniele 29:1a47b7151851 372
daniele 29:1a47b7151851 373 static int renew(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len)
daniele 29:1a47b7151851 374 {
daniele 29:1a47b7151851 375 uint16_t port = PICO_DHCP_CLIENT_PORT;
daniele 29:1a47b7151851 376
daniele 29:1a47b7151851 377 /* open and bind to currently acquired address */
daniele 29:1a47b7151851 378 if (!cli->socket){
daniele 29:1a47b7151851 379 cli->socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_wakeup);
daniele 29:1a47b7151851 380 if (!cli->socket) {
daniele 29:1a47b7151851 381 dbg("DHCPC: error opening socket on renew: %s\n", strerror(pico_err));
daniele 29:1a47b7151851 382 if(cli->cb != NULL)
daniele 29:1a47b7151851 383 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 384 return -1;
daniele 29:1a47b7151851 385 }
daniele 29:1a47b7151851 386 if (pico_socket_bind(cli->socket, &cli->address, &port) != 0){
daniele 29:1a47b7151851 387 dbg("DHCPC: error binding socket on renew: %s\n", strerror(pico_err));
daniele 29:1a47b7151851 388 pico_socket_close(cli->socket);
daniele 29:1a47b7151851 389 if(cli->cb != NULL)
daniele 29:1a47b7151851 390 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 391 return -1;
daniele 29:1a47b7151851 392 }
daniele 29:1a47b7151851 393 }
daniele 29:1a47b7151851 394 cli->state = DHCPSTATE_RENEWING;
daniele 29:1a47b7151851 395 dhclient_send(cli, PICO_DHCP_MSG_REQUEST);
daniele 29:1a47b7151851 396
daniele 29:1a47b7151851 397 return 0;
daniele 29:1a47b7151851 398 }
daniele 29:1a47b7151851 399
daniele 29:1a47b7151851 400 static int reset(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len)
daniele 29:1a47b7151851 401 {
daniele 29:1a47b7151851 402 if(cli->cb != NULL)
daniele 29:1a47b7151851 403 cli->cb(cli, PICO_DHCP_RESET);
daniele 29:1a47b7151851 404 //reset pretty much everything
daniele 29:1a47b7151851 405
daniele 29:1a47b7151851 406 if(cli->timer_param_1)
daniele 29:1a47b7151851 407 cli->timer_param_1->valid = 0;
daniele 29:1a47b7151851 408 if(cli->timer_param_2)
daniele 29:1a47b7151851 409 cli->timer_param_2->valid = 0;
daniele 29:1a47b7151851 410 if(cli->timer_param_lease)
daniele 29:1a47b7151851 411 cli->timer_param_lease->valid = 0;
daniele 29:1a47b7151851 412 if(cli->timer_param_retransmit)
daniele 29:1a47b7151851 413 cli->timer_param_retransmit->valid = 0;
daniele 29:1a47b7151851 414
daniele 29:1a47b7151851 415 pico_socket_close(cli->socket);
daniele 29:1a47b7151851 416 pico_ipv4_link_del(cli->device, cli->address);
daniele 29:1a47b7151851 417
daniele 29:1a47b7151851 418 //initiate negotiations again
daniele 29:1a47b7151851 419 init_cookie(cli);
daniele 29:1a47b7151851 420 pico_dhcp_retry(cli);
daniele 29:1a47b7151851 421 dhclient_send(cli, PICO_DHCP_MSG_DISCOVER);
daniele 29:1a47b7151851 422
daniele 29:1a47b7151851 423 return 0;
daniele 29:1a47b7151851 424
daniele 29:1a47b7151851 425 }
daniele 29:1a47b7151851 426
daniele 29:1a47b7151851 427 static int retransmit(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len)
daniele 29:1a47b7151851 428 {
daniele 29:1a47b7151851 429 pico_dhcp_retry(cli);
daniele 29:1a47b7151851 430
daniele 29:1a47b7151851 431 if(cli->state == DHCPSTATE_DISCOVER)
daniele 29:1a47b7151851 432 dhclient_send(cli, PICO_DHCP_MSG_DISCOVER);
daniele 29:1a47b7151851 433 else if(cli->state == DHCPSTATE_RENEWING)
daniele 29:1a47b7151851 434 dhclient_send(cli, PICO_DHCP_MSG_REQUEST);
daniele 29:1a47b7151851 435 else
daniele 29:1a47b7151851 436 dbg("DHCPC: WARNING: should not get here in state %d!\n", cli->state);
daniele 29:1a47b7151851 437
daniele 29:1a47b7151851 438 return 0;
daniele 29:1a47b7151851 439
daniele 29:1a47b7151851 440 }
daniele 29:1a47b7151851 441
daniele 29:1a47b7151851 442 /**********************
daniele 29:1a47b7151851 443 * fsm implementation *
daniele 29:1a47b7151851 444 **********************/
daniele 29:1a47b7151851 445
daniele 29:1a47b7151851 446 struct dhcp_action_entry {
daniele 29:1a47b7151851 447 uint16_t tcpstate;
daniele 29:1a47b7151851 448 int (*offer)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
daniele 29:1a47b7151851 449 int (*ack)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
daniele 29:1a47b7151851 450 int (*nak)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
daniele 29:1a47b7151851 451 int (*timer1)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
daniele 29:1a47b7151851 452 int (*timer_lease)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
daniele 29:1a47b7151851 453 int (*timer_retransmit)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len);
daniele 29:1a47b7151851 454 };
daniele 29:1a47b7151851 455
daniele 29:1a47b7151851 456 static struct dhcp_action_entry dhcp_fsm[] = {
daniele 29:1a47b7151851 457 /* State offer ack nak timer1 timer_lease timer_retransmit*/
daniele 29:1a47b7151851 458 { DHCPSTATE_DISCOVER, recv_offer, NULL, NULL, NULL, reset, retransmit},
daniele 29:1a47b7151851 459 { DHCPSTATE_OFFER, NULL, NULL, NULL, NULL, reset, NULL},
daniele 29:1a47b7151851 460 { DHCPSTATE_REQUEST, NULL, recv_ack, reset, NULL, reset, retransmit},
daniele 29:1a47b7151851 461 { DHCPSTATE_BOUND, NULL, NULL, reset, renew, reset, NULL},
daniele 29:1a47b7151851 462 { DHCPSTATE_RENEWING, NULL, recv_ack, reset, NULL, reset, retransmit},
daniele 29:1a47b7151851 463 };
daniele 29:1a47b7151851 464
daniele 29:1a47b7151851 465
daniele 29:1a47b7151851 466 static void pico_dhcp_state_machine(int type, struct pico_dhcp_client_cookie* cli, uint8_t* data, int len)
daniele 29:1a47b7151851 467 {
daniele 29:1a47b7151851 468 dbg("DHCPC: received incoming event of type %d\n", type);
daniele 29:1a47b7151851 469 switch(type){
daniele 29:1a47b7151851 470 case PICO_DHCP_MSG_OFFER:
daniele 29:1a47b7151851 471 if(dhcp_fsm[cli->state].offer != NULL)
daniele 29:1a47b7151851 472 dhcp_fsm[cli->state].offer(cli, data, len);
daniele 29:1a47b7151851 473 break;
daniele 29:1a47b7151851 474 case PICO_DHCP_MSG_ACK:
daniele 29:1a47b7151851 475 if(dhcp_fsm[cli->state].ack != NULL){
daniele 29:1a47b7151851 476 dhcp_fsm[cli->state].ack(cli, data, len);
daniele 29:1a47b7151851 477 }
daniele 29:1a47b7151851 478 break;
daniele 29:1a47b7151851 479 case PICO_DHCP_MSG_NAK:
daniele 29:1a47b7151851 480 if(dhcp_fsm[cli->state].nak!= NULL){
daniele 29:1a47b7151851 481 dhcp_fsm[cli->state].nak(cli, data, len);
daniele 29:1a47b7151851 482 }
daniele 29:1a47b7151851 483 break;
daniele 29:1a47b7151851 484 case PICO_DHCP_EVENT_T1:
daniele 29:1a47b7151851 485 if(dhcp_fsm[cli->state].timer1!= NULL){
daniele 29:1a47b7151851 486 dhcp_fsm[cli->state].timer1(cli, NULL, 0);
daniele 29:1a47b7151851 487 }
daniele 29:1a47b7151851 488 break;
daniele 29:1a47b7151851 489 case PICO_DHCP_EVENT_LEASE:
daniele 29:1a47b7151851 490 if(dhcp_fsm[cli->state].timer_lease!= NULL){
daniele 29:1a47b7151851 491 dhcp_fsm[cli->state].timer_lease(cli, NULL, 0);
daniele 29:1a47b7151851 492 }
daniele 29:1a47b7151851 493 break;
daniele 29:1a47b7151851 494 case PICO_DHCP_EVENT_RETRANSMIT:
daniele 29:1a47b7151851 495 if(dhcp_fsm[cli->state].timer_retransmit!= NULL){
daniele 29:1a47b7151851 496 dhcp_fsm[cli->state].timer_retransmit(cli, NULL, 0);
daniele 29:1a47b7151851 497 }
daniele 29:1a47b7151851 498 break;
daniele 29:1a47b7151851 499 default:
daniele 29:1a47b7151851 500 dbg("DHCPC: event not supported yet!!\n");
daniele 29:1a47b7151851 501 break;
daniele 29:1a47b7151851 502 }
daniele 29:1a47b7151851 503 }
daniele 29:1a47b7151851 504
daniele 29:1a47b7151851 505
daniele 29:1a47b7151851 506 /*********************
daniele 29:1a47b7151851 507 * utility functions *
daniele 29:1a47b7151851 508 *********************/
daniele 29:1a47b7151851 509
daniele 29:1a47b7151851 510 static void pico_dhcp_retry(struct pico_dhcp_client_cookie *cli)
daniele 29:1a47b7151851 511 {
daniele 29:1a47b7151851 512 const int MAX_RETRY = 3;
daniele 29:1a47b7151851 513 uint32_t new_xid;
daniele 29:1a47b7151851 514 if (++cli->attempt > MAX_RETRY) {
daniele 29:1a47b7151851 515 cli->start_time = pico_tick;
daniele 29:1a47b7151851 516 cli->attempt = 0;
daniele 29:1a47b7151851 517 new_xid = pico_rand();
daniele 29:1a47b7151851 518 while(get_cookie_by_xid(new_xid) != NULL){
daniele 29:1a47b7151851 519 new_xid = pico_rand();
daniele 29:1a47b7151851 520 }
daniele 29:1a47b7151851 521 cli->xid = new_xid;
daniele 29:1a47b7151851 522 cli->state = DHCPSTATE_DISCOVER;
daniele 29:1a47b7151851 523 }
daniele 29:1a47b7151851 524 }
daniele 29:1a47b7151851 525
daniele 29:1a47b7151851 526 static int dhclient_send(struct pico_dhcp_client_cookie *cli, uint8_t msg_type)
daniele 29:1a47b7151851 527 {
daniele 29:1a47b7151851 528 uint8_t buf_out[DHCPC_DATAGRAM_SIZE] = {0};
daniele 29:1a47b7151851 529 struct pico_dhcphdr *dh_out = (struct pico_dhcphdr *) buf_out;
daniele 29:1a47b7151851 530 int sent = 0;
daniele 29:1a47b7151851 531 int i = 0;
daniele 29:1a47b7151851 532 struct pico_ip4 destination;
daniele 29:1a47b7151851 533 uint16_t port = PICO_DHCPD_PORT;
daniele 29:1a47b7151851 534 if(cli->state == DHCPSTATE_BOUND || cli->state == DHCPSTATE_RENEWING){
daniele 29:1a47b7151851 535 destination.addr = cli->server_id.addr;
daniele 29:1a47b7151851 536 }else{
daniele 29:1a47b7151851 537 destination.addr = long_be(0xFFFFFFFF);
daniele 29:1a47b7151851 538 }
daniele 29:1a47b7151851 539
daniele 29:1a47b7151851 540 if(cli->device->eth == NULL){
daniele 29:1a47b7151851 541 pico_err = PICO_ERR_EOPNOTSUPP;
daniele 29:1a47b7151851 542 if(cli->cb != NULL){
daniele 29:1a47b7151851 543 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 544 }
daniele 29:1a47b7151851 545 return -1;
daniele 29:1a47b7151851 546 }
daniele 29:1a47b7151851 547 memcpy(dh_out->hwaddr, &cli->device->eth->mac, PICO_HLEN_ETHER);
daniele 29:1a47b7151851 548 dh_out->op = PICO_DHCP_OP_REQUEST;
daniele 29:1a47b7151851 549 dh_out->htype = PICO_HTYPE_ETHER;
daniele 29:1a47b7151851 550 dh_out->hlen = PICO_HLEN_ETHER;
daniele 29:1a47b7151851 551 dh_out->xid = cli->xid;
daniele 29:1a47b7151851 552 dh_out->secs = (msg_type == PICO_DHCP_MSG_REQUEST)?0:short_be((pico_tick - cli->start_time)/1000);
daniele 29:1a47b7151851 553 dh_out->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE;
daniele 29:1a47b7151851 554 if (cli->state == DHCPSTATE_RENEWING)
daniele 29:1a47b7151851 555 dh_out->ciaddr = cli->address.addr;
daniele 29:1a47b7151851 556
daniele 29:1a47b7151851 557 /* Option: msg type, len 1 */
daniele 29:1a47b7151851 558 dh_out->options[i++] = PICO_DHCPOPT_MSGTYPE;
daniele 29:1a47b7151851 559 dh_out->options[i++] = 1;
daniele 29:1a47b7151851 560 dh_out->options[i++] = msg_type;
daniele 29:1a47b7151851 561
daniele 29:1a47b7151851 562 if (( msg_type == PICO_DHCP_MSG_REQUEST) && ( cli->state != DHCPSTATE_RENEWING )) {
daniele 29:1a47b7151851 563 dh_out->options[i++] = PICO_DHCPOPT_REQIP;
daniele 29:1a47b7151851 564 dh_out->options[i++] = 4;
daniele 29:1a47b7151851 565 dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF000000) >> 24;
daniele 29:1a47b7151851 566 dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF0000) >> 16;
daniele 29:1a47b7151851 567 dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF00) >> 8;
daniele 29:1a47b7151851 568 dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF);
daniele 29:1a47b7151851 569 dh_out->options[i++] = PICO_DHCPOPT_SERVERID;
daniele 29:1a47b7151851 570 dh_out->options[i++] = 4;
daniele 29:1a47b7151851 571 dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF000000) >> 24;
daniele 29:1a47b7151851 572 dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF0000) >> 16;
daniele 29:1a47b7151851 573 dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF00) >> 8;
daniele 29:1a47b7151851 574 dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF);
daniele 29:1a47b7151851 575 }
daniele 29:1a47b7151851 576
daniele 29:1a47b7151851 577 /* Option: req list, len 4 */
daniele 29:1a47b7151851 578 dh_out->options[i++] = PICO_DHCPOPT_PARMLIST;
daniele 29:1a47b7151851 579 dh_out->options[i++] = 7;
daniele 29:1a47b7151851 580 dh_out->options[i++] = PICO_DHCPOPT_NETMASK;
daniele 29:1a47b7151851 581 dh_out->options[i++] = PICO_DHCPOPT_BCAST;
daniele 29:1a47b7151851 582 dh_out->options[i++] = PICO_DHCPOPT_TIME;
daniele 29:1a47b7151851 583 dh_out->options[i++] = PICO_DHCPOPT_ROUTER;
daniele 29:1a47b7151851 584 dh_out->options[i++] = PICO_DHCPOPT_HOSTNAME;
daniele 29:1a47b7151851 585 dh_out->options[i++] = PICO_DHCPOPT_RENEWALTIME;
daniele 29:1a47b7151851 586 dh_out->options[i++] = PICO_DHCPOPT_REBINDINGTIME;
daniele 29:1a47b7151851 587
daniele 29:1a47b7151851 588 /* Option : max message size */
daniele 29:1a47b7151851 589 if( msg_type == PICO_DHCP_MSG_REQUEST || msg_type == PICO_DHCP_MSG_DISCOVER){
daniele 29:1a47b7151851 590 uint16_t dds = DHCPC_DATAGRAM_SIZE;
daniele 29:1a47b7151851 591 dh_out->options[i++] = PICO_DHCPOPT_MAXMSGSIZE;
daniele 29:1a47b7151851 592 dh_out->options[i++] = 2;
daniele 29:1a47b7151851 593 dh_out->options[i++] = (dds & 0xFF00) >> 8;
daniele 29:1a47b7151851 594 dh_out->options[i++] = (dds & 0xFF);
daniele 29:1a47b7151851 595 }
daniele 29:1a47b7151851 596
daniele 29:1a47b7151851 597
daniele 29:1a47b7151851 598
daniele 29:1a47b7151851 599 dh_out->options[i] = PICO_DHCPOPT_END;
daniele 29:1a47b7151851 600 sent = pico_socket_sendto(cli->socket, buf_out, DHCPC_DATAGRAM_SIZE, &destination, port);
daniele 29:1a47b7151851 601 if (sent < 0) {
daniele 29:1a47b7151851 602 dbg("DHCPC: sendto failed: %s\n", strerror(pico_err));
daniele 29:1a47b7151851 603 if(cli->cb != NULL)
daniele 29:1a47b7151851 604 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 605 }
daniele 29:1a47b7151851 606
daniele 29:1a47b7151851 607
daniele 29:1a47b7151851 608 //resend-timer :
daniele 29:1a47b7151851 609 if(cli->timer_param_retransmit != NULL)
daniele 29:1a47b7151851 610 cli->timer_param_retransmit->valid=0;
daniele 29:1a47b7151851 611
daniele 29:1a47b7151851 612 cli->timer_param_retransmit = pico_zalloc(sizeof(struct dhcp_timer_param));
daniele 29:1a47b7151851 613 if(!cli->timer_param_retransmit){
daniele 29:1a47b7151851 614 if(cli->cb != NULL)
daniele 29:1a47b7151851 615 pico_err = PICO_ERR_ENOMEM;
daniele 29:1a47b7151851 616 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 617 return -1;
daniele 29:1a47b7151851 618 }
daniele 29:1a47b7151851 619 cli->timer_param_retransmit->valid = 1;
daniele 29:1a47b7151851 620 cli->timer_param_retransmit->cli = cli;
daniele 29:1a47b7151851 621 cli->timer_param_retransmit->type = PICO_DHCP_EVENT_RETRANSMIT;
daniele 29:1a47b7151851 622 pico_timer_add(4000, dhcp_timer_cb, cli->timer_param_retransmit);
daniele 29:1a47b7151851 623
daniele 29:1a47b7151851 624 return 0;
daniele 29:1a47b7151851 625 }
daniele 29:1a47b7151851 626
daniele 29:1a47b7151851 627 //identifies type & does some preprocessing : checking if everything is valid
daniele 29:1a47b7151851 628 static int pico_dhcp_verify_and_identify_type(uint8_t* data, int len, struct pico_dhcp_client_cookie *cli)
daniele 29:1a47b7151851 629 {
daniele 29:1a47b7151851 630 struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) data;
daniele 29:1a47b7151851 631 uint8_t *nextopt, opt_data[20], opt_type;
daniele 29:1a47b7151851 632 int opt_len = 20;
daniele 29:1a47b7151851 633
daniele 29:1a47b7151851 634 if (dhdr->xid != cli->xid)
daniele 29:1a47b7151851 635 return 0;
daniele 29:1a47b7151851 636
daniele 29:1a47b7151851 637 if (!is_options_valid(dhdr->options, len - sizeof(struct pico_dhcphdr)))
daniele 29:1a47b7151851 638 return 0;
daniele 29:1a47b7151851 639
daniele 29:1a47b7151851 640 if( dhdr->dhcp_magic != PICO_DHCPD_MAGIC_COOKIE)
daniele 29:1a47b7151851 641 return 0;
daniele 29:1a47b7151851 642
daniele 29:1a47b7151851 643 opt_type = dhcp_get_next_option(dhdr->options, opt_data, &opt_len, &nextopt);
daniele 29:1a47b7151851 644 while (opt_type != PICO_DHCPOPT_END) {
daniele 29:1a47b7151851 645 /* parse interesting options here */
daniele 29:1a47b7151851 646 if (opt_type == PICO_DHCPOPT_MSGTYPE) {
daniele 29:1a47b7151851 647 return *opt_data;
daniele 29:1a47b7151851 648 }
daniele 29:1a47b7151851 649 opt_len = 20;
daniele 29:1a47b7151851 650 opt_type = dhcp_get_next_option(NULL, opt_data, &opt_len, &nextopt);
daniele 29:1a47b7151851 651 }
daniele 29:1a47b7151851 652 return 0;
daniele 29:1a47b7151851 653
daniele 29:1a47b7151851 654 }
daniele 29:1a47b7151851 655
daniele 29:1a47b7151851 656 static int init_cookie(struct pico_dhcp_client_cookie* cli)
daniele 29:1a47b7151851 657 {
daniele 29:1a47b7151851 658 uint8_t n = 3;
daniele 29:1a47b7151851 659 uint16_t port = PICO_DHCP_CLIENT_PORT;
daniele 29:1a47b7151851 660 struct pico_ip4 address, netmask;
daniele 29:1a47b7151851 661
daniele 29:1a47b7151851 662 address.addr = long_be(0x00000000);
daniele 29:1a47b7151851 663 netmask.addr = long_be(0x00000000);
daniele 29:1a47b7151851 664
daniele 29:1a47b7151851 665 cli->state = DHCPSTATE_DISCOVER;
daniele 29:1a47b7151851 666 cli->start_time = pico_tick;
daniele 29:1a47b7151851 667 cli->attempt = 0;
daniele 29:1a47b7151851 668
daniele 29:1a47b7151851 669 cli->socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_wakeup);
daniele 29:1a47b7151851 670 if (!cli->socket) {
daniele 29:1a47b7151851 671 dbg("DHCPC: error opening socket: %s\n", strerror(pico_err));
daniele 29:1a47b7151851 672 if(cli->cb != NULL)
daniele 29:1a47b7151851 673 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 674 return -1;
daniele 29:1a47b7151851 675 }
daniele 29:1a47b7151851 676 if (pico_socket_bind(cli->socket, &address, &port) != 0){
daniele 29:1a47b7151851 677 dbg("DHCPC: error binding socket: %s\n", strerror(pico_err));
daniele 29:1a47b7151851 678 pico_socket_close(cli->socket);
daniele 29:1a47b7151851 679 if(cli->cb != NULL)
daniele 29:1a47b7151851 680 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 681 return -1;
daniele 29:1a47b7151851 682 }
daniele 29:1a47b7151851 683 cli->socket->dev = cli->device;
daniele 29:1a47b7151851 684
daniele 29:1a47b7151851 685 if(pico_ipv4_link_add(cli->device, address, netmask) != 0){
daniele 29:1a47b7151851 686 dbg("DHCPC: error adding link: %s\n", strerror(pico_err));
daniele 29:1a47b7151851 687 if(cli->cb != NULL)
daniele 29:1a47b7151851 688 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 689 return -1;
daniele 29:1a47b7151851 690 }
daniele 29:1a47b7151851 691
daniele 29:1a47b7151851 692 /* attempt to generate a correct xid 3 times, then fail */
daniele 29:1a47b7151851 693 do {
daniele 29:1a47b7151851 694 cli->xid = pico_rand();
daniele 29:1a47b7151851 695 } while (!cli->xid && --n);
daniele 29:1a47b7151851 696 if (!cli->xid) {
daniele 29:1a47b7151851 697 if(cli->cb != NULL)
daniele 29:1a47b7151851 698 cli->cb(cli, PICO_DHCP_ERROR);
daniele 29:1a47b7151851 699 return -1;
daniele 29:1a47b7151851 700 }
daniele 29:1a47b7151851 701
daniele 29:1a47b7151851 702 return 0;
daniele 29:1a47b7151851 703 }
daniele 29:1a47b7151851 704
daniele 29:1a47b7151851 705 static struct pico_dhcp_client_cookie *get_cookie_by_xid(uint32_t xid)
daniele 29:1a47b7151851 706 {
daniele 29:1a47b7151851 707 struct pico_dhcp_client_cookie test = { }, *cookie = NULL;
daniele 29:1a47b7151851 708
daniele 29:1a47b7151851 709 if (!xid)
daniele 29:1a47b7151851 710 return NULL;
daniele 29:1a47b7151851 711
daniele 29:1a47b7151851 712 test.xid = xid;
daniele 29:1a47b7151851 713 cookie = pico_tree_findKey(&DHCPCookies, &test);
daniele 29:1a47b7151851 714 if (!cookie)
daniele 29:1a47b7151851 715 return NULL;
daniele 29:1a47b7151851 716 else
daniele 29:1a47b7151851 717 return cookie;
daniele 29:1a47b7151851 718 }
daniele 29:1a47b7151851 719
daniele 29:1a47b7151851 720 void *pico_dhcp_get_identifier(uint32_t xid)
daniele 29:1a47b7151851 721 {
daniele 29:1a47b7151851 722 return (void *) get_cookie_by_xid(xid);
daniele 29:1a47b7151851 723 }
daniele 29:1a47b7151851 724
daniele 29:1a47b7151851 725 static uint32_t get_xid(uint8_t* data)
daniele 29:1a47b7151851 726 {
daniele 29:1a47b7151851 727 struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) data;
daniele 29:1a47b7151851 728 return dhdr->xid;
daniele 29:1a47b7151851 729 }
daniele 29:1a47b7151851 730
daniele 29:1a47b7151851 731 #endif