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:
Mon Sep 02 08:02:21 2013 +0000
Revision:
51:ab4529a384a6
Parent:
29:1a47b7151851
Child:
61:392dc6d4c501
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
tass 51:ab4529a384a6 5 Authors: Kristof Roelants, Frederik Van Slycken
daniele 29:1a47b7151851 6 *********************************************************************/
daniele 29:1a47b7151851 7
tass 51:ab4529a384a6 8
daniele 29:1a47b7151851 9 #include "pico_dhcp_client.h"
daniele 29:1a47b7151851 10 #include "pico_stack.h"
daniele 29:1a47b7151851 11 #include "pico_config.h"
daniele 29:1a47b7151851 12 #include "pico_device.h"
daniele 29:1a47b7151851 13 #include "pico_ipv4.h"
daniele 29:1a47b7151851 14 #include "pico_socket.h"
tass 51:ab4529a384a6 15 #include "pico_eth.h"
daniele 29:1a47b7151851 16
daniele 29:1a47b7151851 17 #ifdef PICO_SUPPORT_DHCPC
tass 51:ab4529a384a6 18 #define dhcpc_dbg(...) do{}while(0)
tass 51:ab4529a384a6 19 //#define dhcpc_dbg dbg
daniele 29:1a47b7151851 20
tass 51:ab4529a384a6 21 /* timer values */
tass 51:ab4529a384a6 22 #define DHCP_CLIENT_REINIT 3000 /* msec */
tass 51:ab4529a384a6 23 #define DHCP_CLIENT_RETRANS 4 /* sec */
tass 51:ab4529a384a6 24 #define DHCP_CLIENT_RETRIES 3
tass 51:ab4529a384a6 25
tass 51:ab4529a384a6 26 #define DHCP_CLIENT_TIMER_STOPPED 0
tass 51:ab4529a384a6 27 #define DHCP_CLIENT_TIMER_STARTED 1
tass 51:ab4529a384a6 28
tass 51:ab4529a384a6 29 /* custom statuses */
tass 51:ab4529a384a6 30 #define DHCP_CLIENT_STATUS_INIT 0
tass 51:ab4529a384a6 31 #define DHCP_CLIENT_STATUS_SOCKET 1
tass 51:ab4529a384a6 32 #define DHCP_CLIENT_STATUS_BOUND 2
tass 51:ab4529a384a6 33 #define DHCP_CLIENT_STATUS_LINKED 3
tass 51:ab4529a384a6 34 #define DHCP_CLIENT_STATUS_TRANSMITTED 4
tass 51:ab4529a384a6 35 #define DHCP_CLIENT_STATUS_INITIALIZED 5
daniele 29:1a47b7151851 36
tass 51:ab4529a384a6 37 /* maximum size of a DHCP message */
tass 51:ab4529a384a6 38 #define DHCP_CLIENT_MAXMSGZISE PICO_IP_MTU
tass 51:ab4529a384a6 39
tass 51:ab4529a384a6 40 /* serialize client negotiations if multiple devices */
tass 51:ab4529a384a6 41 /* NOTE: ONLY initialization is serialized! */
tass 51:ab4529a384a6 42 static uint8_t pico_dhcp_client_mutex = 1;
daniele 29:1a47b7151851 43
tass 51:ab4529a384a6 44 enum dhcp_client_state {
tass 51:ab4529a384a6 45 DHCP_CLIENT_STATE_INIT_REBOOT = 0,
tass 51:ab4529a384a6 46 DHCP_CLIENT_STATE_REBOOTING,
tass 51:ab4529a384a6 47 DHCP_CLIENT_STATE_INIT,
tass 51:ab4529a384a6 48 DHCP_CLIENT_STATE_SELECTING,
tass 51:ab4529a384a6 49 DHCP_CLIENT_STATE_REQUESTING,
tass 51:ab4529a384a6 50 DHCP_CLIENT_STATE_BOUND,
tass 51:ab4529a384a6 51 DHCP_CLIENT_STATE_RENEWING,
tass 51:ab4529a384a6 52 DHCP_CLIENT_STATE_REBINDING
tass 51:ab4529a384a6 53 };
tass 51:ab4529a384a6 54
tass 51:ab4529a384a6 55 struct dhcp_client_timer
tass 51:ab4529a384a6 56 {
tass 51:ab4529a384a6 57 uint8_t state;
tass 51:ab4529a384a6 58 uint32_t time;
daniele 29:1a47b7151851 59 };
daniele 29:1a47b7151851 60
daniele 29:1a47b7151851 61 struct pico_dhcp_client_cookie
daniele 29:1a47b7151851 62 {
tass 51:ab4529a384a6 63 uint8_t status;
tass 51:ab4529a384a6 64 uint8_t event;
tass 51:ab4529a384a6 65 uint8_t retry;
daniele 29:1a47b7151851 66 uint32_t xid;
tass 51:ab4529a384a6 67 uint32_t *uid;
tass 51:ab4529a384a6 68 enum dhcp_client_state state;
tass 51:ab4529a384a6 69 void (*cb)(void* dhcpc, int code);
tass 51:ab4529a384a6 70 unsigned long init_timestamp;
tass 51:ab4529a384a6 71 struct pico_socket *s;
daniele 29:1a47b7151851 72 struct pico_ip4 address;
daniele 29:1a47b7151851 73 struct pico_ip4 netmask;
daniele 29:1a47b7151851 74 struct pico_ip4 gateway;
daniele 29:1a47b7151851 75 struct pico_ip4 nameserver;
daniele 29:1a47b7151851 76 struct pico_ip4 server_id;
tass 51:ab4529a384a6 77 struct pico_device *dev;
tass 51:ab4529a384a6 78 struct dhcp_client_timer init_timer;
tass 51:ab4529a384a6 79 struct dhcp_client_timer requesting_timer;
tass 51:ab4529a384a6 80 struct dhcp_client_timer renewing_timer;
tass 51:ab4529a384a6 81 struct dhcp_client_timer rebinding_timer;
tass 51:ab4529a384a6 82 struct dhcp_client_timer T1_timer;
tass 51:ab4529a384a6 83 struct dhcp_client_timer T2_timer;
tass 51:ab4529a384a6 84 struct dhcp_client_timer lease_timer;
daniele 29:1a47b7151851 85 };
daniele 29:1a47b7151851 86
tass 51:ab4529a384a6 87 static int pico_dhcp_client_init(struct pico_dhcp_client_cookie *dhcpc);
tass 51:ab4529a384a6 88 static int reset(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 51:ab4529a384a6 89 static int pico_dhcp_client_msg(struct pico_dhcp_client_cookie *dhcpc, uint8_t msg_type);
tass 51:ab4529a384a6 90 static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s);
tass 51:ab4529a384a6 91 static void pico_dhcp_state_machine(uint8_t event, struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 51:ab4529a384a6 92
daniele 29:1a47b7151851 93 static int dhcp_cookies_cmp(void *ka, void *kb)
daniele 29:1a47b7151851 94 {
daniele 29:1a47b7151851 95 struct pico_dhcp_client_cookie *a = ka, *b = kb;
tass 51:ab4529a384a6 96 if (a->xid == b->xid)
daniele 29:1a47b7151851 97 return 0;
tass 51:ab4529a384a6 98 return (a->xid < b->xid) ? -1 : 1;
daniele 29:1a47b7151851 99 }
daniele 29:1a47b7151851 100 PICO_TREE_DECLARE(DHCPCookies, dhcp_cookies_cmp);
daniele 29:1a47b7151851 101
tass 51:ab4529a384a6 102 static struct pico_dhcp_client_cookie *pico_dhcp_client_add_cookie(uint32_t xid, struct pico_device *dev, void (*cb)(void *dhcpc, int code), uint32_t *uid)
tass 51:ab4529a384a6 103 {
tass 51:ab4529a384a6 104 struct pico_dhcp_client_cookie *dhcpc = NULL, *found = NULL, test = {0};
tass 51:ab4529a384a6 105
tass 51:ab4529a384a6 106 test.xid = xid;
tass 51:ab4529a384a6 107 found = pico_tree_findKey(&DHCPCookies, &test);
tass 51:ab4529a384a6 108 if (found) {
tass 51:ab4529a384a6 109 pico_err = PICO_ERR_EAGAIN;
tass 51:ab4529a384a6 110 return NULL;
tass 51:ab4529a384a6 111 }
tass 51:ab4529a384a6 112
tass 51:ab4529a384a6 113 dhcpc = pico_zalloc(sizeof(struct pico_dhcp_client_cookie));
tass 51:ab4529a384a6 114 if (!dhcpc) {
tass 51:ab4529a384a6 115 pico_err = PICO_ERR_ENOMEM;
tass 51:ab4529a384a6 116 return NULL;
tass 51:ab4529a384a6 117 }
tass 51:ab4529a384a6 118
tass 51:ab4529a384a6 119 dhcpc->state = DHCP_CLIENT_STATE_INIT;
tass 51:ab4529a384a6 120 dhcpc->status = DHCP_CLIENT_STATUS_INIT;
tass 51:ab4529a384a6 121 dhcpc->xid = xid;
tass 51:ab4529a384a6 122 dhcpc->uid = uid;
tass 51:ab4529a384a6 123 *(dhcpc->uid) = 0;
tass 51:ab4529a384a6 124 dhcpc->cb = cb;
tass 51:ab4529a384a6 125 dhcpc->dev = dev;
tass 51:ab4529a384a6 126
tass 51:ab4529a384a6 127 pico_tree_insert(&DHCPCookies, dhcpc);
tass 51:ab4529a384a6 128 return dhcpc;
tass 51:ab4529a384a6 129 }
tass 51:ab4529a384a6 130
tass 51:ab4529a384a6 131 static int pico_dhcp_client_del_cookie(uint32_t xid)
tass 51:ab4529a384a6 132 {
tass 51:ab4529a384a6 133 struct pico_dhcp_client_cookie test = {0}, *found = NULL;
tass 51:ab4529a384a6 134
tass 51:ab4529a384a6 135 test.xid = xid;
tass 51:ab4529a384a6 136 found = pico_tree_findKey(&DHCPCookies, &test);
tass 51:ab4529a384a6 137 if (!found)
tass 51:ab4529a384a6 138 return -1;
tass 51:ab4529a384a6 139
tass 51:ab4529a384a6 140 pico_socket_close(found->s);
tass 51:ab4529a384a6 141 pico_tree_delete(&DHCPCookies, found);
tass 51:ab4529a384a6 142 pico_free(found);
tass 51:ab4529a384a6 143 return 0;
tass 51:ab4529a384a6 144 }
tass 51:ab4529a384a6 145
tass 51:ab4529a384a6 146 static struct pico_dhcp_client_cookie *pico_dhcp_client_find_cookie(uint32_t xid)
tass 51:ab4529a384a6 147 {
tass 51:ab4529a384a6 148 struct pico_dhcp_client_cookie test = {0}, *found = NULL;
tass 51:ab4529a384a6 149
tass 51:ab4529a384a6 150 test.xid = xid;
tass 51:ab4529a384a6 151 found = pico_tree_findKey(&DHCPCookies, &test);
tass 51:ab4529a384a6 152 if (found)
tass 51:ab4529a384a6 153 return found;
tass 51:ab4529a384a6 154 else
tass 51:ab4529a384a6 155 return NULL;
tass 51:ab4529a384a6 156 }
tass 51:ab4529a384a6 157
tass 51:ab4529a384a6 158 static void pico_dhcp_client_init_timer(unsigned long now, void *arg)
tass 51:ab4529a384a6 159 {
tass 51:ab4529a384a6 160 struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
tass 51:ab4529a384a6 161
tass 51:ab4529a384a6 162 if (dhcpc->init_timer.state == DHCP_CLIENT_TIMER_STOPPED)
tass 51:ab4529a384a6 163 return;
daniele 29:1a47b7151851 164
tass 51:ab4529a384a6 165 if (++dhcpc->retry >= DHCP_CLIENT_RETRIES) {
tass 51:ab4529a384a6 166 pico_err = PICO_ERR_EAGAIN;
tass 51:ab4529a384a6 167 dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
tass 51:ab4529a384a6 168 pico_dhcp_client_del_cookie(dhcpc->xid);
tass 51:ab4529a384a6 169 pico_dhcp_client_mutex++;
tass 51:ab4529a384a6 170 return;
tass 51:ab4529a384a6 171 }
tass 51:ab4529a384a6 172
tass 51:ab4529a384a6 173 /* init_timer is restarted in retransmit function,
tass 51:ab4529a384a6 174 * otherwise an old init_timer would go on indefinitely */
tass 51:ab4529a384a6 175 dhcpc->event = PICO_DHCP_EVENT_RETRANSMIT;
tass 51:ab4529a384a6 176 pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
tass 51:ab4529a384a6 177 return;
tass 51:ab4529a384a6 178 }
tass 51:ab4529a384a6 179
tass 51:ab4529a384a6 180 static void pico_dhcp_client_requesting_timer(unsigned long now, void *arg)
tass 51:ab4529a384a6 181 {
tass 51:ab4529a384a6 182 struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
tass 51:ab4529a384a6 183
tass 51:ab4529a384a6 184 if (dhcpc->requesting_timer.state == DHCP_CLIENT_TIMER_STOPPED)
tass 51:ab4529a384a6 185 return;
tass 51:ab4529a384a6 186
tass 51:ab4529a384a6 187 if (++dhcpc->retry > DHCP_CLIENT_RETRIES) {
tass 51:ab4529a384a6 188 pico_dhcp_client_mutex++;
tass 51:ab4529a384a6 189 reset(dhcpc, NULL);
tass 51:ab4529a384a6 190 return;
tass 51:ab4529a384a6 191 }
tass 51:ab4529a384a6 192
tass 51:ab4529a384a6 193 /* requesting_timer is restarted in retransmit function,
tass 51:ab4529a384a6 194 * otherwise an old requesting_timer would go on indefinitely */
tass 51:ab4529a384a6 195 dhcpc->event = PICO_DHCP_EVENT_RETRANSMIT;
tass 51:ab4529a384a6 196 pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
tass 51:ab4529a384a6 197 return;
tass 51:ab4529a384a6 198 }
daniele 29:1a47b7151851 199
tass 51:ab4529a384a6 200 static void pico_dhcp_client_renewing_timer(unsigned long now, void *arg)
tass 51:ab4529a384a6 201 {
tass 51:ab4529a384a6 202 struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
tass 51:ab4529a384a6 203
tass 51:ab4529a384a6 204 if (dhcpc->renewing_timer.state == DHCP_CLIENT_TIMER_STOPPED)
tass 51:ab4529a384a6 205 return;
tass 51:ab4529a384a6 206
tass 51:ab4529a384a6 207 /* renewing_timer is restarted in retransmit function,
tass 51:ab4529a384a6 208 * otherwise an old renewing_timer would go on indefinitely */
tass 51:ab4529a384a6 209 dhcpc->retry++;
tass 51:ab4529a384a6 210 dhcpc->event = PICO_DHCP_EVENT_RETRANSMIT;
tass 51:ab4529a384a6 211 pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
tass 51:ab4529a384a6 212 return;
tass 51:ab4529a384a6 213 }
tass 51:ab4529a384a6 214
tass 51:ab4529a384a6 215 static void pico_dhcp_client_rebinding_timer(unsigned long now, void *arg)
tass 51:ab4529a384a6 216 {
tass 51:ab4529a384a6 217 struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
tass 51:ab4529a384a6 218
tass 51:ab4529a384a6 219 if (dhcpc->rebinding_timer.state == DHCP_CLIENT_TIMER_STOPPED)
tass 51:ab4529a384a6 220 return;
tass 51:ab4529a384a6 221
tass 51:ab4529a384a6 222 /* rebinding_timer is restarted in retransmit function,
tass 51:ab4529a384a6 223 * otherwise an old rebinding_timer would go on indefinitely */
tass 51:ab4529a384a6 224 dhcpc->retry++;
tass 51:ab4529a384a6 225 dhcpc->event = PICO_DHCP_EVENT_RETRANSMIT;
tass 51:ab4529a384a6 226 pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
tass 51:ab4529a384a6 227 return;
tass 51:ab4529a384a6 228 }
tass 51:ab4529a384a6 229
tass 51:ab4529a384a6 230 static void pico_dhcp_client_T1_timer(unsigned long now, void *arg)
tass 51:ab4529a384a6 231 {
tass 51:ab4529a384a6 232 struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
tass 51:ab4529a384a6 233
tass 51:ab4529a384a6 234 if (dhcpc->T1_timer.state == DHCP_CLIENT_TIMER_STOPPED)
tass 51:ab4529a384a6 235 return;
daniele 29:1a47b7151851 236
tass 51:ab4529a384a6 237 /* T1 state is set to stopped in renew function,
tass 51:ab4529a384a6 238 * otherwise an old T1 could stop a valid T1 */
tass 51:ab4529a384a6 239 dhcpc->event = PICO_DHCP_EVENT_T1;
tass 51:ab4529a384a6 240 pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
tass 51:ab4529a384a6 241 return;
tass 51:ab4529a384a6 242 }
tass 51:ab4529a384a6 243
tass 51:ab4529a384a6 244 static void pico_dhcp_client_T2_timer(unsigned long now, void *arg)
tass 51:ab4529a384a6 245 {
tass 51:ab4529a384a6 246 struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
tass 51:ab4529a384a6 247
tass 51:ab4529a384a6 248 if (dhcpc->T2_timer.state == DHCP_CLIENT_TIMER_STOPPED)
tass 51:ab4529a384a6 249 return;
tass 51:ab4529a384a6 250
tass 51:ab4529a384a6 251 /* T2 state is set to stopped in rebind function,
tass 51:ab4529a384a6 252 * otherwise an old T2 could stop a valid T2.
tass 51:ab4529a384a6 253 * Likewise for renewing_timer */
tass 51:ab4529a384a6 254 dhcpc->event = PICO_DHCP_EVENT_T2;
tass 51:ab4529a384a6 255 pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
tass 51:ab4529a384a6 256 return;
tass 51:ab4529a384a6 257 }
tass 51:ab4529a384a6 258
tass 51:ab4529a384a6 259 static void pico_dhcp_client_lease_timer(unsigned long now, void *arg)
tass 51:ab4529a384a6 260 {
tass 51:ab4529a384a6 261 struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
tass 51:ab4529a384a6 262
tass 51:ab4529a384a6 263 if (dhcpc->lease_timer.state == DHCP_CLIENT_TIMER_STOPPED)
tass 51:ab4529a384a6 264 return;
tass 51:ab4529a384a6 265
tass 51:ab4529a384a6 266 /* lease state is set to stopped in reset function,
tass 51:ab4529a384a6 267 * otherwise an old lease could stop a valid lease.
tass 51:ab4529a384a6 268 * Likewise for rebinding_timer */
tass 51:ab4529a384a6 269 dhcpc->event = PICO_DHCP_EVENT_LEASE;
tass 51:ab4529a384a6 270 pico_dhcp_state_machine(dhcpc->event, dhcpc, NULL);
tass 51:ab4529a384a6 271 return;
tass 51:ab4529a384a6 272 }
tass 51:ab4529a384a6 273
tass 51:ab4529a384a6 274 static void pico_dhcp_client_reinit(unsigned long now, void *arg)
tass 51:ab4529a384a6 275 {
tass 51:ab4529a384a6 276 struct pico_dhcp_client_cookie *dhcpc = (struct pico_dhcp_client_cookie *)arg;
tass 51:ab4529a384a6 277
tass 51:ab4529a384a6 278 if (++dhcpc->retry > DHCP_CLIENT_RETRIES) {
tass 51:ab4529a384a6 279 pico_err = PICO_ERR_EAGAIN;
tass 51:ab4529a384a6 280 dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
tass 51:ab4529a384a6 281 pico_dhcp_client_del_cookie(dhcpc->xid);
tass 51:ab4529a384a6 282 return;
tass 51:ab4529a384a6 283 }
tass 51:ab4529a384a6 284 pico_dhcp_client_init(dhcpc);
tass 51:ab4529a384a6 285 return;
tass 51:ab4529a384a6 286 }
tass 51:ab4529a384a6 287
tass 51:ab4529a384a6 288 static void pico_dhcp_client_stop_timers(struct pico_dhcp_client_cookie *dhcpc)
tass 51:ab4529a384a6 289 {
tass 51:ab4529a384a6 290 dhcpc->retry = 0;
tass 51:ab4529a384a6 291 dhcpc->init_timer.state = DHCP_CLIENT_TIMER_STOPPED;
tass 51:ab4529a384a6 292 dhcpc->requesting_timer.state = DHCP_CLIENT_TIMER_STOPPED;
tass 51:ab4529a384a6 293 dhcpc->renewing_timer.state = DHCP_CLIENT_TIMER_STOPPED;
tass 51:ab4529a384a6 294 dhcpc->rebinding_timer.state = DHCP_CLIENT_TIMER_STOPPED;
tass 51:ab4529a384a6 295 dhcpc->T1_timer.state = DHCP_CLIENT_TIMER_STOPPED;
tass 51:ab4529a384a6 296 dhcpc->T2_timer.state = DHCP_CLIENT_TIMER_STOPPED;
tass 51:ab4529a384a6 297 dhcpc->lease_timer.state = DHCP_CLIENT_TIMER_STOPPED;
tass 51:ab4529a384a6 298
tass 51:ab4529a384a6 299 return;
tass 51:ab4529a384a6 300 }
tass 51:ab4529a384a6 301
tass 51:ab4529a384a6 302 static void pico_dhcp_client_start_init_timer(struct pico_dhcp_client_cookie *dhcpc)
tass 51:ab4529a384a6 303 {
tass 51:ab4529a384a6 304 uint32_t time = 0;
daniele 29:1a47b7151851 305
tass 51:ab4529a384a6 306 /* timer value is doubled with every retry (exponential backoff) */
tass 51:ab4529a384a6 307 dhcpc->init_timer.state = DHCP_CLIENT_TIMER_STARTED;
tass 51:ab4529a384a6 308 dhcpc->init_timer.time = DHCP_CLIENT_RETRANS;
tass 51:ab4529a384a6 309 time = dhcpc->init_timer.time << dhcpc->retry;
tass 51:ab4529a384a6 310 pico_timer_add(time * 1000, pico_dhcp_client_init_timer, dhcpc);
tass 51:ab4529a384a6 311
tass 51:ab4529a384a6 312 return;
tass 51:ab4529a384a6 313 }
tass 51:ab4529a384a6 314
tass 51:ab4529a384a6 315 static void pico_dhcp_client_start_requesting_timer(struct pico_dhcp_client_cookie *dhcpc)
tass 51:ab4529a384a6 316 {
tass 51:ab4529a384a6 317 uint32_t time = 0;
tass 51:ab4529a384a6 318
tass 51:ab4529a384a6 319 /* timer value is doubled with every retry (exponential backoff) */
tass 51:ab4529a384a6 320 dhcpc->init_timer.state = DHCP_CLIENT_TIMER_STOPPED;
tass 51:ab4529a384a6 321 dhcpc->requesting_timer.state = DHCP_CLIENT_TIMER_STARTED;
tass 51:ab4529a384a6 322 dhcpc->requesting_timer.time = DHCP_CLIENT_RETRANS;
tass 51:ab4529a384a6 323 time = dhcpc->requesting_timer.time << dhcpc->retry;
tass 51:ab4529a384a6 324 pico_timer_add(time * 1000, pico_dhcp_client_requesting_timer, dhcpc);
tass 51:ab4529a384a6 325
tass 51:ab4529a384a6 326 return;
tass 51:ab4529a384a6 327 }
tass 51:ab4529a384a6 328
tass 51:ab4529a384a6 329 static void pico_dhcp_client_start_renewing_timer(struct pico_dhcp_client_cookie *dhcpc)
tass 51:ab4529a384a6 330 {
tass 51:ab4529a384a6 331 uint32_t halftime = 0;
tass 51:ab4529a384a6 332
tass 51:ab4529a384a6 333 /* wait one-half of the remaining time until T2, down to a minimum of 60 seconds */
tass 51:ab4529a384a6 334 /* (dhcpc->retry + 1): initial -> divide by 2, 1st retry -> divide by 4, 2nd retry -> divide by 8, etc */
tass 51:ab4529a384a6 335 dhcpc->T1_timer.state = DHCP_CLIENT_TIMER_STOPPED;
tass 51:ab4529a384a6 336 dhcpc->renewing_timer.state = DHCP_CLIENT_TIMER_STARTED;
tass 51:ab4529a384a6 337 halftime = dhcpc->renewing_timer.time >> (dhcpc->retry + 1);
tass 51:ab4529a384a6 338 if (halftime < 60)
tass 51:ab4529a384a6 339 halftime = 60;
tass 51:ab4529a384a6 340 pico_timer_add(halftime * 1000, pico_dhcp_client_renewing_timer, dhcpc);
tass 51:ab4529a384a6 341
tass 51:ab4529a384a6 342 return;
tass 51:ab4529a384a6 343 }
daniele 29:1a47b7151851 344
tass 51:ab4529a384a6 345 static void pico_dhcp_client_start_rebinding_timer(struct pico_dhcp_client_cookie *dhcpc)
tass 51:ab4529a384a6 346 {
tass 51:ab4529a384a6 347 uint32_t halftime = 0;
tass 51:ab4529a384a6 348
tass 51:ab4529a384a6 349 /* wait one-half of the remaining time until T2, down to a minimum of 60 seconds */
tass 51:ab4529a384a6 350 /* (dhcpc->retry + 1): initial -> divide by 2, 1st retry -> divide by 4, 2nd retry -> divide by 8, etc */
tass 51:ab4529a384a6 351 dhcpc->T2_timer.state = DHCP_CLIENT_TIMER_STOPPED;
tass 51:ab4529a384a6 352 dhcpc->renewing_timer.state = DHCP_CLIENT_TIMER_STOPPED;
tass 51:ab4529a384a6 353 dhcpc->rebinding_timer.state = DHCP_CLIENT_TIMER_STARTED;
tass 51:ab4529a384a6 354 halftime = dhcpc->rebinding_timer.time >> (dhcpc->retry + 1);
tass 51:ab4529a384a6 355 if (halftime < 60)
tass 51:ab4529a384a6 356 halftime = 60;
tass 51:ab4529a384a6 357 pico_timer_add(halftime * 1000, pico_dhcp_client_rebinding_timer, dhcpc);
tass 51:ab4529a384a6 358
tass 51:ab4529a384a6 359 return;
tass 51:ab4529a384a6 360 }
daniele 29:1a47b7151851 361
tass 51:ab4529a384a6 362 static void pico_dhcp_client_start_reacquisition_timers(struct pico_dhcp_client_cookie *dhcpc)
daniele 29:1a47b7151851 363 {
tass 51:ab4529a384a6 364 dhcpc->requesting_timer.state = DHCP_CLIENT_TIMER_STOPPED;
tass 51:ab4529a384a6 365 dhcpc->T1_timer.state = DHCP_CLIENT_TIMER_STARTED;
tass 51:ab4529a384a6 366 dhcpc->T2_timer.state = DHCP_CLIENT_TIMER_STARTED;
tass 51:ab4529a384a6 367 dhcpc->lease_timer.state = DHCP_CLIENT_TIMER_STARTED;
tass 51:ab4529a384a6 368 pico_timer_add(dhcpc->T1_timer.time * 1000, pico_dhcp_client_T1_timer, dhcpc);
tass 51:ab4529a384a6 369 pico_timer_add(dhcpc->T2_timer.time * 1000, pico_dhcp_client_T2_timer, dhcpc);
tass 51:ab4529a384a6 370 pico_timer_add(dhcpc->lease_timer.time * 1000, pico_dhcp_client_lease_timer, dhcpc);
tass 51:ab4529a384a6 371
tass 51:ab4529a384a6 372 return;
tass 51:ab4529a384a6 373 }
tass 51:ab4529a384a6 374
tass 51:ab4529a384a6 375 static int pico_dhcp_client_init(struct pico_dhcp_client_cookie *dhcpc)
tass 51:ab4529a384a6 376 {
tass 51:ab4529a384a6 377 uint16_t port = PICO_DHCP_CLIENT_PORT;
tass 51:ab4529a384a6 378 struct pico_ip4 inaddr_any = {0}, netmask = {0};
tass 51:ab4529a384a6 379
tass 51:ab4529a384a6 380 /* serialize client negotations if multiple devices */
tass 51:ab4529a384a6 381 /* NOTE: ONLY initialization is serialized! */
tass 51:ab4529a384a6 382 if (!pico_dhcp_client_mutex) {
tass 51:ab4529a384a6 383 pico_timer_add(DHCP_CLIENT_REINIT, pico_dhcp_client_reinit, dhcpc);
daniele 29:1a47b7151851 384 return 0;
daniele 29:1a47b7151851 385 }
tass 51:ab4529a384a6 386 pico_dhcp_client_mutex--;
tass 51:ab4529a384a6 387
tass 51:ab4529a384a6 388 switch (dhcpc->status)
tass 51:ab4529a384a6 389 {
tass 51:ab4529a384a6 390 case DHCP_CLIENT_STATUS_INIT:
tass 51:ab4529a384a6 391 dhcpc->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_client_wakeup);
tass 51:ab4529a384a6 392 if (!dhcpc->s) {
tass 51:ab4529a384a6 393 pico_dhcp_client_mutex++;
tass 51:ab4529a384a6 394 pico_timer_add(DHCP_CLIENT_REINIT, pico_dhcp_client_reinit, dhcpc);
tass 51:ab4529a384a6 395 break;
tass 51:ab4529a384a6 396 }
tass 51:ab4529a384a6 397 dhcpc->s->dev = dhcpc->dev;
tass 51:ab4529a384a6 398 dhcpc->status = DHCP_CLIENT_STATUS_SOCKET;
tass 51:ab4529a384a6 399 /* fallthrough */
tass 51:ab4529a384a6 400
tass 51:ab4529a384a6 401 case DHCP_CLIENT_STATUS_SOCKET:
tass 51:ab4529a384a6 402 if (pico_socket_bind(dhcpc->s, &inaddr_any, &port) < 0) {
tass 51:ab4529a384a6 403 pico_dhcp_client_mutex++;
tass 51:ab4529a384a6 404 pico_timer_add(DHCP_CLIENT_REINIT, pico_dhcp_client_reinit, dhcpc);
tass 51:ab4529a384a6 405 break;
tass 51:ab4529a384a6 406 }
tass 51:ab4529a384a6 407 dhcpc->status = DHCP_CLIENT_STATUS_BOUND;
tass 51:ab4529a384a6 408 /* fallthrough */
tass 51:ab4529a384a6 409
tass 51:ab4529a384a6 410 case DHCP_CLIENT_STATUS_BOUND:
tass 51:ab4529a384a6 411 /* adding a link with address 0.0.0.0 and netmask 0.0.0.0,
tass 51:ab4529a384a6 412 * automatically adds a route for a global broadcast */
tass 51:ab4529a384a6 413 if (pico_ipv4_link_add(dhcpc->dev, inaddr_any, netmask) < 0) {
tass 51:ab4529a384a6 414 pico_dhcp_client_mutex++;
tass 51:ab4529a384a6 415 pico_timer_add(DHCP_CLIENT_REINIT, pico_dhcp_client_reinit, dhcpc);
tass 51:ab4529a384a6 416 break;
tass 51:ab4529a384a6 417 }
tass 51:ab4529a384a6 418 dhcpc->status = DHCP_CLIENT_STATUS_LINKED;
tass 51:ab4529a384a6 419 /* fallthrough */
tass 51:ab4529a384a6 420
tass 51:ab4529a384a6 421 case DHCP_CLIENT_STATUS_LINKED:
tass 51:ab4529a384a6 422 if (pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER) < 0) {
tass 51:ab4529a384a6 423 pico_dhcp_client_mutex++;
tass 51:ab4529a384a6 424 pico_timer_add(DHCP_CLIENT_REINIT, pico_dhcp_client_reinit, dhcpc);
tass 51:ab4529a384a6 425 break;
tass 51:ab4529a384a6 426 }
tass 51:ab4529a384a6 427 dhcpc->status = DHCP_CLIENT_STATUS_TRANSMITTED;
tass 51:ab4529a384a6 428 /* fallthrough */
tass 51:ab4529a384a6 429
tass 51:ab4529a384a6 430 case DHCP_CLIENT_STATUS_TRANSMITTED:
tass 51:ab4529a384a6 431 dhcpc->retry = 0;
tass 51:ab4529a384a6 432 dhcpc->init_timestamp = PICO_TIME_MS();
tass 51:ab4529a384a6 433 pico_dhcp_client_start_init_timer(dhcpc);
tass 51:ab4529a384a6 434 break;
tass 51:ab4529a384a6 435
tass 51:ab4529a384a6 436 default:
tass 51:ab4529a384a6 437 return -1;
tass 51:ab4529a384a6 438 }
tass 51:ab4529a384a6 439 return 0;
tass 51:ab4529a384a6 440 }
tass 51:ab4529a384a6 441
tass 51:ab4529a384a6 442 int pico_dhcp_initiate_negotiation(struct pico_device *dev, void (*cb)(void *dhcpc, int code), uint32_t *uid)
tass 51:ab4529a384a6 443 {
tass 51:ab4529a384a6 444 uint8_t retry = 32;
tass 51:ab4529a384a6 445 uint32_t xid = 0;
tass 51:ab4529a384a6 446 struct pico_dhcp_client_cookie *dhcpc = NULL;
tass 51:ab4529a384a6 447
tass 51:ab4529a384a6 448 if (!dev || !cb || !uid) {
tass 51:ab4529a384a6 449 pico_err = PICO_ERR_EINVAL;
tass 51:ab4529a384a6 450 return -1;
tass 51:ab4529a384a6 451 }
tass 51:ab4529a384a6 452 if (!dev->eth) {
tass 51:ab4529a384a6 453 pico_err = PICO_ERR_EOPNOTSUPP;
tass 51:ab4529a384a6 454 return -1;
tass 51:ab4529a384a6 455 }
tass 51:ab4529a384a6 456
tass 51:ab4529a384a6 457 /* attempt to generate a correct xid, else fail */
tass 51:ab4529a384a6 458 do {
tass 51:ab4529a384a6 459 xid = pico_rand();
tass 51:ab4529a384a6 460 } while (!xid && --retry);
tass 51:ab4529a384a6 461
tass 51:ab4529a384a6 462 if (!xid) {
tass 51:ab4529a384a6 463 pico_err = PICO_ERR_EAGAIN;
tass 51:ab4529a384a6 464 return -1;
tass 51:ab4529a384a6 465 }
tass 51:ab4529a384a6 466
tass 51:ab4529a384a6 467 dhcpc = pico_dhcp_client_add_cookie(xid, dev, cb, uid);
tass 51:ab4529a384a6 468 if (!dhcpc)
tass 51:ab4529a384a6 469 return -1;
tass 51:ab4529a384a6 470
tass 51:ab4529a384a6 471 dhcpc_dbg("DHCP client: cookie with xid %u\n", dhcpc->xid);
tass 51:ab4529a384a6 472 return pico_dhcp_client_init(dhcpc);
tass 51:ab4529a384a6 473 }
daniele 29:1a47b7151851 474
tass 51:ab4529a384a6 475 static void pico_dhcp_client_recv_params(struct pico_dhcp_client_cookie *dhcpc, struct pico_dhcp_opt *opt)
tass 51:ab4529a384a6 476 {
tass 51:ab4529a384a6 477 do {
tass 51:ab4529a384a6 478 switch (opt->code)
tass 51:ab4529a384a6 479 {
tass 51:ab4529a384a6 480 case PICO_DHCP_OPT_PAD:
tass 51:ab4529a384a6 481 break;
tass 51:ab4529a384a6 482
tass 51:ab4529a384a6 483 case PICO_DHCP_OPT_END:
tass 51:ab4529a384a6 484 break;
tass 51:ab4529a384a6 485
tass 51:ab4529a384a6 486 case PICO_DHCP_OPT_MSGTYPE:
tass 51:ab4529a384a6 487 dhcpc->event = opt->ext.msg_type.type;
tass 51:ab4529a384a6 488 dhcpc_dbg("DHCP client: message type %u\n", dhcpc->event);
tass 51:ab4529a384a6 489 break;
tass 51:ab4529a384a6 490
tass 51:ab4529a384a6 491 case PICO_DHCP_OPT_LEASETIME:
tass 51:ab4529a384a6 492 dhcpc->lease_timer.time = long_be(opt->ext.lease_time.time);
tass 51:ab4529a384a6 493 dhcpc_dbg("DHCP client: lease time %u\n", dhcpc->lease_timer.time);
tass 51:ab4529a384a6 494 break;
tass 51:ab4529a384a6 495
tass 51:ab4529a384a6 496 case PICO_DHCP_OPT_RENEWALTIME:
tass 51:ab4529a384a6 497 dhcpc->T1_timer.time = long_be(opt->ext.renewal_time.time);
tass 51:ab4529a384a6 498 dhcpc_dbg("DHCP client: renewal time %u\n", dhcpc->T1_timer.time);
tass 51:ab4529a384a6 499 break;
tass 51:ab4529a384a6 500
tass 51:ab4529a384a6 501 case PICO_DHCP_OPT_REBINDINGTIME:
tass 51:ab4529a384a6 502 dhcpc->T2_timer.time = long_be(opt->ext.rebinding_time.time);
tass 51:ab4529a384a6 503 dhcpc_dbg("DHCP client: rebinding time %u\n", dhcpc->T2_timer.time);
tass 51:ab4529a384a6 504 break;
tass 51:ab4529a384a6 505
tass 51:ab4529a384a6 506 case PICO_DHCP_OPT_ROUTER:
tass 51:ab4529a384a6 507 dhcpc->gateway = opt->ext.router.ip;
tass 51:ab4529a384a6 508 dhcpc_dbg("DHCP client: router %08X\n", dhcpc->gateway.addr);
tass 51:ab4529a384a6 509 break;
tass 51:ab4529a384a6 510
tass 51:ab4529a384a6 511 case PICO_DHCP_OPT_DNS:
tass 51:ab4529a384a6 512 dhcpc->nameserver = opt->ext.dns.ip;
tass 51:ab4529a384a6 513 dhcpc_dbg("DHCP client: dns %08X\n", dhcpc->nameserver.addr);
tass 51:ab4529a384a6 514 break;
tass 51:ab4529a384a6 515
tass 51:ab4529a384a6 516 case PICO_DHCP_OPT_NETMASK:
tass 51:ab4529a384a6 517 dhcpc->netmask = opt->ext.netmask.ip;
tass 51:ab4529a384a6 518 dhcpc_dbg("DHCP client: netmask %08X\n", dhcpc->netmask.addr);
tass 51:ab4529a384a6 519 break;
tass 51:ab4529a384a6 520
tass 51:ab4529a384a6 521 case PICO_DHCP_OPT_SERVERID:
tass 51:ab4529a384a6 522 dhcpc->server_id = opt->ext.server_id.ip;
tass 51:ab4529a384a6 523 dhcpc_dbg("DHCP client: server ID %08X\n", dhcpc->server_id.addr);
tass 51:ab4529a384a6 524 break;
tass 51:ab4529a384a6 525
tass 51:ab4529a384a6 526 case PICO_DHCP_OPT_OPTOVERLOAD:
tass 51:ab4529a384a6 527 dhcpc_dbg("DHCP client: WARNING option overload present (not processed)");
tass 51:ab4529a384a6 528 break;
tass 51:ab4529a384a6 529
tass 51:ab4529a384a6 530 default:
tass 51:ab4529a384a6 531 dhcpc_dbg("DHCP client: WARNING unsupported option %u\n", opt->code);
tass 51:ab4529a384a6 532 break;
tass 51:ab4529a384a6 533 }
tass 51:ab4529a384a6 534 } while (pico_dhcp_next_option(&opt));
tass 51:ab4529a384a6 535
tass 51:ab4529a384a6 536 /* default values for T1 and T2 when not provided */
tass 51:ab4529a384a6 537 if (!dhcpc->T1_timer.time)
tass 51:ab4529a384a6 538 dhcpc->T1_timer.time = dhcpc->lease_timer.time >> 1;
tass 51:ab4529a384a6 539 if (!dhcpc->T2_timer.time)
tass 51:ab4529a384a6 540 dhcpc->T2_timer.time = (dhcpc->lease_timer.time * 875) / 1000;
tass 51:ab4529a384a6 541
tass 51:ab4529a384a6 542 return;
tass 51:ab4529a384a6 543 }
tass 51:ab4529a384a6 544
tass 51:ab4529a384a6 545 static int recv_offer(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
tass 51:ab4529a384a6 546 {
tass 51:ab4529a384a6 547 struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf;
tass 51:ab4529a384a6 548 struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)hdr->options;
tass 51:ab4529a384a6 549
tass 51:ab4529a384a6 550 pico_dhcp_client_recv_params(dhcpc, opt);
tass 51:ab4529a384a6 551 if ((dhcpc->event != PICO_DHCP_MSG_OFFER) || !dhcpc->server_id.addr || !dhcpc->netmask.addr || !dhcpc->lease_timer.time)
tass 51:ab4529a384a6 552 return -1;
tass 51:ab4529a384a6 553 dhcpc->address.addr = hdr->yiaddr;
tass 51:ab4529a384a6 554
tass 51:ab4529a384a6 555 /* we skip state SELECTING, process first offer received */
tass 51:ab4529a384a6 556 dhcpc->state = DHCP_CLIENT_STATE_REQUESTING;
tass 51:ab4529a384a6 557 dhcpc->retry = 0;
tass 51:ab4529a384a6 558 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
tass 51:ab4529a384a6 559 pico_dhcp_client_start_requesting_timer(dhcpc);
tass 51:ab4529a384a6 560 return 0;
tass 51:ab4529a384a6 561 }
tass 51:ab4529a384a6 562
tass 51:ab4529a384a6 563 static int recv_ack(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
tass 51:ab4529a384a6 564 {
tass 51:ab4529a384a6 565 struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf;
tass 51:ab4529a384a6 566 struct pico_dhcp_opt *opt = (struct pico_dhcp_opt *)hdr->options;
tass 51:ab4529a384a6 567 struct pico_ip4 address = {0}, netmask = {0}, inaddr_any = {0}, bcast = { .addr = 0xFFFFFFFF };
tass 51:ab4529a384a6 568
tass 51:ab4529a384a6 569 pico_dhcp_client_recv_params(dhcpc, opt);
tass 51:ab4529a384a6 570 if ((dhcpc->event != PICO_DHCP_MSG_ACK) || !dhcpc->server_id.addr || !dhcpc->netmask.addr || !dhcpc->lease_timer.time)
daniele 29:1a47b7151851 571 return -1;
daniele 29:1a47b7151851 572
tass 51:ab4529a384a6 573 /* close the socket used for address (re)acquisition */
tass 51:ab4529a384a6 574 pico_socket_close(dhcpc->s);
tass 51:ab4529a384a6 575 /* delete the link with address 0.0.0.0, add new link with acquired address */
tass 51:ab4529a384a6 576 if (dhcpc->status == DHCP_CLIENT_STATUS_TRANSMITTED) {
tass 51:ab4529a384a6 577 pico_ipv4_link_del(dhcpc->dev, address);
tass 51:ab4529a384a6 578 pico_ipv4_link_add(dhcpc->dev, dhcpc->address, dhcpc->netmask);
tass 51:ab4529a384a6 579 dhcpc->status = DHCP_CLIENT_STATUS_INITIALIZED;
tass 51:ab4529a384a6 580 }
tass 51:ab4529a384a6 581 /* delete the default route for our global broadcast messages, otherwise another interface can not rebind */
tass 51:ab4529a384a6 582 if (dhcpc->state == DHCP_CLIENT_STATE_REBINDING)
tass 51:ab4529a384a6 583 pico_ipv4_route_del(bcast, netmask, inaddr_any, 1, pico_ipv4_link_get(&dhcpc->address));
tass 51:ab4529a384a6 584
tass 51:ab4529a384a6 585 dbg("DHCP client: renewal time (T1) %u\n", dhcpc->T1_timer.time);
tass 51:ab4529a384a6 586 dbg("DHCP client: rebinding time (T2) %u\n", dhcpc->T2_timer.time);
tass 51:ab4529a384a6 587 dbg("DHCP client: lease time %u\n", dhcpc->lease_timer.time);
tass 51:ab4529a384a6 588
tass 51:ab4529a384a6 589 dhcpc->retry = 0;
tass 51:ab4529a384a6 590 dhcpc->renewing_timer.time = dhcpc->T2_timer.time - dhcpc->T1_timer.time;
tass 51:ab4529a384a6 591 dhcpc->rebinding_timer.time = dhcpc->lease_timer.time - dhcpc->T2_timer.time;
tass 51:ab4529a384a6 592 pico_dhcp_client_start_reacquisition_timers(dhcpc);
tass 51:ab4529a384a6 593
tass 51:ab4529a384a6 594 pico_dhcp_client_mutex++;
tass 51:ab4529a384a6 595 *(dhcpc->uid) = dhcpc->xid;
tass 51:ab4529a384a6 596 dhcpc->cb(dhcpc, PICO_DHCP_SUCCESS);
tass 51:ab4529a384a6 597 dhcpc->state = DHCP_CLIENT_STATE_BOUND;
tass 51:ab4529a384a6 598 return 0;
tass 51:ab4529a384a6 599 }
tass 51:ab4529a384a6 600
tass 51:ab4529a384a6 601 static int renew(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
tass 51:ab4529a384a6 602 {
tass 51:ab4529a384a6 603 uint16_t port = PICO_DHCP_CLIENT_PORT;
tass 51:ab4529a384a6 604
tass 51:ab4529a384a6 605 dhcpc->state = DHCP_CLIENT_STATE_RENEWING;
tass 51:ab4529a384a6 606 dhcpc->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_client_wakeup);
tass 51:ab4529a384a6 607 if (!dhcpc->s) {
tass 51:ab4529a384a6 608 dhcpc_dbg("DHCP client ERROR: failure opening socket on renew, aborting DHCP! (%s)\n", strerror(pico_err));
tass 51:ab4529a384a6 609 dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
tass 51:ab4529a384a6 610 return -1;
tass 51:ab4529a384a6 611 }
tass 51:ab4529a384a6 612 if (pico_socket_bind(dhcpc->s, &dhcpc->address, &port) != 0) {
tass 51:ab4529a384a6 613 dhcpc_dbg("DHCP client ERROR: failure binding socket on renew, aborting DHCP! (%s)\n", strerror(pico_err));
tass 51:ab4529a384a6 614 pico_socket_close(dhcpc->s);
tass 51:ab4529a384a6 615 dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
tass 51:ab4529a384a6 616 return -1;
daniele 29:1a47b7151851 617 }
daniele 29:1a47b7151851 618
tass 51:ab4529a384a6 619 dhcpc->retry = 0;
tass 51:ab4529a384a6 620 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
tass 51:ab4529a384a6 621 pico_dhcp_client_start_renewing_timer(dhcpc);
tass 51:ab4529a384a6 622
tass 51:ab4529a384a6 623 return 0;
tass 51:ab4529a384a6 624 }
tass 51:ab4529a384a6 625
tass 51:ab4529a384a6 626 static int rebind(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
tass 51:ab4529a384a6 627 {
tass 51:ab4529a384a6 628 struct pico_ip4 bcast = { .addr = 0xFFFFFFFF }, netmask = {0}, inaddr_any = {0};
tass 51:ab4529a384a6 629
tass 51:ab4529a384a6 630 dhcpc->state = DHCP_CLIENT_STATE_REBINDING;
tass 51:ab4529a384a6 631 dhcpc->retry = 0;
tass 51:ab4529a384a6 632 /* we need a default route for our global broadcast messages, otherwise they get dropped. */
tass 51:ab4529a384a6 633 pico_ipv4_route_add(bcast, netmask, inaddr_any, 1, pico_ipv4_link_get(&dhcpc->address));
tass 51:ab4529a384a6 634 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
tass 51:ab4529a384a6 635 pico_dhcp_client_start_rebinding_timer(dhcpc);
tass 51:ab4529a384a6 636
tass 51:ab4529a384a6 637 return 0;
tass 51:ab4529a384a6 638 }
tass 51:ab4529a384a6 639
tass 51:ab4529a384a6 640 static int reset(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
tass 51:ab4529a384a6 641 {
tass 51:ab4529a384a6 642 struct pico_ip4 address = {0}, netmask = {0}, inaddr_any = {0}, bcast = { .addr = 0xFFFFFFFF };
tass 51:ab4529a384a6 643
tass 51:ab4529a384a6 644 if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING)
tass 51:ab4529a384a6 645 address.addr = PICO_IP4_ANY;
tass 51:ab4529a384a6 646 else
tass 51:ab4529a384a6 647 address.addr = dhcpc->address.addr;
tass 51:ab4529a384a6 648
tass 51:ab4529a384a6 649 /* delete the default route for our global broadcast messages, otherwise another interface can not rebind */
tass 51:ab4529a384a6 650 if (dhcpc->state == DHCP_CLIENT_STATE_REBINDING)
tass 51:ab4529a384a6 651 pico_ipv4_route_del(bcast, netmask, inaddr_any, 1, pico_ipv4_link_get(&dhcpc->address));
tass 51:ab4529a384a6 652
tass 51:ab4529a384a6 653 /* close the socket used for address (re)acquisition */
tass 51:ab4529a384a6 654 pico_socket_close(dhcpc->s);
tass 51:ab4529a384a6 655 /* delete the link with the currently in use address */
tass 51:ab4529a384a6 656 pico_ipv4_link_del(dhcpc->dev, address);
tass 51:ab4529a384a6 657
tass 51:ab4529a384a6 658 dhcpc->cb(dhcpc, PICO_DHCP_RESET);
tass 51:ab4529a384a6 659 dhcpc->state = DHCP_CLIENT_STATE_INIT;
tass 51:ab4529a384a6 660 dhcpc->status = DHCP_CLIENT_STATUS_INIT;
tass 51:ab4529a384a6 661 pico_dhcp_client_stop_timers(dhcpc);
tass 51:ab4529a384a6 662 pico_dhcp_client_init(dhcpc);
tass 51:ab4529a384a6 663 return 0;
tass 51:ab4529a384a6 664 }
tass 51:ab4529a384a6 665
tass 51:ab4529a384a6 666 static int retransmit(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
tass 51:ab4529a384a6 667 {
tass 51:ab4529a384a6 668 switch (dhcpc->state)
tass 51:ab4529a384a6 669 {
tass 51:ab4529a384a6 670 case DHCP_CLIENT_STATE_INIT:
tass 51:ab4529a384a6 671 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER);
tass 51:ab4529a384a6 672 pico_dhcp_client_start_init_timer(dhcpc);
tass 51:ab4529a384a6 673 break;
tass 51:ab4529a384a6 674
tass 51:ab4529a384a6 675 case DHCP_CLIENT_STATE_REQUESTING:
tass 51:ab4529a384a6 676 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
tass 51:ab4529a384a6 677 pico_dhcp_client_start_requesting_timer(dhcpc);
tass 51:ab4529a384a6 678 break;
tass 51:ab4529a384a6 679
tass 51:ab4529a384a6 680 case DHCP_CLIENT_STATE_RENEWING:
tass 51:ab4529a384a6 681 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
tass 51:ab4529a384a6 682 pico_dhcp_client_start_renewing_timer(dhcpc);
tass 51:ab4529a384a6 683 break;
tass 51:ab4529a384a6 684
tass 51:ab4529a384a6 685 case DHCP_CLIENT_STATE_REBINDING:
tass 51:ab4529a384a6 686 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER);
tass 51:ab4529a384a6 687 pico_dhcp_client_start_rebinding_timer(dhcpc);
tass 51:ab4529a384a6 688 break;
tass 51:ab4529a384a6 689
tass 51:ab4529a384a6 690 default:
tass 51:ab4529a384a6 691 dhcpc_dbg("DHCP client WARNING: retransmit in incorrect state (%u)!\n", dhcpc->state);
tass 51:ab4529a384a6 692 return -1;
tass 51:ab4529a384a6 693 }
tass 51:ab4529a384a6 694 return 0;
tass 51:ab4529a384a6 695 }
tass 51:ab4529a384a6 696
tass 51:ab4529a384a6 697 struct dhcp_action_entry {
tass 51:ab4529a384a6 698 int (*offer)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 51:ab4529a384a6 699 int (*ack)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 51:ab4529a384a6 700 int (*nak)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 51:ab4529a384a6 701 int (*timer1)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 51:ab4529a384a6 702 int (*timer2)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 51:ab4529a384a6 703 int (*timer_lease)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 51:ab4529a384a6 704 int (*timer_retransmit)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 51:ab4529a384a6 705 };
tass 51:ab4529a384a6 706
tass 51:ab4529a384a6 707 static struct dhcp_action_entry dhcp_fsm[] =
tass 51:ab4529a384a6 708 { /* event |offer |ack |nak |T1 |T2 |lease |retransmit */
tass 51:ab4529a384a6 709 /* state init-reboot */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL },
tass 51:ab4529a384a6 710 /* state rebooting */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL },
tass 51:ab4529a384a6 711 /* state init */ { recv_offer, NULL, NULL, NULL, NULL, NULL, retransmit },
tass 51:ab4529a384a6 712 /* state selecting */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL },
tass 51:ab4529a384a6 713 /* state requesting */ { NULL, recv_ack, reset, NULL, NULL, NULL, retransmit },
tass 51:ab4529a384a6 714 /* state bound */ { NULL, NULL, NULL, renew, NULL, NULL, NULL },
tass 51:ab4529a384a6 715 /* state renewing */ { NULL, recv_ack, reset, NULL, rebind, NULL, retransmit },
tass 51:ab4529a384a6 716 /* state rebinding */ { NULL, recv_ack, reset, NULL, NULL, reset, retransmit },
tass 51:ab4529a384a6 717 };
tass 51:ab4529a384a6 718
tass 51:ab4529a384a6 719 /* TIMERS REMARK:
tass 51:ab4529a384a6 720 * In state bound we have T1, T2 and the lease timer running. If T1 goes off, we attempt to renew.
tass 51:ab4529a384a6 721 * If the renew succeeds a new T1, T2 and lease timer is started. The former T2 and lease timer is
tass 51:ab4529a384a6 722 * still running though. This poses no concerns as the T2 and lease event in state bound have a NULL
tass 51:ab4529a384a6 723 * pointer in the fsm. If the former T2 or lease timer goes off, nothing happens. Same situation
tass 51:ab4529a384a6 724 * applies for T2 and a succesfull rebind. */
tass 51:ab4529a384a6 725
tass 51:ab4529a384a6 726 static void pico_dhcp_state_machine(uint8_t event, struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
tass 51:ab4529a384a6 727 {
tass 51:ab4529a384a6 728 switch (event)
tass 51:ab4529a384a6 729 {
tass 51:ab4529a384a6 730 case PICO_DHCP_MSG_OFFER:
tass 51:ab4529a384a6 731 dhcpc_dbg("DHCP client: received OFFER\n");
tass 51:ab4529a384a6 732 if (dhcp_fsm[dhcpc->state].offer)
tass 51:ab4529a384a6 733 dhcp_fsm[dhcpc->state].offer(dhcpc, buf);
tass 51:ab4529a384a6 734 break;
tass 51:ab4529a384a6 735
tass 51:ab4529a384a6 736 case PICO_DHCP_MSG_ACK:
tass 51:ab4529a384a6 737 dhcpc_dbg("DHCP client: received ACK\n");
tass 51:ab4529a384a6 738 if (dhcp_fsm[dhcpc->state].ack)
tass 51:ab4529a384a6 739 dhcp_fsm[dhcpc->state].ack(dhcpc, buf);
tass 51:ab4529a384a6 740 break;
tass 51:ab4529a384a6 741
tass 51:ab4529a384a6 742 case PICO_DHCP_MSG_NAK:
tass 51:ab4529a384a6 743 dhcpc_dbg("DHCP client: received NAK\n");
tass 51:ab4529a384a6 744 if (dhcp_fsm[dhcpc->state].nak)
tass 51:ab4529a384a6 745 dhcp_fsm[dhcpc->state].nak(dhcpc, buf);
tass 51:ab4529a384a6 746 break;
tass 51:ab4529a384a6 747
tass 51:ab4529a384a6 748 case PICO_DHCP_EVENT_T1:
tass 51:ab4529a384a6 749 dhcpc_dbg("DHCP client: received T1 timeout\n");
tass 51:ab4529a384a6 750 if (dhcp_fsm[dhcpc->state].timer1)
tass 51:ab4529a384a6 751 dhcp_fsm[dhcpc->state].timer1(dhcpc, NULL);
tass 51:ab4529a384a6 752 break;
tass 51:ab4529a384a6 753
tass 51:ab4529a384a6 754 case PICO_DHCP_EVENT_T2:
tass 51:ab4529a384a6 755 dhcpc_dbg("DHCP client: received T2 timeout\n");
tass 51:ab4529a384a6 756 if (dhcp_fsm[dhcpc->state].timer2)
tass 51:ab4529a384a6 757 dhcp_fsm[dhcpc->state].timer2(dhcpc, NULL);
tass 51:ab4529a384a6 758 break;
tass 51:ab4529a384a6 759
tass 51:ab4529a384a6 760 case PICO_DHCP_EVENT_LEASE:
tass 51:ab4529a384a6 761 dhcpc_dbg("DHCP client: received LEASE timeout\n");
tass 51:ab4529a384a6 762 if (dhcp_fsm[dhcpc->state].timer_lease)
tass 51:ab4529a384a6 763 dhcp_fsm[dhcpc->state].timer_lease(dhcpc, NULL);
tass 51:ab4529a384a6 764 break;
tass 51:ab4529a384a6 765
tass 51:ab4529a384a6 766 case PICO_DHCP_EVENT_RETRANSMIT:
tass 51:ab4529a384a6 767 dhcpc_dbg("DHCP client: received RETRANSMIT timeout\n");
tass 51:ab4529a384a6 768 if (dhcp_fsm[dhcpc->state].timer_retransmit)
tass 51:ab4529a384a6 769 dhcp_fsm[dhcpc->state].timer_retransmit(dhcpc, NULL);
tass 51:ab4529a384a6 770 break;
tass 51:ab4529a384a6 771
tass 51:ab4529a384a6 772 default:
tass 51:ab4529a384a6 773 dhcpc_dbg("DHCP client WARNING: unrecognized event (%u)!\n", dhcpc->event);
tass 51:ab4529a384a6 774 return;
tass 51:ab4529a384a6 775 }
tass 51:ab4529a384a6 776 return;
tass 51:ab4529a384a6 777 }
tass 51:ab4529a384a6 778
tass 51:ab4529a384a6 779 static int pico_dhcp_client_opt_parse(void *ptr, int len)
tass 51:ab4529a384a6 780 {
tass 51:ab4529a384a6 781 int optlen = len - sizeof(struct pico_dhcp_hdr);
tass 51:ab4529a384a6 782 struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)ptr;
tass 51:ab4529a384a6 783 struct pico_dhcp_opt *opt = NULL;
tass 51:ab4529a384a6 784
tass 51:ab4529a384a6 785 if (hdr->dhcp_magic != PICO_DHCPD_MAGIC_COOKIE)
tass 51:ab4529a384a6 786 return -1;
tass 51:ab4529a384a6 787 if (!pico_dhcp_are_options_valid(hdr->options, optlen))
tass 51:ab4529a384a6 788 return -1;
tass 51:ab4529a384a6 789
tass 51:ab4529a384a6 790 opt = (struct pico_dhcp_opt *)hdr->options;
tass 51:ab4529a384a6 791 do {
tass 51:ab4529a384a6 792 if (opt->code == PICO_DHCP_OPT_MSGTYPE)
tass 51:ab4529a384a6 793 return opt->ext.msg_type.type;
tass 51:ab4529a384a6 794 } while (pico_dhcp_next_option(&opt));
tass 51:ab4529a384a6 795
tass 51:ab4529a384a6 796 return -1;
tass 51:ab4529a384a6 797 }
tass 51:ab4529a384a6 798
tass 51:ab4529a384a6 799 static int pico_dhcp_client_msg(struct pico_dhcp_client_cookie *dhcpc, uint8_t msg_type)
tass 51:ab4529a384a6 800 {
tass 51:ab4529a384a6 801 int r = 0, optlen = 0, offset = 0;
tass 51:ab4529a384a6 802 struct pico_ip4 destination = { .addr = 0xFFFFFFFF};
tass 51:ab4529a384a6 803 struct pico_dhcp_hdr *hdr = NULL;
tass 51:ab4529a384a6 804
tass 51:ab4529a384a6 805 switch (msg_type)
tass 51:ab4529a384a6 806 {
tass 51:ab4529a384a6 807 case PICO_DHCP_MSG_DISCOVER:
tass 51:ab4529a384a6 808 dhcpc_dbg("DHCP client: sent DHCPDISCOVER\n");
tass 51:ab4529a384a6 809 optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_MAXMSGSIZE + PICO_DHCP_OPTLEN_PARAMLIST + PICO_DHCP_OPTLEN_END;
tass 51:ab4529a384a6 810 hdr = pico_zalloc(sizeof(struct pico_dhcp_hdr) + optlen);
tass 51:ab4529a384a6 811 /* specific options */
tass 51:ab4529a384a6 812 offset += pico_dhcp_opt_maxmsgsize(&hdr->options[offset], DHCP_CLIENT_MAXMSGZISE);
tass 51:ab4529a384a6 813 break;
tass 51:ab4529a384a6 814
tass 51:ab4529a384a6 815 case PICO_DHCP_MSG_REQUEST:
tass 51:ab4529a384a6 816 dhcpc_dbg("DHCP client: sent DHCPREQUEST\n");
tass 51:ab4529a384a6 817 optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_MAXMSGSIZE + PICO_DHCP_OPTLEN_PARAMLIST + PICO_DHCP_OPTLEN_REQIP + PICO_DHCP_OPTLEN_SERVERID
tass 51:ab4529a384a6 818 + PICO_DHCP_OPTLEN_END;
tass 51:ab4529a384a6 819 hdr = pico_zalloc(sizeof(struct pico_dhcp_hdr) + optlen);
tass 51:ab4529a384a6 820 /* specific options */
tass 51:ab4529a384a6 821 offset += pico_dhcp_opt_maxmsgsize(&hdr->options[offset], DHCP_CLIENT_MAXMSGZISE);
tass 51:ab4529a384a6 822 if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING) {
tass 51:ab4529a384a6 823 offset += pico_dhcp_opt_reqip(&hdr->options[offset], &dhcpc->address);
tass 51:ab4529a384a6 824 offset += pico_dhcp_opt_serverid(&hdr->options[offset], &dhcpc->server_id);
tass 51:ab4529a384a6 825 }
tass 51:ab4529a384a6 826 break;
tass 51:ab4529a384a6 827
tass 51:ab4529a384a6 828 default:
tass 51:ab4529a384a6 829 return -1;
tass 51:ab4529a384a6 830 }
tass 51:ab4529a384a6 831
tass 51:ab4529a384a6 832 /* common options */
tass 51:ab4529a384a6 833 offset += pico_dhcp_opt_msgtype(&hdr->options[offset], msg_type);
tass 51:ab4529a384a6 834 offset += pico_dhcp_opt_paramlist(&hdr->options[offset]);
tass 51:ab4529a384a6 835 offset += pico_dhcp_opt_end(&hdr->options[offset]);
tass 51:ab4529a384a6 836
tass 51:ab4529a384a6 837 switch (dhcpc->state)
tass 51:ab4529a384a6 838 {
tass 51:ab4529a384a6 839 case DHCP_CLIENT_STATE_BOUND:
tass 51:ab4529a384a6 840 destination.addr = dhcpc->server_id.addr;
tass 51:ab4529a384a6 841 hdr->ciaddr = dhcpc->address.addr;
tass 51:ab4529a384a6 842 break;
tass 51:ab4529a384a6 843
tass 51:ab4529a384a6 844 case DHCP_CLIENT_STATE_RENEWING:
tass 51:ab4529a384a6 845 destination.addr = dhcpc->server_id.addr;
tass 51:ab4529a384a6 846 hdr->ciaddr = dhcpc->address.addr;
tass 51:ab4529a384a6 847 break;
tass 51:ab4529a384a6 848
tass 51:ab4529a384a6 849 case DHCP_CLIENT_STATE_REBINDING:
tass 51:ab4529a384a6 850 hdr->ciaddr = dhcpc->address.addr;
tass 51:ab4529a384a6 851 break;
tass 51:ab4529a384a6 852
tass 51:ab4529a384a6 853 default:
tass 51:ab4529a384a6 854 /* do nothing */
tass 51:ab4529a384a6 855 break;
tass 51:ab4529a384a6 856 }
tass 51:ab4529a384a6 857
tass 51:ab4529a384a6 858 /* header information */
tass 51:ab4529a384a6 859 hdr->op = PICO_DHCP_OP_REQUEST;
tass 51:ab4529a384a6 860 hdr->htype = PICO_DHCP_HTYPE_ETH;
tass 51:ab4529a384a6 861 hdr->hlen = PICO_SIZE_ETH;
tass 51:ab4529a384a6 862 hdr->xid = dhcpc->xid;
tass 51:ab4529a384a6 863 hdr->flags = short_be(PICO_DHCP_FLAG_BROADCAST);
tass 51:ab4529a384a6 864 hdr->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE;
tass 51:ab4529a384a6 865 /* copy client hardware address */
tass 51:ab4529a384a6 866 memcpy(hdr->hwaddr, &dhcpc->dev->eth->mac, PICO_SIZE_ETH);
tass 51:ab4529a384a6 867
tass 51:ab4529a384a6 868 r = pico_socket_sendto(dhcpc->s, hdr, sizeof(struct pico_dhcp_hdr) + optlen, &destination, PICO_DHCPD_PORT);
tass 51:ab4529a384a6 869 pico_free(hdr);
tass 51:ab4529a384a6 870 if (r < 0)
daniele 29:1a47b7151851 871 return -1;
daniele 29:1a47b7151851 872
daniele 29:1a47b7151851 873 return 0;
daniele 29:1a47b7151851 874 }
daniele 29:1a47b7151851 875
tass 51:ab4529a384a6 876 static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s)
daniele 29:1a47b7151851 877 {
tass 51:ab4529a384a6 878 uint8_t buf[DHCP_CLIENT_MAXMSGZISE] = {0};
tass 51:ab4529a384a6 879 int r = 0;
tass 51:ab4529a384a6 880 struct pico_dhcp_hdr *hdr = NULL;
tass 51:ab4529a384a6 881 struct pico_dhcp_client_cookie *dhcpc = NULL;
daniele 29:1a47b7151851 882
tass 51:ab4529a384a6 883 if (ev != PICO_SOCK_EV_RD)
tass 51:ab4529a384a6 884 return;
tass 51:ab4529a384a6 885 r = pico_socket_recvfrom(s, buf, DHCP_CLIENT_MAXMSGZISE, NULL, NULL);
tass 51:ab4529a384a6 886 if (r < 0)
tass 51:ab4529a384a6 887 return;
daniele 29:1a47b7151851 888
tass 51:ab4529a384a6 889 /* If the 'xid' of an arriving message does not match the 'xid'
tass 51:ab4529a384a6 890 * of the most recent transmitted message, the message must be
tass 51:ab4529a384a6 891 * silently discarded. */
tass 51:ab4529a384a6 892 hdr = (struct pico_dhcp_hdr *)buf;
tass 51:ab4529a384a6 893 dhcpc = pico_dhcp_client_find_cookie(hdr->xid);
tass 51:ab4529a384a6 894 if (!dhcpc)
tass 51:ab4529a384a6 895 return;
tass 51:ab4529a384a6 896 dhcpc->event = pico_dhcp_client_opt_parse(buf, r);
tass 51:ab4529a384a6 897 pico_dhcp_state_machine(dhcpc->event, dhcpc, buf);
daniele 29:1a47b7151851 898 }
daniele 29:1a47b7151851 899
daniele 29:1a47b7151851 900 void *pico_dhcp_get_identifier(uint32_t xid)
daniele 29:1a47b7151851 901 {
tass 51:ab4529a384a6 902 return (void *)pico_dhcp_client_find_cookie(xid);
tass 51:ab4529a384a6 903 }
tass 51:ab4529a384a6 904
tass 51:ab4529a384a6 905 struct pico_ip4 pico_dhcp_get_address(void* dhcpc)
tass 51:ab4529a384a6 906 {
tass 51:ab4529a384a6 907 return ((struct pico_dhcp_client_cookie*)dhcpc)->address;
daniele 29:1a47b7151851 908 }
daniele 29:1a47b7151851 909
tass 51:ab4529a384a6 910 struct pico_ip4 pico_dhcp_get_gateway(void* dhcpc)
daniele 29:1a47b7151851 911 {
tass 51:ab4529a384a6 912 return ((struct pico_dhcp_client_cookie*)dhcpc)->gateway;
daniele 29:1a47b7151851 913 }
daniele 29:1a47b7151851 914
tass 51:ab4529a384a6 915 struct pico_ip4 pico_dhcp_get_nameserver(void* dhcpc)
tass 51:ab4529a384a6 916 {
tass 51:ab4529a384a6 917 return ((struct pico_dhcp_client_cookie*)dhcpc)->nameserver;
tass 51:ab4529a384a6 918 }
daniele 29:1a47b7151851 919 #endif