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 Dec 05 08:31:32 2013 +0000
Revision:
128:ae39e6e81531
Parent:
127:476fed453d4d
Child:
131:4758606c9316
updated repo to work with uint64 tick.

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 128:ae39e6e81531 70 pico_time 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 70:cd218dd180e5 89 static int8_t 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 128:ae39e6e81531 159 static void pico_dhcp_client_init_timer(pico_time __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 128:ae39e6e81531 181 static void pico_dhcp_client_requesting_timer(pico_time __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 128:ae39e6e81531 201 static void pico_dhcp_client_renewing_timer(pico_time __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 128:ae39e6e81531 216 static void pico_dhcp_client_rebinding_timer(pico_time __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 128:ae39e6e81531 231 static void pico_dhcp_client_T1_timer(pico_time __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 128:ae39e6e81531 245 static void pico_dhcp_client_T2_timer(pico_time __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 128:ae39e6e81531 260 static void pico_dhcp_client_lease_timer(pico_time __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 128:ae39e6e81531 275 static void pico_dhcp_client_reinit(pico_time __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 72:887bc44746ff 568 struct pico_ip4 address = {0}, netmask = {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 71:f15dc127f5f9 574 /* Issue #20 the server can transmit on ACK a different IP than the one in OFFER */
tass 71:f15dc127f5f9 575 /* RFC2131 ch 4.3.2 ... The client SHOULD use the parameters in the DHCPACK message for configuration */
tass 71:f15dc127f5f9 576 if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING)
tass 71:f15dc127f5f9 577 dhcpc->address.addr = hdr->yiaddr;
tass 73:dfb737147f6e 578
tass 73:dfb737147f6e 579
tass 68:0847e35d08a6 580 /* close the socket used for address (re)acquisition */
tass 68:0847e35d08a6 581 pico_socket_close(dhcpc->s);
tass 68:0847e35d08a6 582 /* delete the link with address 0.0.0.0, add new link with acquired address */
tass 68:0847e35d08a6 583 if (dhcpc->status == DHCP_CLIENT_STATUS_TRANSMITTED) {
tass 68:0847e35d08a6 584 pico_ipv4_link_del(dhcpc->dev, address);
tass 68:0847e35d08a6 585 pico_ipv4_link_add(dhcpc->dev, dhcpc->address, dhcpc->netmask);
tass 68:0847e35d08a6 586 dhcpc->status = DHCP_CLIENT_STATUS_INITIALIZED;
tass 68:0847e35d08a6 587 }
tass 68:0847e35d08a6 588 /* delete the default route for our global broadcast messages, otherwise another interface can not rebind */
tass 68:0847e35d08a6 589 if (dhcpc->state == DHCP_CLIENT_STATE_REBINDING)
tass 72:887bc44746ff 590 pico_ipv4_route_del(bcast, netmask, 1);
tass 68:0847e35d08a6 591
tass 68:0847e35d08a6 592 dbg("DHCP client: renewal time (T1) %u\n", dhcpc->T1_timer.time);
tass 68:0847e35d08a6 593 dbg("DHCP client: rebinding time (T2) %u\n", dhcpc->T2_timer.time);
tass 68:0847e35d08a6 594 dbg("DHCP client: lease time %u\n", dhcpc->lease_timer.time);
tass 68:0847e35d08a6 595
tass 68:0847e35d08a6 596 dhcpc->retry = 0;
tass 68:0847e35d08a6 597 dhcpc->renewing_timer.time = dhcpc->T2_timer.time - dhcpc->T1_timer.time;
tass 68:0847e35d08a6 598 dhcpc->rebinding_timer.time = dhcpc->lease_timer.time - dhcpc->T2_timer.time;
tass 68:0847e35d08a6 599 pico_dhcp_client_start_reacquisition_timers(dhcpc);
tass 68:0847e35d08a6 600
tass 68:0847e35d08a6 601 pico_dhcp_client_mutex++;
tass 68:0847e35d08a6 602 *(dhcpc->uid) = dhcpc->xid;
tass 68:0847e35d08a6 603 dhcpc->cb(dhcpc, PICO_DHCP_SUCCESS);
tass 68:0847e35d08a6 604 dhcpc->state = DHCP_CLIENT_STATE_BOUND;
tass 68:0847e35d08a6 605 return 0;
tass 68:0847e35d08a6 606 }
tass 68:0847e35d08a6 607
tass 68:0847e35d08a6 608 static int renew(struct pico_dhcp_client_cookie *dhcpc, uint8_t __attribute__((unused)) *buf)
tass 68:0847e35d08a6 609 {
tass 68:0847e35d08a6 610 uint16_t port = PICO_DHCP_CLIENT_PORT;
tass 68:0847e35d08a6 611
tass 68:0847e35d08a6 612 dhcpc->state = DHCP_CLIENT_STATE_RENEWING;
tass 68:0847e35d08a6 613 dhcpc->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_client_wakeup);
tass 68:0847e35d08a6 614 if (!dhcpc->s) {
tass 68:0847e35d08a6 615 dhcpc_dbg("DHCP client ERROR: failure opening socket on renew, aborting DHCP! (%s)\n", strerror(pico_err));
tass 68:0847e35d08a6 616 dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
tass 68:0847e35d08a6 617 return -1;
tass 68:0847e35d08a6 618 }
tass 68:0847e35d08a6 619 if (pico_socket_bind(dhcpc->s, &dhcpc->address, &port) != 0) {
tass 68:0847e35d08a6 620 dhcpc_dbg("DHCP client ERROR: failure binding socket on renew, aborting DHCP! (%s)\n", strerror(pico_err));
tass 68:0847e35d08a6 621 pico_socket_close(dhcpc->s);
tass 68:0847e35d08a6 622 dhcpc->cb(dhcpc, PICO_DHCP_ERROR);
tass 68:0847e35d08a6 623 return -1;
tass 68:0847e35d08a6 624 }
tass 68:0847e35d08a6 625
tass 68:0847e35d08a6 626 dhcpc->retry = 0;
tass 68:0847e35d08a6 627 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
tass 68:0847e35d08a6 628 pico_dhcp_client_start_renewing_timer(dhcpc);
tass 68:0847e35d08a6 629
tass 68:0847e35d08a6 630 return 0;
tass 68:0847e35d08a6 631 }
tass 68:0847e35d08a6 632
tass 68:0847e35d08a6 633 static int rebind(struct pico_dhcp_client_cookie *dhcpc, uint8_t __attribute__((unused)) *buf)
tass 68:0847e35d08a6 634 {
tass 68:0847e35d08a6 635 struct pico_ip4 bcast = { .addr = 0xFFFFFFFF }, netmask = {0}, inaddr_any = {0};
tass 68:0847e35d08a6 636
tass 68:0847e35d08a6 637 dhcpc->state = DHCP_CLIENT_STATE_REBINDING;
tass 68:0847e35d08a6 638 dhcpc->retry = 0;
tass 68:0847e35d08a6 639 /* we need a default route for our global broadcast messages, otherwise they get dropped. */
tass 68:0847e35d08a6 640 pico_ipv4_route_add(bcast, netmask, inaddr_any, 1, pico_ipv4_link_get(&dhcpc->address));
tass 68:0847e35d08a6 641 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
tass 68:0847e35d08a6 642 pico_dhcp_client_start_rebinding_timer(dhcpc);
tass 68:0847e35d08a6 643
tass 68:0847e35d08a6 644 return 0;
tass 68:0847e35d08a6 645 }
tass 68:0847e35d08a6 646
tass 68:0847e35d08a6 647 static int reset(struct pico_dhcp_client_cookie *dhcpc, uint8_t __attribute__((unused)) *buf)
tass 68:0847e35d08a6 648 {
tass 72:887bc44746ff 649 struct pico_ip4 address = {0};
tass 68:0847e35d08a6 650
tass 68:0847e35d08a6 651 if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING)
tass 68:0847e35d08a6 652 address.addr = PICO_IP4_ANY;
tass 68:0847e35d08a6 653 else
tass 68:0847e35d08a6 654 address.addr = dhcpc->address.addr;
tass 68:0847e35d08a6 655
tass 68:0847e35d08a6 656 /* close the socket used for address (re)acquisition */
tass 68:0847e35d08a6 657 pico_socket_close(dhcpc->s);
tass 68:0847e35d08a6 658 /* delete the link with the currently in use address */
tass 68:0847e35d08a6 659 pico_ipv4_link_del(dhcpc->dev, address);
tass 68:0847e35d08a6 660
tass 68:0847e35d08a6 661 dhcpc->cb(dhcpc, PICO_DHCP_RESET);
tass 104:cb77d02209ff 662 if (dhcpc->state < DHCP_CLIENT_STATE_BOUND)
tass 104:cb77d02209ff 663 {
tass 104:cb77d02209ff 664 pico_dhcp_client_mutex++;
tass 104:cb77d02209ff 665 }
tass 68:0847e35d08a6 666 dhcpc->state = DHCP_CLIENT_STATE_INIT;
tass 68:0847e35d08a6 667 dhcpc->status = DHCP_CLIENT_STATUS_INIT;
tass 68:0847e35d08a6 668 pico_dhcp_client_stop_timers(dhcpc);
tass 68:0847e35d08a6 669 pico_dhcp_client_init(dhcpc);
tass 68:0847e35d08a6 670 return 0;
tass 68:0847e35d08a6 671 }
tass 68:0847e35d08a6 672
tass 68:0847e35d08a6 673 static int retransmit(struct pico_dhcp_client_cookie *dhcpc, uint8_t __attribute__((unused)) *buf)
tass 68:0847e35d08a6 674 {
tass 68:0847e35d08a6 675 switch (dhcpc->state)
tass 68:0847e35d08a6 676 {
tass 68:0847e35d08a6 677 case DHCP_CLIENT_STATE_INIT:
tass 68:0847e35d08a6 678 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER);
tass 68:0847e35d08a6 679 pico_dhcp_client_start_init_timer(dhcpc);
tass 68:0847e35d08a6 680 break;
tass 68:0847e35d08a6 681
tass 68:0847e35d08a6 682 case DHCP_CLIENT_STATE_REQUESTING:
tass 68:0847e35d08a6 683 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
tass 68:0847e35d08a6 684 pico_dhcp_client_start_requesting_timer(dhcpc);
tass 68:0847e35d08a6 685 break;
tass 68:0847e35d08a6 686
tass 68:0847e35d08a6 687 case DHCP_CLIENT_STATE_RENEWING:
tass 68:0847e35d08a6 688 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_REQUEST);
tass 68:0847e35d08a6 689 pico_dhcp_client_start_renewing_timer(dhcpc);
tass 68:0847e35d08a6 690 break;
tass 68:0847e35d08a6 691
tass 68:0847e35d08a6 692 case DHCP_CLIENT_STATE_REBINDING:
tass 68:0847e35d08a6 693 pico_dhcp_client_msg(dhcpc, PICO_DHCP_MSG_DISCOVER);
tass 68:0847e35d08a6 694 pico_dhcp_client_start_rebinding_timer(dhcpc);
tass 68:0847e35d08a6 695 break;
tass 68:0847e35d08a6 696
tass 68:0847e35d08a6 697 default:
tass 68:0847e35d08a6 698 dhcpc_dbg("DHCP client WARNING: retransmit in incorrect state (%u)!\n", dhcpc->state);
tass 68:0847e35d08a6 699 return -1;
tass 68:0847e35d08a6 700 }
tass 68:0847e35d08a6 701 return 0;
tass 68:0847e35d08a6 702 }
tass 68:0847e35d08a6 703
tass 68:0847e35d08a6 704 struct dhcp_action_entry {
tass 68:0847e35d08a6 705 int (*offer)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 68:0847e35d08a6 706 int (*ack)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 68:0847e35d08a6 707 int (*nak)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 68:0847e35d08a6 708 int (*timer1)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 68:0847e35d08a6 709 int (*timer2)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 68:0847e35d08a6 710 int (*timer_lease)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 68:0847e35d08a6 711 int (*timer_retransmit)(struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf);
tass 68:0847e35d08a6 712 };
tass 68:0847e35d08a6 713
tass 68:0847e35d08a6 714 static struct dhcp_action_entry dhcp_fsm[] =
tass 68:0847e35d08a6 715 { /* event |offer |ack |nak |T1 |T2 |lease |retransmit */
tass 68:0847e35d08a6 716 /* state init-reboot */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL },
tass 68:0847e35d08a6 717 /* state rebooting */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL },
tass 68:0847e35d08a6 718 /* state init */ { recv_offer, NULL, NULL, NULL, NULL, NULL, retransmit },
tass 68:0847e35d08a6 719 /* state selecting */ { NULL, NULL, NULL, NULL, NULL, NULL, NULL },
tass 68:0847e35d08a6 720 /* state requesting */ { NULL, recv_ack, reset, NULL, NULL, NULL, retransmit },
tass 68:0847e35d08a6 721 /* state bound */ { NULL, NULL, NULL, renew, NULL, NULL, NULL },
tass 68:0847e35d08a6 722 /* state renewing */ { NULL, recv_ack, reset, NULL, rebind, NULL, retransmit },
tass 68:0847e35d08a6 723 /* state rebinding */ { NULL, recv_ack, reset, NULL, NULL, reset, retransmit },
tass 68:0847e35d08a6 724 };
tass 68:0847e35d08a6 725
tass 68:0847e35d08a6 726 /* TIMERS REMARK:
tass 68:0847e35d08a6 727 * In state bound we have T1, T2 and the lease timer running. If T1 goes off, we attempt to renew.
tass 68:0847e35d08a6 728 * If the renew succeeds a new T1, T2 and lease timer is started. The former T2 and lease timer is
tass 68:0847e35d08a6 729 * still running though. This poses no concerns as the T2 and lease event in state bound have a NULL
tass 68:0847e35d08a6 730 * pointer in the fsm. If the former T2 or lease timer goes off, nothing happens. Same situation
tass 68:0847e35d08a6 731 * applies for T2 and a succesfull rebind. */
tass 68:0847e35d08a6 732
tass 68:0847e35d08a6 733 static void pico_dhcp_state_machine(uint8_t event, struct pico_dhcp_client_cookie *dhcpc, uint8_t *buf)
tass 68:0847e35d08a6 734 {
tass 68:0847e35d08a6 735 switch (event)
tass 68:0847e35d08a6 736 {
tass 68:0847e35d08a6 737 case PICO_DHCP_MSG_OFFER:
tass 68:0847e35d08a6 738 dhcpc_dbg("DHCP client: received OFFER\n");
tass 68:0847e35d08a6 739 if (dhcp_fsm[dhcpc->state].offer)
tass 68:0847e35d08a6 740 dhcp_fsm[dhcpc->state].offer(dhcpc, buf);
tass 68:0847e35d08a6 741 break;
tass 68:0847e35d08a6 742
tass 68:0847e35d08a6 743 case PICO_DHCP_MSG_ACK:
tass 68:0847e35d08a6 744 dhcpc_dbg("DHCP client: received ACK\n");
tass 68:0847e35d08a6 745 if (dhcp_fsm[dhcpc->state].ack)
tass 68:0847e35d08a6 746 dhcp_fsm[dhcpc->state].ack(dhcpc, buf);
tass 68:0847e35d08a6 747 break;
tass 68:0847e35d08a6 748
tass 68:0847e35d08a6 749 case PICO_DHCP_MSG_NAK:
tass 68:0847e35d08a6 750 dhcpc_dbg("DHCP client: received NAK\n");
tass 68:0847e35d08a6 751 if (dhcp_fsm[dhcpc->state].nak)
tass 68:0847e35d08a6 752 dhcp_fsm[dhcpc->state].nak(dhcpc, buf);
tass 68:0847e35d08a6 753 break;
tass 68:0847e35d08a6 754
tass 68:0847e35d08a6 755 case PICO_DHCP_EVENT_T1:
tass 68:0847e35d08a6 756 dhcpc_dbg("DHCP client: received T1 timeout\n");
tass 68:0847e35d08a6 757 if (dhcp_fsm[dhcpc->state].timer1)
tass 68:0847e35d08a6 758 dhcp_fsm[dhcpc->state].timer1(dhcpc, NULL);
tass 68:0847e35d08a6 759 break;
tass 68:0847e35d08a6 760
tass 68:0847e35d08a6 761 case PICO_DHCP_EVENT_T2:
tass 68:0847e35d08a6 762 dhcpc_dbg("DHCP client: received T2 timeout\n");
tass 68:0847e35d08a6 763 if (dhcp_fsm[dhcpc->state].timer2)
tass 68:0847e35d08a6 764 dhcp_fsm[dhcpc->state].timer2(dhcpc, NULL);
tass 68:0847e35d08a6 765 break;
tass 68:0847e35d08a6 766
tass 68:0847e35d08a6 767 case PICO_DHCP_EVENT_LEASE:
tass 68:0847e35d08a6 768 dhcpc_dbg("DHCP client: received LEASE timeout\n");
tass 68:0847e35d08a6 769 if (dhcp_fsm[dhcpc->state].timer_lease)
tass 68:0847e35d08a6 770 dhcp_fsm[dhcpc->state].timer_lease(dhcpc, NULL);
tass 68:0847e35d08a6 771 break;
tass 68:0847e35d08a6 772
tass 68:0847e35d08a6 773 case PICO_DHCP_EVENT_RETRANSMIT:
tass 68:0847e35d08a6 774 dhcpc_dbg("DHCP client: received RETRANSMIT timeout\n");
tass 68:0847e35d08a6 775 if (dhcp_fsm[dhcpc->state].timer_retransmit)
tass 68:0847e35d08a6 776 dhcp_fsm[dhcpc->state].timer_retransmit(dhcpc, NULL);
tass 68:0847e35d08a6 777 break;
tass 68:0847e35d08a6 778
tass 68:0847e35d08a6 779 default:
tass 68:0847e35d08a6 780 dhcpc_dbg("DHCP client WARNING: unrecognized event (%u)!\n", dhcpc->event);
tass 68:0847e35d08a6 781 return;
tass 68:0847e35d08a6 782 }
tass 68:0847e35d08a6 783 return;
tass 68:0847e35d08a6 784 }
tass 68:0847e35d08a6 785
tass 70:cd218dd180e5 786 static int16_t pico_dhcp_client_opt_parse(void *ptr, uint16_t len)
tass 68:0847e35d08a6 787 {
tass 74:c146c4e346c4 788 uint32_t optlen = len - (uint32_t)sizeof(struct pico_dhcp_hdr);
tass 68:0847e35d08a6 789 struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)ptr;
tass 68:0847e35d08a6 790 struct pico_dhcp_opt *opt = NULL;
tass 68:0847e35d08a6 791
tass 68:0847e35d08a6 792 if (hdr->dhcp_magic != PICO_DHCPD_MAGIC_COOKIE)
tass 68:0847e35d08a6 793 return -1;
tass 70:cd218dd180e5 794 if (!pico_dhcp_are_options_valid(hdr->options, (int32_t)optlen))
tass 68:0847e35d08a6 795 return -1;
tass 68:0847e35d08a6 796
tass 68:0847e35d08a6 797 opt = (struct pico_dhcp_opt *)hdr->options;
tass 68:0847e35d08a6 798 do {
tass 68:0847e35d08a6 799 if (opt->code == PICO_DHCP_OPT_MSGTYPE)
tass 68:0847e35d08a6 800 return opt->ext.msg_type.type;
tass 68:0847e35d08a6 801 } while (pico_dhcp_next_option(&opt));
tass 68:0847e35d08a6 802
tass 68:0847e35d08a6 803 return -1;
tass 68:0847e35d08a6 804 }
tass 68:0847e35d08a6 805
tass 70:cd218dd180e5 806 static int8_t pico_dhcp_client_msg(struct pico_dhcp_client_cookie *dhcpc, uint8_t msg_type)
tass 68:0847e35d08a6 807 {
tass 70:cd218dd180e5 808 int32_t r = 0;
tass 70:cd218dd180e5 809 uint16_t optlen = 0, offset = 0;
tass 68:0847e35d08a6 810 struct pico_ip4 destination = { .addr = 0xFFFFFFFF};
tass 68:0847e35d08a6 811 struct pico_dhcp_hdr *hdr = NULL;
tass 68:0847e35d08a6 812
tass 68:0847e35d08a6 813 switch (msg_type)
tass 68:0847e35d08a6 814 {
tass 68:0847e35d08a6 815 case PICO_DHCP_MSG_DISCOVER:
tass 68:0847e35d08a6 816 dhcpc_dbg("DHCP client: sent DHCPDISCOVER\n");
tass 68:0847e35d08a6 817 optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_MAXMSGSIZE + PICO_DHCP_OPTLEN_PARAMLIST + PICO_DHCP_OPTLEN_END;
tass 70:cd218dd180e5 818 hdr = pico_zalloc((size_t)(sizeof(struct pico_dhcp_hdr) + optlen));
tass 68:0847e35d08a6 819 /* specific options */
tass 73:dfb737147f6e 820 offset = (uint16_t)(offset + pico_dhcp_opt_maxmsgsize(&hdr->options[offset], DHCP_CLIENT_MAXMSGZISE));
tass 68:0847e35d08a6 821 break;
tass 68:0847e35d08a6 822
tass 68:0847e35d08a6 823 case PICO_DHCP_MSG_REQUEST:
tass 68:0847e35d08a6 824 dhcpc_dbg("DHCP client: sent DHCPREQUEST\n");
tass 68:0847e35d08a6 825 optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_MAXMSGSIZE + PICO_DHCP_OPTLEN_PARAMLIST + PICO_DHCP_OPTLEN_REQIP + PICO_DHCP_OPTLEN_SERVERID
tass 68:0847e35d08a6 826 + PICO_DHCP_OPTLEN_END;
tass 68:0847e35d08a6 827 hdr = pico_zalloc(sizeof(struct pico_dhcp_hdr) + optlen);
tass 68:0847e35d08a6 828 /* specific options */
tass 73:dfb737147f6e 829 offset = (uint16_t)(offset+pico_dhcp_opt_maxmsgsize(&hdr->options[offset], DHCP_CLIENT_MAXMSGZISE));
tass 68:0847e35d08a6 830 if (dhcpc->state == DHCP_CLIENT_STATE_REQUESTING) {
tass 73:dfb737147f6e 831 offset = (uint16_t)(offset+pico_dhcp_opt_reqip(&hdr->options[offset], &dhcpc->address));
tass 73:dfb737147f6e 832 offset = (uint16_t)(offset+pico_dhcp_opt_serverid(&hdr->options[offset], &dhcpc->server_id));
tass 68:0847e35d08a6 833 }
tass 68:0847e35d08a6 834 break;
tass 68:0847e35d08a6 835
tass 68:0847e35d08a6 836 default:
tass 68:0847e35d08a6 837 return -1;
tass 68:0847e35d08a6 838 }
tass 68:0847e35d08a6 839
tass 68:0847e35d08a6 840 /* common options */
tass 73:dfb737147f6e 841 offset = (uint16_t)(offset+pico_dhcp_opt_msgtype(&hdr->options[offset], msg_type));
tass 73:dfb737147f6e 842 offset = (uint16_t)(offset+pico_dhcp_opt_paramlist(&hdr->options[offset]));
tass 73:dfb737147f6e 843 offset = (uint16_t)(offset+pico_dhcp_opt_end(&hdr->options[offset]));
tass 68:0847e35d08a6 844
tass 68:0847e35d08a6 845 switch (dhcpc->state)
tass 68:0847e35d08a6 846 {
tass 68:0847e35d08a6 847 case DHCP_CLIENT_STATE_BOUND:
tass 68:0847e35d08a6 848 destination.addr = dhcpc->server_id.addr;
tass 68:0847e35d08a6 849 hdr->ciaddr = dhcpc->address.addr;
tass 68:0847e35d08a6 850 break;
tass 68:0847e35d08a6 851
tass 68:0847e35d08a6 852 case DHCP_CLIENT_STATE_RENEWING:
tass 68:0847e35d08a6 853 destination.addr = dhcpc->server_id.addr;
tass 68:0847e35d08a6 854 hdr->ciaddr = dhcpc->address.addr;
tass 68:0847e35d08a6 855 break;
tass 68:0847e35d08a6 856
tass 68:0847e35d08a6 857 case DHCP_CLIENT_STATE_REBINDING:
tass 68:0847e35d08a6 858 hdr->ciaddr = dhcpc->address.addr;
tass 68:0847e35d08a6 859 break;
tass 68:0847e35d08a6 860
tass 68:0847e35d08a6 861 default:
tass 68:0847e35d08a6 862 /* do nothing */
tass 68:0847e35d08a6 863 break;
tass 68:0847e35d08a6 864 }
tass 68:0847e35d08a6 865
tass 68:0847e35d08a6 866 /* header information */
tass 68:0847e35d08a6 867 hdr->op = PICO_DHCP_OP_REQUEST;
tass 68:0847e35d08a6 868 hdr->htype = PICO_DHCP_HTYPE_ETH;
tass 68:0847e35d08a6 869 hdr->hlen = PICO_SIZE_ETH;
tass 68:0847e35d08a6 870 hdr->xid = dhcpc->xid;
tass 68:0847e35d08a6 871 hdr->flags = short_be(PICO_DHCP_FLAG_BROADCAST);
tass 68:0847e35d08a6 872 hdr->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE;
tass 68:0847e35d08a6 873 /* copy client hardware address */
tass 68:0847e35d08a6 874 memcpy(hdr->hwaddr, &dhcpc->dev->eth->mac, PICO_SIZE_ETH);
tass 68:0847e35d08a6 875
tass 70:cd218dd180e5 876 r = pico_socket_sendto(dhcpc->s, hdr, (int)(sizeof(struct pico_dhcp_hdr) + optlen), &destination, PICO_DHCPD_PORT);
tass 68:0847e35d08a6 877 pico_free(hdr);
tass 68:0847e35d08a6 878 if (r < 0)
tass 68:0847e35d08a6 879 return -1;
tass 68:0847e35d08a6 880
tass 68:0847e35d08a6 881 return 0;
tass 68:0847e35d08a6 882 }
tass 68:0847e35d08a6 883
tass 68:0847e35d08a6 884 static void pico_dhcp_client_wakeup(uint16_t ev, struct pico_socket *s)
tass 68:0847e35d08a6 885 {
tass 68:0847e35d08a6 886 uint8_t buf[DHCP_CLIENT_MAXMSGZISE] = {0};
tass 68:0847e35d08a6 887 int r = 0;
tass 68:0847e35d08a6 888 struct pico_dhcp_hdr *hdr = NULL;
tass 68:0847e35d08a6 889 struct pico_dhcp_client_cookie *dhcpc = NULL;
tass 68:0847e35d08a6 890
tass 68:0847e35d08a6 891 if (ev != PICO_SOCK_EV_RD)
tass 68:0847e35d08a6 892 return;
tass 68:0847e35d08a6 893 r = pico_socket_recvfrom(s, buf, DHCP_CLIENT_MAXMSGZISE, NULL, NULL);
tass 68:0847e35d08a6 894 if (r < 0)
tass 68:0847e35d08a6 895 return;
tass 68:0847e35d08a6 896
tass 68:0847e35d08a6 897 /* If the 'xid' of an arriving message does not match the 'xid'
tass 68:0847e35d08a6 898 * of the most recent transmitted message, the message must be
tass 68:0847e35d08a6 899 * silently discarded. */
tass 68:0847e35d08a6 900 hdr = (struct pico_dhcp_hdr *)buf;
tass 68:0847e35d08a6 901 dhcpc = pico_dhcp_client_find_cookie(hdr->xid);
tass 68:0847e35d08a6 902 if (!dhcpc)
tass 68:0847e35d08a6 903 return;
tass 70:cd218dd180e5 904 dhcpc->event = (uint8_t)pico_dhcp_client_opt_parse(buf, (uint16_t)r);
tass 68:0847e35d08a6 905 pico_dhcp_state_machine(dhcpc->event, dhcpc, buf);
tass 68:0847e35d08a6 906 }
tass 68:0847e35d08a6 907
tass 68:0847e35d08a6 908 void *pico_dhcp_get_identifier(uint32_t xid)
tass 68:0847e35d08a6 909 {
tass 68:0847e35d08a6 910 return (void *)pico_dhcp_client_find_cookie(xid);
tass 68:0847e35d08a6 911 }
tass 68:0847e35d08a6 912
tass 68:0847e35d08a6 913 struct pico_ip4 pico_dhcp_get_address(void* dhcpc)
tass 68:0847e35d08a6 914 {
tass 68:0847e35d08a6 915 return ((struct pico_dhcp_client_cookie*)dhcpc)->address;
tass 68:0847e35d08a6 916 }
tass 68:0847e35d08a6 917
tass 68:0847e35d08a6 918 struct pico_ip4 pico_dhcp_get_gateway(void* dhcpc)
tass 68:0847e35d08a6 919 {
tass 68:0847e35d08a6 920 return ((struct pico_dhcp_client_cookie*)dhcpc)->gateway;
tass 68:0847e35d08a6 921 }
tass 68:0847e35d08a6 922
tass 127:476fed453d4d 923 struct pico_ip4 pico_dhcp_get_netmask(void *dhcpc)
tass 127:476fed453d4d 924 {
tass 127:476fed453d4d 925 return ((struct pico_dhcp_client_cookie*)dhcpc)->netmask;
tass 127:476fed453d4d 926 }
tass 127:476fed453d4d 927
tass 128:ae39e6e81531 928
tass 68:0847e35d08a6 929 struct pico_ip4 pico_dhcp_get_nameserver(void* dhcpc)
tass 68:0847e35d08a6 930 {
tass 68:0847e35d08a6 931 return ((struct pico_dhcp_client_cookie*)dhcpc)->nameserver;
tass 68:0847e35d08a6 932 }
tass 68:0847e35d08a6 933 #endif