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 Jan 28 15:12:00 2016 +0100
Revision:
155:a70f34550c34
Parent:
154:6c0e92a80c4a
Adding TCP flag for FIN.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
tass 68:0847e35d08a6 1 /*********************************************************************
tass 152:a3d286bf94e5 2 PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved.
TASS Belgium NV 131:4758606c9316 3 See LICENSE and COPYING for usage.
tass 68:0847e35d08a6 4
tass 68:0847e35d08a6 5
TASS Belgium NV 131:4758606c9316 6 Authors: Frederik Van Slycken, Kristof Roelants
TASS Belgium NV 131:4758606c9316 7 *********************************************************************/
tass 68:0847e35d08a6 8
tass 68:0847e35d08a6 9 #include "pico_dhcp_server.h"
tass 68:0847e35d08a6 10 #include "pico_config.h"
tass 68:0847e35d08a6 11 #include "pico_addressing.h"
tass 68:0847e35d08a6 12 #include "pico_socket.h"
tass 68:0847e35d08a6 13 #include "pico_udp.h"
tass 68:0847e35d08a6 14 #include "pico_stack.h"
tass 68:0847e35d08a6 15 #include "pico_arp.h"
tass 68:0847e35d08a6 16
tass 152:a3d286bf94e5 17 #if (defined PICO_SUPPORT_DHCPD && defined PICO_SUPPORT_UDP)
tass picotcp@tass.be 141:fb35b52d1c80 18
TASS Belgium NV 131:4758606c9316 19 #define dhcps_dbg(...) do {} while(0)
TASS Belgium NV 131:4758606c9316 20 /* #define dhcps_dbg dbg */
tass 68:0847e35d08a6 21
TASS Belgium NV 131:4758606c9316 22 /* default configurations */
tass 68:0847e35d08a6 23 #define DHCP_SERVER_OPENDNS long_be(0xd043dede) /* OpenDNS DNS server 208.67.222.222 */
tass 68:0847e35d08a6 24 #define DHCP_SERVER_POOL_START long_be(0x00000064)
tass 68:0847e35d08a6 25 #define DHCP_SERVER_POOL_END long_be(0x000000fe)
tass 68:0847e35d08a6 26 #define DHCP_SERVER_LEASE_TIME long_be(0x00000078)
tass 68:0847e35d08a6 27
tass 68:0847e35d08a6 28 /* maximum size of a DHCP message */
tass 152:a3d286bf94e5 29 #define DHCP_SERVER_MAXMSGSIZE (PICO_IP_MRU - sizeof(struct pico_ipv4_hdr) - sizeof(struct pico_udp_hdr))
tass 68:0847e35d08a6 30
tass 68:0847e35d08a6 31 enum dhcp_server_state {
TASS Belgium NV 131:4758606c9316 32 PICO_DHCP_STATE_DISCOVER = 0,
TASS Belgium NV 131:4758606c9316 33 PICO_DHCP_STATE_OFFER,
TASS Belgium NV 131:4758606c9316 34 PICO_DHCP_STATE_REQUEST,
TASS Belgium NV 131:4758606c9316 35 PICO_DHCP_STATE_BOUND,
TASS Belgium NV 131:4758606c9316 36 PICO_DHCP_STATE_RENEWING
tass 68:0847e35d08a6 37 };
tass 68:0847e35d08a6 38
tass 68:0847e35d08a6 39 struct pico_dhcp_server_negotiation {
TASS Belgium NV 131:4758606c9316 40 uint32_t xid;
TASS Belgium NV 131:4758606c9316 41 enum dhcp_server_state state;
TASS Belgium NV 131:4758606c9316 42 struct pico_dhcp_server_setting *dhcps;
TASS Belgium NV 131:4758606c9316 43 struct pico_ip4 ciaddr;
TASS Belgium NV 131:4758606c9316 44 struct pico_eth hwaddr;
tass picotcp@tass.be 149:5f4cb161cec3 45 uint8_t bcast;
tass 68:0847e35d08a6 46 };
tass 68:0847e35d08a6 47
tass picotcp@tass.be 149:5f4cb161cec3 48 static inline int ip_address_is_in_dhcp_range(struct pico_dhcp_server_negotiation *n, uint32_t x)
tass picotcp@tass.be 149:5f4cb161cec3 49 {
tass picotcp@tass.be 149:5f4cb161cec3 50 uint32_t ip_hostendian = long_be(x);
tass picotcp@tass.be 149:5f4cb161cec3 51 if (ip_hostendian < long_be(n->dhcps->pool_start))
tass picotcp@tass.be 149:5f4cb161cec3 52 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 53
tass picotcp@tass.be 149:5f4cb161cec3 54 if (ip_hostendian > long_be(n->dhcps->pool_end))
tass picotcp@tass.be 149:5f4cb161cec3 55 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 56
tass picotcp@tass.be 149:5f4cb161cec3 57 return 1;
tass picotcp@tass.be 149:5f4cb161cec3 58 }
tass picotcp@tass.be 149:5f4cb161cec3 59
tass picotcp@tass.be 149:5f4cb161cec3 60
tass 68:0847e35d08a6 61 static void pico_dhcpd_wakeup(uint16_t ev, struct pico_socket *s);
tass 68:0847e35d08a6 62
tass 68:0847e35d08a6 63 static int dhcp_settings_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 64 {
TASS Belgium NV 131:4758606c9316 65 struct pico_dhcp_server_setting *a = ka, *b = kb;
TASS Belgium NV 131:4758606c9316 66 if (a->dev == b->dev)
TASS Belgium NV 131:4758606c9316 67 return 0;
TASS Belgium NV 131:4758606c9316 68
tass picotcp@tass.be 149:5f4cb161cec3 69 return (a->dev < b->dev) ? (-1) : (1);
TASS Belgium NV 131:4758606c9316 70 }
tass 68:0847e35d08a6 71 PICO_TREE_DECLARE(DHCPSettings, dhcp_settings_cmp);
tass 68:0847e35d08a6 72
tass 68:0847e35d08a6 73 static int dhcp_negotiations_cmp(void *ka, void *kb)
tass 68:0847e35d08a6 74 {
TASS Belgium NV 131:4758606c9316 75 struct pico_dhcp_server_negotiation *a = ka, *b = kb;
TASS Belgium NV 131:4758606c9316 76 if (a->xid == b->xid)
TASS Belgium NV 131:4758606c9316 77 return 0;
TASS Belgium NV 131:4758606c9316 78
tass picotcp@tass.be 149:5f4cb161cec3 79 return (a->xid < b->xid) ? (-1) : (1);
TASS Belgium NV 131:4758606c9316 80 }
tass 68:0847e35d08a6 81 PICO_TREE_DECLARE(DHCPNegotiations, dhcp_negotiations_cmp);
tass 68:0847e35d08a6 82
tass 152:a3d286bf94e5 83
tass 152:a3d286bf94e5 84 static inline void dhcps_set_default_pool_start_if_not_provided(struct pico_dhcp_server_setting *dhcps)
tass 152:a3d286bf94e5 85 {
tass 152:a3d286bf94e5 86 if (!dhcps->pool_start)
tass 152:a3d286bf94e5 87 dhcps->pool_start = (dhcps->server_ip.addr & dhcps->netmask.addr) | DHCP_SERVER_POOL_START;
tass 152:a3d286bf94e5 88 }
tass 152:a3d286bf94e5 89
tass 152:a3d286bf94e5 90 static inline void dhcps_set_default_pool_end_if_not_provided(struct pico_dhcp_server_setting *dhcps)
tass 152:a3d286bf94e5 91 {
tass 152:a3d286bf94e5 92 if (!dhcps->pool_end)
tass 152:a3d286bf94e5 93 dhcps->pool_end = (dhcps->server_ip.addr & dhcps->netmask.addr) | DHCP_SERVER_POOL_END;
tass 152:a3d286bf94e5 94 }
tass 152:a3d286bf94e5 95 static inline void dhcps_set_default_lease_time_if_not_provided(struct pico_dhcp_server_setting *dhcps)
tass 152:a3d286bf94e5 96 {
tass 152:a3d286bf94e5 97 if (!dhcps->lease_time)
tass 152:a3d286bf94e5 98 dhcps->lease_time = DHCP_SERVER_LEASE_TIME;
tass 152:a3d286bf94e5 99 }
tass 152:a3d286bf94e5 100
tass 152:a3d286bf94e5 101 static inline struct pico_dhcp_server_setting *dhcps_try_open_socket(struct pico_dhcp_server_setting *dhcps)
tass 152:a3d286bf94e5 102 {
tass 152:a3d286bf94e5 103 uint16_t port = PICO_DHCPD_PORT;
tass 152:a3d286bf94e5 104 dhcps->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcpd_wakeup);
tass 152:a3d286bf94e5 105 if (!dhcps->s) {
tass 152:a3d286bf94e5 106 dhcps_dbg("DHCP server ERROR: failure opening socket (%s)\n", strerror(pico_err));
tass 152:a3d286bf94e5 107 PICO_FREE(dhcps);
tass 152:a3d286bf94e5 108 return NULL;
tass 152:a3d286bf94e5 109 }
tass 152:a3d286bf94e5 110
tass 152:a3d286bf94e5 111 if (pico_socket_bind(dhcps->s, &dhcps->server_ip, &port) < 0) {
tass 152:a3d286bf94e5 112 dhcps_dbg("DHCP server ERROR: failure binding socket (%s)\n", strerror(pico_err));
tass 152:a3d286bf94e5 113 PICO_FREE(dhcps);
tass 152:a3d286bf94e5 114 return NULL;
tass 152:a3d286bf94e5 115 }
tass 152:a3d286bf94e5 116
tass 152:a3d286bf94e5 117 pico_tree_insert(&DHCPSettings, dhcps);
tass 152:a3d286bf94e5 118 return dhcps;
tass 152:a3d286bf94e5 119 }
tass 152:a3d286bf94e5 120
tass 68:0847e35d08a6 121 static struct pico_dhcp_server_setting *pico_dhcp_server_add_setting(struct pico_dhcp_server_setting *setting)
tass 68:0847e35d08a6 122 {
TASS Belgium NV 131:4758606c9316 123 struct pico_dhcp_server_setting *dhcps = NULL, *found = NULL, test = {
TASS Belgium NV 131:4758606c9316 124 0
TASS Belgium NV 131:4758606c9316 125 };
TASS Belgium NV 131:4758606c9316 126 struct pico_ipv4_link *link = NULL;
TASS Belgium NV 131:4758606c9316 127
TASS Belgium NV 131:4758606c9316 128 link = pico_ipv4_link_get(&setting->server_ip);
TASS Belgium NV 131:4758606c9316 129 if (!link) {
TASS Belgium NV 131:4758606c9316 130 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 131 return NULL;
TASS Belgium NV 131:4758606c9316 132 }
TASS Belgium NV 131:4758606c9316 133
TASS Belgium NV 131:4758606c9316 134 test.dev = setting->dev;
TASS Belgium NV 131:4758606c9316 135 found = pico_tree_findKey(&DHCPSettings, &test);
TASS Belgium NV 131:4758606c9316 136 if (found) {
TASS Belgium NV 131:4758606c9316 137 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 138 return NULL;
TASS Belgium NV 131:4758606c9316 139 }
TASS Belgium NV 131:4758606c9316 140
tass picotcp@tass.be 149:5f4cb161cec3 141 dhcps = PICO_ZALLOC(sizeof(struct pico_dhcp_server_setting));
TASS Belgium NV 131:4758606c9316 142 if (!dhcps) {
TASS Belgium NV 131:4758606c9316 143 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 144 return NULL;
TASS Belgium NV 131:4758606c9316 145 }
tass 68:0847e35d08a6 146
TASS Belgium NV 131:4758606c9316 147 dhcps->lease_time = setting->lease_time;
TASS Belgium NV 131:4758606c9316 148 dhcps->pool_start = setting->pool_start;
TASS Belgium NV 131:4758606c9316 149 dhcps->pool_next = setting->pool_next;
TASS Belgium NV 131:4758606c9316 150 dhcps->pool_end = setting->pool_end;
TASS Belgium NV 131:4758606c9316 151 dhcps->dev = link->dev;
TASS Belgium NV 131:4758606c9316 152 dhcps->server_ip = link->address;
TASS Belgium NV 131:4758606c9316 153 dhcps->netmask = link->netmask;
TASS Belgium NV 131:4758606c9316 154
TASS Belgium NV 131:4758606c9316 155 /* default values if not provided */
tass 152:a3d286bf94e5 156 dhcps_set_default_lease_time_if_not_provided(dhcps);
tass 152:a3d286bf94e5 157 dhcps_set_default_pool_end_if_not_provided(dhcps);
tass 152:a3d286bf94e5 158 dhcps_set_default_pool_start_if_not_provided(dhcps);
tass 68:0847e35d08a6 159
TASS Belgium NV 131:4758606c9316 160 dhcps->pool_next = dhcps->pool_start;
TASS Belgium NV 131:4758606c9316 161
tass 152:a3d286bf94e5 162 return dhcps_try_open_socket(dhcps);
tass 68:0847e35d08a6 163
tass 68:0847e35d08a6 164 }
tass 68:0847e35d08a6 165
tass 68:0847e35d08a6 166 static struct pico_dhcp_server_negotiation *pico_dhcp_server_find_negotiation(uint32_t xid)
tass 68:0847e35d08a6 167 {
TASS Belgium NV 131:4758606c9316 168 struct pico_dhcp_server_negotiation test = {
TASS Belgium NV 131:4758606c9316 169 0
TASS Belgium NV 131:4758606c9316 170 }, *found = NULL;
tass 68:0847e35d08a6 171
TASS Belgium NV 131:4758606c9316 172 test.xid = xid;
TASS Belgium NV 131:4758606c9316 173 found = pico_tree_findKey(&DHCPNegotiations, &test);
TASS Belgium NV 131:4758606c9316 174 if (found)
TASS Belgium NV 131:4758606c9316 175 return found;
TASS Belgium NV 131:4758606c9316 176 else
TASS Belgium NV 131:4758606c9316 177 return NULL;
tass 68:0847e35d08a6 178 }
tass 68:0847e35d08a6 179
tass 152:a3d286bf94e5 180 static inline void dhcp_negotiation_set_ciaddr(struct pico_dhcp_server_negotiation *dhcpn)
tass 152:a3d286bf94e5 181 {
tass 152:a3d286bf94e5 182 struct pico_ip4 *ciaddr = NULL;
tass 152:a3d286bf94e5 183 ciaddr = pico_arp_reverse_lookup(&dhcpn->hwaddr);
tass 152:a3d286bf94e5 184 if (!ciaddr) {
tass 152:a3d286bf94e5 185 dhcpn->ciaddr.addr = dhcpn->dhcps->pool_next;
tass 152:a3d286bf94e5 186 dhcpn->dhcps->pool_next = long_be(long_be(dhcpn->dhcps->pool_next) + 1);
tass 152:a3d286bf94e5 187 pico_arp_create_entry(dhcpn->hwaddr.addr, dhcpn->ciaddr, dhcpn->dhcps->dev);
tass 152:a3d286bf94e5 188 } else {
tass 152:a3d286bf94e5 189 dhcpn->ciaddr = *ciaddr;
tass 152:a3d286bf94e5 190 }
tass 152:a3d286bf94e5 191 }
tass 152:a3d286bf94e5 192
tass 68:0847e35d08a6 193 static struct pico_dhcp_server_negotiation *pico_dhcp_server_add_negotiation(struct pico_device *dev, struct pico_dhcp_hdr *hdr)
tass 68:0847e35d08a6 194 {
TASS Belgium NV 131:4758606c9316 195 struct pico_dhcp_server_negotiation *dhcpn = NULL;
TASS Belgium NV 131:4758606c9316 196 struct pico_dhcp_server_setting test = {
TASS Belgium NV 131:4758606c9316 197 0
TASS Belgium NV 131:4758606c9316 198 };
tass 68:0847e35d08a6 199
TASS Belgium NV 131:4758606c9316 200 if (pico_dhcp_server_find_negotiation(hdr->xid))
TASS Belgium NV 131:4758606c9316 201 return NULL;
tass 68:0847e35d08a6 202
tass picotcp@tass.be 149:5f4cb161cec3 203 dhcpn = PICO_ZALLOC(sizeof(struct pico_dhcp_server_negotiation));
TASS Belgium NV 131:4758606c9316 204 if (!dhcpn) {
TASS Belgium NV 131:4758606c9316 205 pico_err = PICO_ERR_ENOMEM;
TASS Belgium NV 131:4758606c9316 206 return NULL;
TASS Belgium NV 131:4758606c9316 207 }
tass 68:0847e35d08a6 208
TASS Belgium NV 131:4758606c9316 209 dhcpn->xid = hdr->xid;
TASS Belgium NV 131:4758606c9316 210 dhcpn->state = PICO_DHCP_STATE_DISCOVER;
tass picotcp@tass.be 149:5f4cb161cec3 211 dhcpn->bcast = ((short_be(hdr->flags) & PICO_DHCP_FLAG_BROADCAST) != 0) ? (1) : (0);
TASS Belgium NV 131:4758606c9316 212 memcpy(dhcpn->hwaddr.addr, hdr->hwaddr, PICO_SIZE_ETH);
tass 68:0847e35d08a6 213
TASS Belgium NV 131:4758606c9316 214 test.dev = dev;
TASS Belgium NV 131:4758606c9316 215 dhcpn->dhcps = pico_tree_findKey(&DHCPSettings, &test);
TASS Belgium NV 131:4758606c9316 216 if (!dhcpn->dhcps) {
TASS Belgium NV 131:4758606c9316 217 dhcps_dbg("DHCP server WARNING: received DHCP message on unconfigured link %s\n", dev->name);
tass picotcp@tass.be 149:5f4cb161cec3 218 PICO_FREE(dhcpn);
TASS Belgium NV 131:4758606c9316 219 return NULL;
TASS Belgium NV 131:4758606c9316 220 }
tass 68:0847e35d08a6 221
tass 152:a3d286bf94e5 222 dhcp_negotiation_set_ciaddr(dhcpn);
TASS Belgium NV 131:4758606c9316 223 pico_tree_insert(&DHCPNegotiations, dhcpn);
TASS Belgium NV 131:4758606c9316 224 return dhcpn;
tass 68:0847e35d08a6 225 }
tass 68:0847e35d08a6 226
tass 68:0847e35d08a6 227 static void dhcpd_make_reply(struct pico_dhcp_server_negotiation *dhcpn, uint8_t msg_type)
tass 68:0847e35d08a6 228 {
TASS Belgium NV 131:4758606c9316 229 int r = 0, optlen = 0, offset = 0;
TASS Belgium NV 131:4758606c9316 230 struct pico_ip4 broadcast = {
TASS Belgium NV 131:4758606c9316 231 0
TASS Belgium NV 131:4758606c9316 232 }, dns = {
TASS Belgium NV 131:4758606c9316 233 0
TASS Belgium NV 131:4758606c9316 234 }, destination = {
TASS Belgium NV 131:4758606c9316 235 .addr = 0xFFFFFFFF
TASS Belgium NV 131:4758606c9316 236 };
TASS Belgium NV 131:4758606c9316 237 struct pico_dhcp_hdr *hdr = NULL;
tass 68:0847e35d08a6 238
TASS Belgium NV 131:4758606c9316 239 dns.addr = DHCP_SERVER_OPENDNS;
TASS Belgium NV 131:4758606c9316 240 broadcast.addr = dhcpn->dhcps->server_ip.addr | ~(dhcpn->dhcps->netmask.addr);
tass 68:0847e35d08a6 241
TASS Belgium NV 131:4758606c9316 242 optlen = PICO_DHCP_OPTLEN_MSGTYPE + PICO_DHCP_OPTLEN_SERVERID + PICO_DHCP_OPTLEN_LEASETIME + PICO_DHCP_OPTLEN_NETMASK + PICO_DHCP_OPTLEN_ROUTER
TASS Belgium NV 131:4758606c9316 243 + PICO_DHCP_OPTLEN_BROADCAST + PICO_DHCP_OPTLEN_DNS + PICO_DHCP_OPTLEN_END;
tass picotcp@tass.be 149:5f4cb161cec3 244 hdr = PICO_ZALLOC(sizeof(struct pico_dhcp_hdr) + (uint32_t)optlen);
tass picotcp@tass.be 149:5f4cb161cec3 245 if (!hdr) {
tass picotcp@tass.be 149:5f4cb161cec3 246 return;
tass picotcp@tass.be 149:5f4cb161cec3 247 }
tass 68:0847e35d08a6 248
TASS Belgium NV 131:4758606c9316 249 hdr->op = PICO_DHCP_OP_REPLY;
TASS Belgium NV 131:4758606c9316 250 hdr->htype = PICO_DHCP_HTYPE_ETH;
TASS Belgium NV 131:4758606c9316 251 hdr->hlen = PICO_SIZE_ETH;
TASS Belgium NV 131:4758606c9316 252 hdr->xid = dhcpn->xid;
TASS Belgium NV 131:4758606c9316 253 hdr->yiaddr = dhcpn->ciaddr.addr;
TASS Belgium NV 131:4758606c9316 254 hdr->siaddr = dhcpn->dhcps->server_ip.addr;
TASS Belgium NV 131:4758606c9316 255 hdr->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE;
TASS Belgium NV 131:4758606c9316 256 memcpy(hdr->hwaddr, dhcpn->hwaddr.addr, PICO_SIZE_ETH);
tass 68:0847e35d08a6 257
TASS Belgium NV 131:4758606c9316 258 /* options */
tass 154:6c0e92a80c4a 259 offset += pico_dhcp_opt_msgtype(DHCP_OPT(hdr,offset), msg_type);
tass 154:6c0e92a80c4a 260 offset += pico_dhcp_opt_serverid(DHCP_OPT(hdr,offset), &dhcpn->dhcps->server_ip);
tass 154:6c0e92a80c4a 261 offset += pico_dhcp_opt_leasetime(DHCP_OPT(hdr,offset), dhcpn->dhcps->lease_time);
tass 154:6c0e92a80c4a 262 offset += pico_dhcp_opt_netmask(DHCP_OPT(hdr,offset), &dhcpn->dhcps->netmask);
tass 154:6c0e92a80c4a 263 offset += pico_dhcp_opt_router(DHCP_OPT(hdr,offset), &dhcpn->dhcps->server_ip);
tass 154:6c0e92a80c4a 264 offset += pico_dhcp_opt_broadcast(DHCP_OPT(hdr,offset), &broadcast);
tass 154:6c0e92a80c4a 265 offset += pico_dhcp_opt_dns(DHCP_OPT(hdr,offset), &dns);
tass 154:6c0e92a80c4a 266 offset += pico_dhcp_opt_end(DHCP_OPT(hdr,offset));
tass 68:0847e35d08a6 267
tass picotcp@tass.be 149:5f4cb161cec3 268 if (dhcpn->bcast == 0)
tass picotcp@tass.be 149:5f4cb161cec3 269 destination.addr = hdr->yiaddr;
tass picotcp@tass.be 149:5f4cb161cec3 270 else {
tass picotcp@tass.be 149:5f4cb161cec3 271 hdr->flags |= short_be(PICO_DHCP_FLAG_BROADCAST);
tass picotcp@tass.be 149:5f4cb161cec3 272 destination.addr = broadcast.addr;
tass picotcp@tass.be 149:5f4cb161cec3 273 }
tass picotcp@tass.be 149:5f4cb161cec3 274
TASS Belgium NV 131:4758606c9316 275 r = pico_socket_sendto(dhcpn->dhcps->s, hdr, (int)(sizeof(struct pico_dhcp_hdr) + (uint32_t)optlen), &destination, PICO_DHCP_CLIENT_PORT);
TASS Belgium NV 131:4758606c9316 276 if (r < 0)
TASS Belgium NV 131:4758606c9316 277 dhcps_dbg("DHCP server WARNING: failure sending: %s!\n", strerror(pico_err));
tass 68:0847e35d08a6 278
tass 152:a3d286bf94e5 279 PICO_FREE(hdr);
tass 152:a3d286bf94e5 280
TASS Belgium NV 131:4758606c9316 281 return;
tass 68:0847e35d08a6 282 }
tass 68:0847e35d08a6 283
tass 152:a3d286bf94e5 284 static inline void parse_opt_msgtype(struct pico_dhcp_opt *opt, uint8_t *msgtype)
tass 152:a3d286bf94e5 285 {
tass 152:a3d286bf94e5 286 if (opt->code == PICO_DHCP_OPT_MSGTYPE) {
tass 152:a3d286bf94e5 287 *msgtype = opt->ext.msg_type.type;
tass 152:a3d286bf94e5 288 dhcps_dbg("DHCP server: message type %u\n", msgtype);
tass 152:a3d286bf94e5 289 }
tass 152:a3d286bf94e5 290 }
tass 152:a3d286bf94e5 291
tass 152:a3d286bf94e5 292 static inline void parse_opt_reqip(struct pico_dhcp_opt *opt, struct pico_ip4 *reqip)
tass 152:a3d286bf94e5 293 {
tass 152:a3d286bf94e5 294 if (opt->code == PICO_DHCP_OPT_REQIP)
tass 152:a3d286bf94e5 295 reqip->addr = opt->ext.req_ip.ip.addr;
tass 152:a3d286bf94e5 296 }
tass 152:a3d286bf94e5 297
tass 152:a3d286bf94e5 298 static inline void parse_opt_serverid(struct pico_dhcp_opt *opt, struct pico_ip4 *serverid)
tass 152:a3d286bf94e5 299 {
tass 152:a3d286bf94e5 300 if (opt->code == PICO_DHCP_OPT_SERVERID)
tass 152:a3d286bf94e5 301 *serverid = opt->ext.server_id.ip;
tass 152:a3d286bf94e5 302 }
tass 152:a3d286bf94e5 303
tass 152:a3d286bf94e5 304 static inline void dhcps_make_reply_to_request_msg(struct pico_dhcp_server_negotiation *dhcpn, int bound_valid_flag)
tass 68:0847e35d08a6 305 {
tass 152:a3d286bf94e5 306 if ((dhcpn->state == PICO_DHCP_STATE_BOUND) && bound_valid_flag)
tass 152:a3d286bf94e5 307 dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_ACK);
tass 152:a3d286bf94e5 308
tass 152:a3d286bf94e5 309 if (dhcpn->state == PICO_DHCP_STATE_OFFER) {
tass 152:a3d286bf94e5 310 dhcpn->state = PICO_DHCP_STATE_BOUND;
tass 152:a3d286bf94e5 311 dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_ACK);
tass 152:a3d286bf94e5 312 }
tass 152:a3d286bf94e5 313 }
tass 152:a3d286bf94e5 314
tass 152:a3d286bf94e5 315 static inline void dhcps_make_reply_to_discover_or_request(struct pico_dhcp_server_negotiation *dhcpn, uint8_t msgtype, int bound_valid_flag)
tass 152:a3d286bf94e5 316 {
tass 152:a3d286bf94e5 317 if (PICO_DHCP_MSG_DISCOVER == msgtype) {
tass 152:a3d286bf94e5 318 dhcpd_make_reply(dhcpn, PICO_DHCP_MSG_OFFER);
tass 152:a3d286bf94e5 319 dhcpn->state = PICO_DHCP_STATE_OFFER;
tass 152:a3d286bf94e5 320 } else if (PICO_DHCP_MSG_REQUEST == msgtype) {
tass 152:a3d286bf94e5 321 dhcps_make_reply_to_request_msg(dhcpn, bound_valid_flag);
tass 152:a3d286bf94e5 322 }
tass 152:a3d286bf94e5 323 }
tass 152:a3d286bf94e5 324
tass 152:a3d286bf94e5 325 static inline void dhcps_parse_options_loop(struct pico_dhcp_server_negotiation *dhcpn, struct pico_dhcp_hdr *hdr)
tass 152:a3d286bf94e5 326 {
tass 154:6c0e92a80c4a 327 struct pico_dhcp_opt *opt = DHCP_OPT(hdr,0);
TASS Belgium NV 131:4758606c9316 328 uint8_t msgtype = 0;
TASS Belgium NV 131:4758606c9316 329 struct pico_ip4 reqip = {
TASS Belgium NV 131:4758606c9316 330 0
TASS Belgium NV 131:4758606c9316 331 }, server_id = {
TASS Belgium NV 131:4758606c9316 332 0
TASS Belgium NV 131:4758606c9316 333 };
tass 152:a3d286bf94e5 334
tass 152:a3d286bf94e5 335 do {
tass 152:a3d286bf94e5 336 parse_opt_msgtype(opt, &msgtype);
tass 152:a3d286bf94e5 337 parse_opt_reqip(opt, &reqip);
tass 152:a3d286bf94e5 338 parse_opt_serverid(opt, &server_id);
tass 152:a3d286bf94e5 339 } while (pico_dhcp_next_option(&opt));
tass 152:a3d286bf94e5 340 dhcps_make_reply_to_discover_or_request(dhcpn, msgtype, (!reqip.addr) && (!server_id.addr) && (hdr->ciaddr == dhcpn->ciaddr.addr));
tass 152:a3d286bf94e5 341 }
tass 152:a3d286bf94e5 342
tass 152:a3d286bf94e5 343 static void pico_dhcp_server_recv(struct pico_socket *s, uint8_t *buf, uint32_t len)
tass 152:a3d286bf94e5 344 {
tass 152:a3d286bf94e5 345 int32_t optlen = (int32_t)(len - sizeof(struct pico_dhcp_hdr));
tass 152:a3d286bf94e5 346 struct pico_dhcp_hdr *hdr = (struct pico_dhcp_hdr *)buf;
tass 152:a3d286bf94e5 347 struct pico_dhcp_server_negotiation *dhcpn = NULL;
TASS Belgium NV 131:4758606c9316 348 struct pico_device *dev = NULL;
tass 68:0847e35d08a6 349
tass 154:6c0e92a80c4a 350 if (!pico_dhcp_are_options_valid(DHCP_OPT(hdr,0), optlen))
TASS Belgium NV 131:4758606c9316 351 return;
TASS Belgium NV 131:4758606c9316 352
TASS Belgium NV 131:4758606c9316 353 dev = pico_ipv4_link_find(&s->local_addr.ip4);
TASS Belgium NV 131:4758606c9316 354 dhcpn = pico_dhcp_server_find_negotiation(hdr->xid);
TASS Belgium NV 131:4758606c9316 355 if (!dhcpn)
TASS Belgium NV 131:4758606c9316 356 dhcpn = pico_dhcp_server_add_negotiation(dev, hdr);
TASS Belgium NV 131:4758606c9316 357
tass picotcp@tass.be 149:5f4cb161cec3 358 if (!ip_address_is_in_dhcp_range(dhcpn, dhcpn->ciaddr.addr))
TASS Belgium NV 131:4758606c9316 359 return;
TASS Belgium NV 131:4758606c9316 360
tass 152:a3d286bf94e5 361 dhcps_parse_options_loop(dhcpn, hdr);
tass 68:0847e35d08a6 362
tass 68:0847e35d08a6 363 }
tass 68:0847e35d08a6 364
tass 68:0847e35d08a6 365 static void pico_dhcpd_wakeup(uint16_t ev, struct pico_socket *s)
tass 68:0847e35d08a6 366 {
TASS Belgium NV 131:4758606c9316 367 uint8_t buf[DHCP_SERVER_MAXMSGSIZE] = {
TASS Belgium NV 131:4758606c9316 368 0
TASS Belgium NV 131:4758606c9316 369 };
TASS Belgium NV 131:4758606c9316 370 int r = 0;
tass 68:0847e35d08a6 371
TASS Belgium NV 131:4758606c9316 372 if (ev != PICO_SOCK_EV_RD)
TASS Belgium NV 131:4758606c9316 373 return;
TASS Belgium NV 131:4758606c9316 374
TASS Belgium NV 131:4758606c9316 375 r = pico_socket_recvfrom(s, buf, DHCP_SERVER_MAXMSGSIZE, NULL, NULL);
TASS Belgium NV 131:4758606c9316 376 if (r < 0)
TASS Belgium NV 131:4758606c9316 377 return;
TASS Belgium NV 131:4758606c9316 378
TASS Belgium NV 131:4758606c9316 379 pico_dhcp_server_recv(s, buf, (uint32_t)r);
tass 68:0847e35d08a6 380 return;
tass 68:0847e35d08a6 381 }
tass 68:0847e35d08a6 382
tass 68:0847e35d08a6 383 int pico_dhcp_server_initiate(struct pico_dhcp_server_setting *setting)
tass 68:0847e35d08a6 384 {
TASS Belgium NV 131:4758606c9316 385 if (!setting || !setting->server_ip.addr) {
TASS Belgium NV 131:4758606c9316 386 pico_err = PICO_ERR_EINVAL;
TASS Belgium NV 131:4758606c9316 387 return -1;
TASS Belgium NV 131:4758606c9316 388 }
tass 68:0847e35d08a6 389
TASS Belgium NV 131:4758606c9316 390 if (pico_dhcp_server_add_setting(setting) == NULL)
TASS Belgium NV 131:4758606c9316 391 return -1;
tass 68:0847e35d08a6 392
TASS Belgium NV 131:4758606c9316 393 return 0;
tass 68:0847e35d08a6 394 }
tass picotcp@tass.be 149:5f4cb161cec3 395
tass picotcp@tass.be 149:5f4cb161cec3 396 int pico_dhcp_server_destroy(struct pico_device *dev)
tass picotcp@tass.be 149:5f4cb161cec3 397 {
tass 154:6c0e92a80c4a 398 struct pico_dhcp_server_setting *found, test = { 0 };
tass 154:6c0e92a80c4a 399 test.dev = dev;
tass picotcp@tass.be 149:5f4cb161cec3 400 found = pico_tree_findKey(&DHCPSettings, &test);
tass picotcp@tass.be 149:5f4cb161cec3 401 if (!found) {
tass picotcp@tass.be 149:5f4cb161cec3 402 pico_err = PICO_ERR_ENOENT;
tass picotcp@tass.be 149:5f4cb161cec3 403 return -1;
tass picotcp@tass.be 149:5f4cb161cec3 404 }
tass picotcp@tass.be 149:5f4cb161cec3 405
tass picotcp@tass.be 149:5f4cb161cec3 406 pico_tree_delete(&DHCPSettings, found);
tass picotcp@tass.be 149:5f4cb161cec3 407 PICO_FREE(found);
tass picotcp@tass.be 149:5f4cb161cec3 408 return 0;
tass picotcp@tass.be 149:5f4cb161cec3 409 }
tass picotcp@tass.be 149:5f4cb161cec3 410
tass 68:0847e35d08a6 411 #endif /* PICO_SUPPORT_DHCP */