CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2

Dependents:   USBEthernet_TEST

Fork of USB_Ethernet by Daniele Lacamera

Committer:
daniele
Date:
Sat Aug 03 13:16:14 2013 +0000
Revision:
2:540f6e142d59
Moved to single package

Who changed what in which revision?

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