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 Belgium NV
Date:
Mon Dec 16 11:25:54 2013 +0100
Revision:
131:4758606c9316
Parent:
128:ae39e6e81531
Child:
137:a1c8bfa9d691
Syncronized with master branch

Who changed what in which revision?

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