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 31 11:34:20 2013 +0000
Revision:
6:55b47464d5bc
Integrated mbed friendly sockets;

Who changed what in which revision?

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