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

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

PicoTCP. Copyright (c) 2013 TASS Belgium NV.

Released under the GNU General Public License, version 2.

Different licensing models may exist, at the sole discretion of the Copyright holders.

Official homepage: http://www.picotcp.com

Bug tracker: https://github.com/tass-belgium/picotcp/issues

Development steps:

  • initial integration with mbed RTOS
  • generic mbed Ethernet driver
  • high performance NXP LPC1768 specific Ethernet driver
  • Multi-threading support for mbed RTOS
  • Berkeley sockets and integration with the New Socket API
  • Fork of the apps running on top of the New Socket API
  • Scheduling optimizations
  • Debugging/benchmarking/testing

Demo application (measuring TCP sender performance):

Import programlpc1768-picotcp-demo

A PicoTCP demo app testing the ethernet throughput on the lpc1768 mbed board.

Committer:
tass
Date:
Fri May 17 12:09:59 2013 +0000
Revision:
1:cfe8984a32b4
Parent:
libraries/picotcp/modules/pico_dhcp_client.c@0:d7f2341ab245
Update for smaller SOCKETQ

Who changed what in which revision?

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