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