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:
daniele
Date:
Sun Jun 16 20:19:44 2013 +0000
Revision:
29:1a47b7151851
Child:
51:ab4529a384a6
Updated from masterbranch;

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