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:
Thu Sep 19 13:26:14 2013 +0000
Revision:
68:0847e35d08a6
Child:
69:43873e366ae1
Imported from masterbranch, again

Who changed what in which revision?

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