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:
Fri May 24 15:25:25 2013 +0000
Revision:
3:b4047e8a0123
Updated from main repo + fixed Mutexes;

Who changed what in which revision?

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