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:
daniele
Date:
Fri May 24 15:25:25 2013 +0000
Revision:
3:b4047e8a0123
Updated from main repo + fixed Mutexes;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
daniele 3:b4047e8a0123 1 /*********************************************************************
daniele 3:b4047e8a0123 2 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
daniele 3:b4047e8a0123 3 See LICENSE and COPYING for usage.
daniele 3:b4047e8a0123 4
daniele 3:b4047e8a0123 5
daniele 3:b4047e8a0123 6 Authors: Frederik Van Slycken, Kristof Roelants
daniele 3:b4047e8a0123 7 *********************************************************************/
daniele 3:b4047e8a0123 8
daniele 3:b4047e8a0123 9 #ifdef PICO_SUPPORT_DHCPD
daniele 3:b4047e8a0123 10
daniele 3:b4047e8a0123 11 #include "pico_dhcp_server.h"
daniele 3:b4047e8a0123 12 #include "pico_stack.h"
daniele 3:b4047e8a0123 13 #include "pico_config.h"
daniele 3:b4047e8a0123 14 #include "pico_addressing.h"
daniele 3:b4047e8a0123 15 #include "pico_socket.h"
daniele 3:b4047e8a0123 16 #include "pico_arp.h"
daniele 3:b4047e8a0123 17 #include <stdlib.h>
daniele 3:b4047e8a0123 18
daniele 3:b4047e8a0123 19 # define dhcpd_dbg(...) do{}while(0)
daniele 3:b4047e8a0123 20 //# define dhcpd_dbg dbg
daniele 3:b4047e8a0123 21
daniele 3:b4047e8a0123 22 #define dhcpd_make_offer(x) dhcpd_make_reply(x, PICO_DHCP_MSG_OFFER)
daniele 3:b4047e8a0123 23 #define dhcpd_make_ack(x) dhcpd_make_reply(x, PICO_DHCP_MSG_ACK)
daniele 3:b4047e8a0123 24 #define ip_inrange(x) ((long_be(x) >= long_be(dn->settings->pool_start)) && (long_be(x) <= long_be(dn->settings->pool_end)))
daniele 3:b4047e8a0123 25
daniele 3:b4047e8a0123 26 static int dhcp_settings_cmp(void *ka, void *kb)
daniele 3:b4047e8a0123 27 {
daniele 3:b4047e8a0123 28 struct pico_dhcpd_settings *a = ka, *b = kb;
daniele 3:b4047e8a0123 29 if (a->dev < b->dev)
daniele 3:b4047e8a0123 30 return -1;
daniele 3:b4047e8a0123 31 else if (a->dev > b->dev)
daniele 3:b4047e8a0123 32 return 1;
daniele 3:b4047e8a0123 33 else
daniele 3:b4047e8a0123 34 return 0;
daniele 3:b4047e8a0123 35 }
daniele 3:b4047e8a0123 36 PICO_TREE_DECLARE(DHCPSettings, dhcp_settings_cmp);
daniele 3:b4047e8a0123 37
daniele 3:b4047e8a0123 38 static int dhcp_negotiations_cmp(void *ka, void *kb)
daniele 3:b4047e8a0123 39 {
daniele 3:b4047e8a0123 40 struct pico_dhcp_negotiation *a = ka, *b = kb;
daniele 3:b4047e8a0123 41 if (a->xid < b->xid)
daniele 3:b4047e8a0123 42 return -1;
daniele 3:b4047e8a0123 43 else if (a->xid > b->xid)
daniele 3:b4047e8a0123 44 return 1;
daniele 3:b4047e8a0123 45 else
daniele 3:b4047e8a0123 46 return 0;
daniele 3:b4047e8a0123 47 }
daniele 3:b4047e8a0123 48 PICO_TREE_DECLARE(DHCPNegotiations, dhcp_negotiations_cmp);
daniele 3:b4047e8a0123 49
daniele 3:b4047e8a0123 50 static struct pico_dhcp_negotiation *get_negotiation_by_xid(uint32_t xid)
daniele 3:b4047e8a0123 51 {
daniele 3:b4047e8a0123 52 struct pico_dhcp_negotiation test = { }, *neg = NULL;
daniele 3:b4047e8a0123 53
daniele 3:b4047e8a0123 54 test.xid = xid;
daniele 3:b4047e8a0123 55 neg = pico_tree_findKey(&DHCPNegotiations, &test);
daniele 3:b4047e8a0123 56 if (!neg)
daniele 3:b4047e8a0123 57 return NULL;
daniele 3:b4047e8a0123 58 else
daniele 3:b4047e8a0123 59 return neg;
daniele 3:b4047e8a0123 60 }
daniele 3:b4047e8a0123 61
daniele 3:b4047e8a0123 62 static void dhcpd_make_reply(struct pico_dhcp_negotiation *dn, uint8_t reply_type)
daniele 3:b4047e8a0123 63 {
daniele 3:b4047e8a0123 64 uint8_t buf_out[DHCPD_DATAGRAM_SIZE] = {0};
daniele 3:b4047e8a0123 65 struct pico_dhcphdr *dh_out = (struct pico_dhcphdr *) buf_out;
daniele 3:b4047e8a0123 66 struct pico_ip4 destination = { };
daniele 3:b4047e8a0123 67 uint32_t bcast = dn->settings->my_ip.addr | ~(dn->settings->netmask.addr);
daniele 3:b4047e8a0123 68 uint32_t dns_server = OPENDNS;
daniele 3:b4047e8a0123 69 uint16_t port = PICO_DHCP_CLIENT_PORT;
daniele 3:b4047e8a0123 70 int sent = 0;
daniele 3:b4047e8a0123 71
daniele 3:b4047e8a0123 72 memcpy(dh_out->hwaddr, dn->eth.addr, PICO_HLEN_ETHER);
daniele 3:b4047e8a0123 73 dh_out->op = PICO_DHCP_OP_REPLY;
daniele 3:b4047e8a0123 74 dh_out->htype = PICO_HTYPE_ETHER;
daniele 3:b4047e8a0123 75 dh_out->hlen = PICO_HLEN_ETHER;
daniele 3:b4047e8a0123 76 dh_out->xid = dn->xid;
daniele 3:b4047e8a0123 77 dh_out->yiaddr = dn->ipv4.addr;
daniele 3:b4047e8a0123 78 dh_out->siaddr = dn->settings->my_ip.addr;
daniele 3:b4047e8a0123 79 dh_out->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE;
daniele 3:b4047e8a0123 80
daniele 3:b4047e8a0123 81 /* Option: msg type, len 1 */
daniele 3:b4047e8a0123 82 dh_out->options[0] = PICO_DHCPOPT_MSGTYPE;
daniele 3:b4047e8a0123 83 dh_out->options[1] = 1;
daniele 3:b4047e8a0123 84 dh_out->options[2] = reply_type;
daniele 3:b4047e8a0123 85
daniele 3:b4047e8a0123 86 /* Option: server id, len 4 */
daniele 3:b4047e8a0123 87 dh_out->options[3] = PICO_DHCPOPT_SERVERID;
daniele 3:b4047e8a0123 88 dh_out->options[4] = 4;
daniele 3:b4047e8a0123 89 memcpy(dh_out->options + 5, &dn->settings->my_ip.addr, 4);
daniele 3:b4047e8a0123 90
daniele 3:b4047e8a0123 91 /* Option: Lease time, len 4 */
daniele 3:b4047e8a0123 92 dh_out->options[9] = PICO_DHCPOPT_LEASETIME;
daniele 3:b4047e8a0123 93 dh_out->options[10] = 4;
daniele 3:b4047e8a0123 94 memcpy(dh_out->options + 11, &dn->settings->lease_time, 4);
daniele 3:b4047e8a0123 95
daniele 3:b4047e8a0123 96 /* Option: Netmask, len 4 */
daniele 3:b4047e8a0123 97 dh_out->options[15] = PICO_DHCPOPT_NETMASK;
daniele 3:b4047e8a0123 98 dh_out->options[16] = 4;
daniele 3:b4047e8a0123 99 memcpy(dh_out->options + 17, &dn->settings->netmask.addr, 4);
daniele 3:b4047e8a0123 100
daniele 3:b4047e8a0123 101 /* Option: Router, len 4 */
daniele 3:b4047e8a0123 102 dh_out->options[21] = PICO_DHCPOPT_ROUTER;
daniele 3:b4047e8a0123 103 dh_out->options[22] = 4;
daniele 3:b4047e8a0123 104 memcpy(dh_out->options + 23, &dn->settings->my_ip.addr, 4);
daniele 3:b4047e8a0123 105
daniele 3:b4047e8a0123 106 /* Option: Broadcast, len 4 */
daniele 3:b4047e8a0123 107 dh_out->options[27] = PICO_DHCPOPT_BCAST;
daniele 3:b4047e8a0123 108 dh_out->options[28] = 4;
daniele 3:b4047e8a0123 109 memcpy(dh_out->options + 29, &bcast, 4);
daniele 3:b4047e8a0123 110
daniele 3:b4047e8a0123 111 /* Option: DNS, len 4 */
daniele 3:b4047e8a0123 112 dh_out->options[33] = PICO_DHCPOPT_DNS;
daniele 3:b4047e8a0123 113 dh_out->options[34] = 4;
daniele 3:b4047e8a0123 114 memcpy(dh_out->options + 35, &dns_server, 4);
daniele 3:b4047e8a0123 115
daniele 3:b4047e8a0123 116 dh_out->options[40] = PICO_DHCPOPT_END;
daniele 3:b4047e8a0123 117
daniele 3:b4047e8a0123 118 destination.addr = dh_out->yiaddr;
daniele 3:b4047e8a0123 119
daniele 3:b4047e8a0123 120 sent = pico_socket_sendto(dn->settings->s, buf_out, DHCPD_DATAGRAM_SIZE, &destination, port);
daniele 3:b4047e8a0123 121 if (sent < 0) {
daniele 3:b4047e8a0123 122 dhcpd_dbg("DHCPD: sendto failed with code %d!\n", pico_err);
daniele 3:b4047e8a0123 123 }
daniele 3:b4047e8a0123 124 }
daniele 3:b4047e8a0123 125
daniele 3:b4047e8a0123 126 static void dhcp_recv(struct pico_socket *s, uint8_t *buffer, int len)
daniele 3:b4047e8a0123 127 {
daniele 3:b4047e8a0123 128 struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) buffer;
daniele 3:b4047e8a0123 129 struct pico_dhcp_negotiation *dn = get_negotiation_by_xid(dhdr->xid);
daniele 3:b4047e8a0123 130 struct pico_ip4* ipv4 = NULL;
daniele 3:b4047e8a0123 131 struct pico_dhcpd_settings test, *settings = NULL;
daniele 3:b4047e8a0123 132 uint8_t *nextopt, opt_data[20], opt_type;
daniele 3:b4047e8a0123 133 int opt_len = 20;
daniele 3:b4047e8a0123 134
daniele 3:b4047e8a0123 135 if (!is_options_valid(dhdr->options, len - sizeof(struct pico_dhcphdr))) {
daniele 3:b4047e8a0123 136 dhcpd_dbg("DHCPD WARNING: invalid options in dhcp message\n");
daniele 3:b4047e8a0123 137 return;
daniele 3:b4047e8a0123 138 }
daniele 3:b4047e8a0123 139
daniele 3:b4047e8a0123 140 if (!dn) {
daniele 3:b4047e8a0123 141 dn = pico_zalloc(sizeof(struct pico_dhcp_negotiation));
daniele 3:b4047e8a0123 142 if (!dn) {
daniele 3:b4047e8a0123 143 pico_err = PICO_ERR_ENOMEM;
daniele 3:b4047e8a0123 144 return;
daniele 3:b4047e8a0123 145 }
daniele 3:b4047e8a0123 146 dn->xid = dhdr->xid;
daniele 3:b4047e8a0123 147 dn->state = DHCPSTATE_DISCOVER;
daniele 3:b4047e8a0123 148 memcpy(dn->eth.addr, dhdr->hwaddr, PICO_HLEN_ETHER);
daniele 3:b4047e8a0123 149
daniele 3:b4047e8a0123 150 test.dev = pico_ipv4_link_find(&s->local_addr.ip4);
daniele 3:b4047e8a0123 151 settings = pico_tree_findKey(&DHCPSettings, &test);
daniele 3:b4047e8a0123 152 if (settings) {
daniele 3:b4047e8a0123 153 dn->settings = settings;
daniele 3:b4047e8a0123 154 } else {
daniele 3:b4047e8a0123 155 dhcpd_dbg("DHCPD WARNING: received DHCP message on unconfigured link %s\n", test.dev->name);
daniele 3:b4047e8a0123 156 pico_free(dn);
daniele 3:b4047e8a0123 157 return;
daniele 3:b4047e8a0123 158 }
daniele 3:b4047e8a0123 159
daniele 3:b4047e8a0123 160 ipv4 = pico_arp_reverse_lookup(&dn->eth);
daniele 3:b4047e8a0123 161 if (!ipv4) {
daniele 3:b4047e8a0123 162 dn->ipv4.addr = settings->pool_next;
daniele 3:b4047e8a0123 163 pico_arp_create_entry(dn->eth.addr, dn->ipv4, settings->dev);
daniele 3:b4047e8a0123 164 settings->pool_next = long_be(long_be(settings->pool_next) + 1);
daniele 3:b4047e8a0123 165 } else {
daniele 3:b4047e8a0123 166 dn->ipv4.addr = ipv4->addr;
daniele 3:b4047e8a0123 167 }
daniele 3:b4047e8a0123 168
daniele 3:b4047e8a0123 169 if (pico_tree_insert(&DHCPNegotiations, dn)) {
daniele 3:b4047e8a0123 170 dhcpd_dbg("DHCPD WARNING: tried creating new negotation for existing xid %u\n", dn->xid);
daniele 3:b4047e8a0123 171 pico_free(dn);
daniele 3:b4047e8a0123 172 return; /* Element key already exists */
daniele 3:b4047e8a0123 173 }
daniele 3:b4047e8a0123 174 }
daniele 3:b4047e8a0123 175
daniele 3:b4047e8a0123 176 if (!ip_inrange(dn->ipv4.addr))
daniele 3:b4047e8a0123 177 return;
daniele 3:b4047e8a0123 178
daniele 3:b4047e8a0123 179 opt_type = dhcp_get_next_option(dhdr->options, opt_data, &opt_len, &nextopt);
daniele 3:b4047e8a0123 180 while (opt_type != PICO_DHCPOPT_END) {
daniele 3:b4047e8a0123 181 /* parse interesting options here */
daniele 3:b4047e8a0123 182 if (opt_type == PICO_DHCPOPT_MSGTYPE) {
daniele 3:b4047e8a0123 183 /* server simple state machine */
daniele 3:b4047e8a0123 184 uint8_t msg_type = opt_data[0];
daniele 3:b4047e8a0123 185 if (msg_type == PICO_DHCP_MSG_DISCOVER) {
daniele 3:b4047e8a0123 186 dhcpd_make_offer(dn);
daniele 3:b4047e8a0123 187 dn->state = DHCPSTATE_OFFER;
daniele 3:b4047e8a0123 188 return;
daniele 3:b4047e8a0123 189 } else if ((msg_type == PICO_DHCP_MSG_REQUEST)&&( dn->state == DHCPSTATE_OFFER)) {
daniele 3:b4047e8a0123 190 dhcpd_make_ack(dn);
daniele 3:b4047e8a0123 191 dn->state = DHCPSTATE_BOUND;
daniele 3:b4047e8a0123 192 return;
daniele 3:b4047e8a0123 193 }
daniele 3:b4047e8a0123 194 }
daniele 3:b4047e8a0123 195 opt_len = 20;
daniele 3:b4047e8a0123 196 opt_type = dhcp_get_next_option(NULL, opt_data, &opt_len, &nextopt);
daniele 3:b4047e8a0123 197 }
daniele 3:b4047e8a0123 198 }
daniele 3:b4047e8a0123 199
daniele 3:b4047e8a0123 200 static void pico_dhcpd_wakeup(uint16_t ev, struct pico_socket *s)
daniele 3:b4047e8a0123 201 {
daniele 3:b4047e8a0123 202 uint8_t buf[DHCPD_DATAGRAM_SIZE] = { };
daniele 3:b4047e8a0123 203 int r = 0;
daniele 3:b4047e8a0123 204 uint32_t peer = 0;
daniele 3:b4047e8a0123 205 uint16_t port = 0;
daniele 3:b4047e8a0123 206
daniele 3:b4047e8a0123 207 dhcpd_dbg("DHCPD: called dhcpd_wakeup\n");
daniele 3:b4047e8a0123 208 if (ev == PICO_SOCK_EV_RD) {
daniele 3:b4047e8a0123 209 do {
daniele 3:b4047e8a0123 210 r = pico_socket_recvfrom(s, buf, DHCPD_DATAGRAM_SIZE, &peer, &port);
daniele 3:b4047e8a0123 211 if (r > 0 && port == PICO_DHCP_CLIENT_PORT) {
daniele 3:b4047e8a0123 212 dhcp_recv(s, buf, r);
daniele 3:b4047e8a0123 213 }
daniele 3:b4047e8a0123 214 } while(r>0);
daniele 3:b4047e8a0123 215 }
daniele 3:b4047e8a0123 216 }
daniele 3:b4047e8a0123 217
daniele 3:b4047e8a0123 218 int pico_dhcp_server_initiate(struct pico_dhcpd_settings *setting)
daniele 3:b4047e8a0123 219 {
daniele 3:b4047e8a0123 220 struct pico_dhcpd_settings *settings = NULL;
daniele 3:b4047e8a0123 221 struct pico_ipv4_link *link = NULL;
daniele 3:b4047e8a0123 222 uint16_t port = PICO_DHCPD_PORT;
daniele 3:b4047e8a0123 223
daniele 3:b4047e8a0123 224 if (!setting) {
daniele 3:b4047e8a0123 225 pico_err = PICO_ERR_EINVAL;
daniele 3:b4047e8a0123 226 return -1;
daniele 3:b4047e8a0123 227 }
daniele 3:b4047e8a0123 228
daniele 3:b4047e8a0123 229 if (!setting->my_ip.addr) {
daniele 3:b4047e8a0123 230 pico_err = PICO_ERR_EINVAL;
daniele 3:b4047e8a0123 231 dhcpd_dbg("DHCPD: IP address of interface was not supplied\n");
daniele 3:b4047e8a0123 232 return -1;
daniele 3:b4047e8a0123 233 }
daniele 3:b4047e8a0123 234
daniele 3:b4047e8a0123 235 link = pico_ipv4_link_get(&setting->my_ip);
daniele 3:b4047e8a0123 236 if (!link) {
daniele 3:b4047e8a0123 237 pico_err = PICO_ERR_EINVAL;
daniele 3:b4047e8a0123 238 dhcpd_dbg("DHCPD: no link with IP %X found\n", setting->my_ip.addr);
daniele 3:b4047e8a0123 239 return -1;
daniele 3:b4047e8a0123 240 }
daniele 3:b4047e8a0123 241
daniele 3:b4047e8a0123 242 settings = pico_zalloc(sizeof(struct pico_dhcpd_settings));
daniele 3:b4047e8a0123 243 if (!settings) {
daniele 3:b4047e8a0123 244 pico_err = PICO_ERR_ENOMEM;
daniele 3:b4047e8a0123 245 return -1;
daniele 3:b4047e8a0123 246 }
daniele 3:b4047e8a0123 247 memcpy(settings, setting, sizeof(struct pico_dhcpd_settings));
daniele 3:b4047e8a0123 248
daniele 3:b4047e8a0123 249 settings->dev = link->dev;
daniele 3:b4047e8a0123 250 dhcpd_dbg("DHCPD: configuring DHCP server for link %s\n", link->dev->name);
daniele 3:b4047e8a0123 251 settings->my_ip.addr = link->address.addr;
daniele 3:b4047e8a0123 252 dhcpd_dbg("DHCPD: using server addr %X\n", long_be(settings->my_ip.addr));
daniele 3:b4047e8a0123 253 settings->netmask.addr = link->netmask.addr;
daniele 3:b4047e8a0123 254 dhcpd_dbg("DHCPD: using netmask %X\n", long_be(settings->netmask.addr));
daniele 3:b4047e8a0123 255
daniele 3:b4047e8a0123 256 /* default values if not provided */
daniele 3:b4047e8a0123 257 if (settings->pool_start == 0)
daniele 3:b4047e8a0123 258 settings->pool_start = (settings->my_ip.addr & settings->netmask.addr) | POOL_START;
daniele 3:b4047e8a0123 259 dhcpd_dbg("DHCPD: using pool_start %X\n", long_be(settings->pool_start));
daniele 3:b4047e8a0123 260 if (settings->pool_end == 0)
daniele 3:b4047e8a0123 261 settings->pool_end = (settings->my_ip.addr & settings->netmask.addr) | POOL_END;
daniele 3:b4047e8a0123 262 dhcpd_dbg("DHCPD: using pool_end %x\n", long_be(settings->pool_end));
daniele 3:b4047e8a0123 263 if (settings->lease_time == 0)
daniele 3:b4047e8a0123 264 settings->lease_time = LEASE_TIME;
daniele 3:b4047e8a0123 265 dhcpd_dbg("DHCPD: using lease time %x\n", long_be(settings->lease_time));
daniele 3:b4047e8a0123 266 settings->pool_next = settings->pool_start;
daniele 3:b4047e8a0123 267
daniele 3:b4047e8a0123 268 settings->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcpd_wakeup);
daniele 3:b4047e8a0123 269 if (!settings->s) {
daniele 3:b4047e8a0123 270 dhcpd_dbg("DHCP: could not open client socket\n");
daniele 3:b4047e8a0123 271 pico_free(settings);
daniele 3:b4047e8a0123 272 return -1;
daniele 3:b4047e8a0123 273 }
daniele 3:b4047e8a0123 274 if (pico_socket_bind(settings->s, &settings->my_ip, &port) != 0) {
daniele 3:b4047e8a0123 275 dhcpd_dbg("DHCP: could not bind server socket (%s)\n", strerror(pico_err));
daniele 3:b4047e8a0123 276 pico_free(settings);
daniele 3:b4047e8a0123 277 return -1;
daniele 3:b4047e8a0123 278 }
daniele 3:b4047e8a0123 279
daniele 3:b4047e8a0123 280 if (pico_tree_insert(&DHCPSettings, settings)) {
daniele 3:b4047e8a0123 281 dhcpd_dbg("DHCPD ERROR: link %s already configured\n", link->dev->name);
daniele 3:b4047e8a0123 282 pico_err = PICO_ERR_EINVAL;
daniele 3:b4047e8a0123 283 pico_free(settings);
daniele 3:b4047e8a0123 284 return -1; /* Element key already exists */
daniele 3:b4047e8a0123 285 }
daniele 3:b4047e8a0123 286 dhcpd_dbg("DHCPD: configured DHCP server for link %s\n", link->dev->name);
daniele 3:b4047e8a0123 287
daniele 3:b4047e8a0123 288 return 0;
daniele 3:b4047e8a0123 289 }
daniele 3:b4047e8a0123 290 #endif /* PICO_SUPPORT_DHCP */