Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dhcp_service_api.c Source File

dhcp_service_api.c

00001 /*
00002  * Copyright (c) 2013-2018, Arm Limited and affiliates.
00003  * SPDX-License-Identifier: Apache-2.0
00004  *
00005  * Licensed under the Apache License, Version 2.0 (the "License");
00006  * you may not use this file except in compliance with the License.
00007  * You may obtain a copy of the License at
00008  *
00009  *     http://www.apache.org/licenses/LICENSE-2.0
00010  *
00011  * Unless required by applicable law or agreed to in writing, software
00012  * distributed under the License is distributed on an "AS IS" BASIS,
00013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00014  * See the License for the specific language governing permissions and
00015  * limitations under the License.
00016  */
00017 
00018 #include "nsconfig.h"
00019 
00020 #include <string.h>
00021 #include <ns_types.h>
00022 #include <ns_trace.h>
00023 #include "eventOS_event.h"
00024 #include "eventOS_scheduler.h"
00025 #include "eventOS_event_timer.h"
00026 #include "nsdynmemLIB.h"
00027 #include "ns_list.h"
00028 #include "randLIB.h"
00029 #include "socket_api.h"
00030 #include "net_interface.h"
00031 #include "common_functions.h"
00032 #include "libDHCPv6/libDHCPv6.h"
00033 #include "NWK_INTERFACE/Include/protocol.h" // just for protocol_core_monotonic_time
00034 
00035 #include "dhcp_service_api.h"
00036 #ifdef HAVE_DHCPV6
00037 #define TRACE_GROUP    "dhcp"
00038 
00039 #define MAX_SERVERS 20
00040 
00041 /* Fixed-point randomisation limits for randlib_randomise_base() - RFC 3315
00042  * says RAND is uniformly distributed between -0.1 and +0.1
00043  */
00044 #define RAND1_LOW   0x7333 // 1 - 0.1; minimum for "1+RAND"
00045 #define RAND1_HIGH  0x8CCD // 1 + 0.1; maximum for "1+RAND"
00046 
00047 typedef struct {
00048     dhcp_service_receive_req_cb *recv_req_cb;
00049     uint16_t instance_id;
00050     int8_t interface_id;
00051     dhcp_instance_type_e instance_type;
00052     ns_list_link_t link;
00053 } server_instance_t;
00054 typedef NS_LIST_HEAD (server_instance_t, link) server_instance_list_t;
00055 
00056 
00057 typedef struct {
00058     uint16_t instance_id;
00059     int8_t interface_id;
00060     uint8_t server_address[16];
00061     bool    relay_activated;
00062     ns_list_link_t link;
00063 } relay_instance_t;
00064 typedef NS_LIST_HEAD (relay_instance_t, link) relay_instance_list_t;
00065 
00066 typedef struct {
00067     ns_address_t addr;
00068     dhcp_service_receive_resp_cb *recv_resp_cb;
00069     uint16_t instance_id;
00070     int8_t interface_id;
00071     int8_t socket;
00072     uint8_t options;
00073     void  *client_obj_ptr;
00074     uint32_t msg_tr_id;
00075     uint32_t message_tr_id;
00076     uint32_t first_transmit_time;
00077     uint16_t timeout;
00078     uint16_t timeout_init;
00079     uint16_t timeout_max;
00080     uint8_t retrans_max;
00081     uint8_t retrans;
00082     uint8_t *msg_ptr;
00083     uint16_t msg_len;
00084     uint8_t *relay_start;
00085     ns_list_link_t link;
00086 } msg_tr_t;
00087 typedef NS_LIST_HEAD (msg_tr_t, link) tr_list_t;
00088 
00089 typedef struct {
00090     ns_address_t src_address;
00091     server_instance_list_t srv_list;
00092     relay_instance_list_t relay_list;
00093     tr_list_t tr_list;
00094     int8_t dhcp_server_socket;
00095     int8_t dhcp_client_socket;
00096     int8_t dhcp_relay_socket;
00097     int8_t dhcpv6_socket_service_tasklet;
00098 } dhcp_service_class_t;
00099 
00100 #define DHCPV6_SOCKET_SERVICE_TASKLET_INIT      1
00101 #define DHCPV6_SOCKET_SERVICE_TIMER             2
00102 
00103 #define DHCPV6_SOCKET_SERVICE_TIMER_ID          1
00104 
00105 #define DHCPV6_SOCKET_TIMER_UPDATE_PERIOD_IN_MS 100
00106 
00107 dhcp_service_class_t *dhcp_service = NULL;
00108 static bool dhcpv6_socket_timeout_timer_active = false;
00109 
00110 void dhcp_service_send_message(msg_tr_t *msg_tr_ptr);
00111 
00112 void DHCPv6_socket_service_tasklet(arm_event_s *event)
00113 {
00114     if (event->event_type == DHCPV6_SOCKET_SERVICE_TASKLET_INIT) {
00115         //We should define peridiocally timer service!!
00116         eventOS_event_timer_request(DHCPV6_SOCKET_SERVICE_TIMER_ID, DHCPV6_SOCKET_SERVICE_TIMER, dhcp_service->dhcpv6_socket_service_tasklet, DHCPV6_SOCKET_TIMER_UPDATE_PERIOD_IN_MS);
00117         dhcpv6_socket_timeout_timer_active = true;
00118     } else if (event->event_type == DHCPV6_SOCKET_SERVICE_TIMER) {
00119 
00120         if (dhcp_service_timer_tick(1)) {
00121             dhcpv6_socket_timeout_timer_active = true;
00122             eventOS_event_timer_request(DHCPV6_SOCKET_SERVICE_TIMER_ID, DHCPV6_SOCKET_SERVICE_TIMER, dhcp_service->dhcpv6_socket_service_tasklet, DHCPV6_SOCKET_TIMER_UPDATE_PERIOD_IN_MS);
00123         } else {
00124             dhcpv6_socket_timeout_timer_active = false;
00125         }
00126     }
00127 }
00128 
00129 bool dhcp_service_allocate(void)
00130 {
00131     bool retVal = false;
00132     if (dhcp_service == NULL) {
00133         dhcp_service = ns_dyn_mem_alloc(sizeof(dhcp_service_class_t));
00134         if (dhcp_service) {
00135             ns_list_init(&dhcp_service->srv_list);
00136             ns_list_init(&dhcp_service->relay_list);
00137             ns_list_init(&dhcp_service->tr_list);
00138             dhcp_service->dhcp_client_socket = -1;
00139             dhcp_service->dhcp_server_socket = -1;
00140             dhcp_service->dhcp_relay_socket = -1;
00141             dhcp_service->dhcpv6_socket_service_tasklet = eventOS_event_handler_create(DHCPv6_socket_service_tasklet, DHCPV6_SOCKET_SERVICE_TASKLET_INIT);
00142             if (dhcp_service->dhcpv6_socket_service_tasklet < 0) {
00143                 ns_dyn_mem_free(dhcp_service);
00144                 dhcp_service = NULL;
00145             } else {
00146                 retVal = true;
00147             }
00148         }
00149     } else {
00150         retVal = true;
00151     }
00152     return retVal;
00153 }
00154 
00155 /*Subclass instances*/
00156 msg_tr_t *dhcp_tr_find(uint32_t msg_tr_id)
00157 {
00158     msg_tr_t *result = NULL;
00159     ns_list_foreach(msg_tr_t, cur_ptr, &dhcp_service->tr_list) {
00160         if (cur_ptr->msg_tr_id == msg_tr_id) {
00161             result = cur_ptr;
00162         }
00163     }
00164     return result;
00165 }
00166 
00167 
00168 msg_tr_t *dhcp_tr_create(void)
00169 {
00170     uint32_t tr_id;
00171     msg_tr_t *msg_ptr = NULL;
00172     msg_ptr = ns_dyn_mem_temporary_alloc(sizeof(msg_tr_t));
00173     if (msg_ptr == NULL) {
00174         return NULL;
00175     }
00176 
00177     memset(msg_ptr, 0, sizeof(msg_tr_t));
00178     msg_ptr->msg_ptr = NULL;
00179     msg_ptr->recv_resp_cb = NULL;
00180 
00181     tr_id = randLIB_get_32bit() & 0xffffff;// 24 bits for random
00182     // Ensure a unique non-zero transaction id for each transaction
00183     while (tr_id == 0 || dhcp_tr_find(tr_id) != NULL) {
00184         tr_id = (tr_id + 1) & 0xffffff;
00185     }
00186     msg_ptr->msg_tr_id = tr_id;
00187     ns_list_add_to_start(&dhcp_service->tr_list, msg_ptr);
00188     return msg_ptr;
00189 }
00190 
00191 void dhcp_tr_delete(msg_tr_t *msg_ptr)
00192 {
00193     if (msg_ptr != NULL) {
00194         ns_list_remove(&dhcp_service->tr_list, msg_ptr);
00195         ns_dyn_mem_free(msg_ptr->msg_ptr);
00196         ns_dyn_mem_free(msg_ptr);
00197     }
00198     return;
00199 }
00200 
00201 void dhcp_tr_set_retry_timers(msg_tr_t *msg_ptr, uint8_t msg_type)
00202 {
00203     if (msg_ptr != NULL) {
00204         if (msg_type == DHCPV6_SOLICATION_TYPE) {
00205             msg_ptr->timeout_init = SOL_TIMEOUT;
00206             msg_ptr->timeout_max = SOL_MAX_RT;
00207             msg_ptr->retrans_max = 0;
00208         } else if (msg_type == DHCPV6_RENEW_TYPE) {
00209             msg_ptr->timeout_init = REN_TIMEOUT;
00210             msg_ptr->timeout_max = REN_MAX_RT;
00211             msg_ptr->retrans_max = 0;
00212         } else if (msg_type == DHCPV6_LEASEQUERY_TYPE) {
00213             msg_ptr->timeout_init = LQ_TIMEOUT;
00214             msg_ptr->timeout_max = LQ_MAX_RT;
00215             msg_ptr->retrans_max = LQ_MAX_RC;
00216         } else {
00217             msg_ptr->timeout_init = REL_TIMEOUT;
00218             msg_ptr->timeout_max = 0;
00219             msg_ptr->retrans_max = REL_MAX_RC;
00220         }
00221 
00222         // Convert from seconds to 1/10s ticks, with initial randomisation factor
00223         msg_ptr->timeout_init = randLIB_randomise_base(msg_ptr->timeout_init * 10, RAND1_LOW, RAND1_HIGH);
00224         msg_ptr->timeout_max *= 10;
00225 
00226         msg_ptr->timeout = msg_ptr->timeout_init;
00227         if (!dhcpv6_socket_timeout_timer_active) {
00228             eventOS_event_timer_request(DHCPV6_SOCKET_SERVICE_TIMER_ID, DHCPV6_SOCKET_SERVICE_TIMER, dhcp_service->dhcpv6_socket_service_tasklet, DHCPV6_SOCKET_TIMER_UPDATE_PERIOD_IN_MS);
00229             dhcpv6_socket_timeout_timer_active = true;
00230         }
00231     }
00232     return;
00233 }
00234 
00235 server_instance_t *dhcp_service_client_find(uint16_t instance_id)
00236 {
00237     server_instance_t *result = NULL;
00238     ns_list_foreach(server_instance_t, cur_ptr, &dhcp_service->srv_list) {
00239         if (cur_ptr->instance_id == instance_id) {
00240             result = cur_ptr;
00241         }
00242     }
00243     return result;
00244 }
00245 
00246 
00247 static uint16_t dhcp_service_relay_interface_get(int8_t  interface_id)
00248 {
00249     ns_list_foreach(server_instance_t, cur_ptr, &dhcp_service->srv_list) {
00250         if (cur_ptr->interface_id == interface_id && cur_ptr->instance_type == DHCP_INTANCE_RELAY_AGENT) {
00251             return cur_ptr->instance_id;
00252         }
00253     }
00254 
00255     return 0;
00256 }
00257 
00258 
00259 
00260 static relay_instance_t *dhcp_service_relay_find(uint16_t instance_id)
00261 {
00262     relay_instance_t *result = NULL;
00263     ns_list_foreach(relay_instance_t, cur_ptr, &dhcp_service->relay_list) {
00264         if (cur_ptr->instance_id == instance_id) {
00265             result = cur_ptr;
00266         }
00267     }
00268     return result;
00269 }
00270 
00271 static relay_instance_t *dhcp_service_relay_interface(int8_t  interface_id)
00272 {
00273     relay_instance_t *result = NULL;
00274     ns_list_foreach(relay_instance_t, cur_ptr, &dhcp_service->relay_list) {
00275         if (cur_ptr->interface_id == interface_id) {
00276             result = cur_ptr;
00277         }
00278     }
00279     return result;
00280 }
00281 
00282 
00283 void recv_dhcp_server_msg(void *cb_res)
00284 {
00285     socket_callback_t *sckt_data;
00286     server_instance_t *srv_ptr = NULL;
00287     msg_tr_t *msg_tr_ptr;
00288     uint8_t *msg_ptr, *allocated_ptr;
00289     uint16_t msg_len;
00290     dhcpv6_relay_msg_t relay_msg;
00291 
00292     sckt_data = cb_res;
00293 
00294     if (sckt_data->event_type != SOCKET_DATA || sckt_data->d_len < 4) {
00295         return;
00296     }
00297     tr_debug("dhcp Server recv request");
00298     msg_tr_ptr = dhcp_tr_create();
00299     msg_ptr = ns_dyn_mem_temporary_alloc(sckt_data->d_len);
00300     allocated_ptr = msg_ptr;
00301     if (msg_ptr == NULL || msg_tr_ptr == NULL) {
00302         // read actual message
00303         tr_error("Out of resources");
00304         goto cleanup;
00305     }
00306     msg_len = socket_read(sckt_data->socket_id, &msg_tr_ptr->addr, msg_ptr, sckt_data->d_len);
00307 
00308     uint8_t msg_type = *msg_ptr;
00309     if (msg_type == DHCPV6_RELAY_FORWARD) {
00310         if (!libdhcpv6_relay_msg_read(msg_ptr, msg_len, &relay_msg)) {
00311             tr_error("Relay forward not correct");
00312             goto cleanup;
00313         }
00314         //Update Source and data
00315         msg_tr_ptr->relay_start = msg_ptr;
00316         memcpy(msg_tr_ptr->addr.address, relay_msg.peer_address, 16);
00317         msg_ptr = relay_msg.relay_options.msg_ptr;
00318         msg_len = relay_msg.relay_options.len;
00319         msg_type = *msg_ptr;
00320 
00321 
00322     } else if (msg_type == DHCPV6_RELAY_REPLY) {
00323         tr_error("Relay reply drop at server");
00324         goto cleanup;
00325     }
00326 
00327     //TODO use real function from lib also call validity check
00328     msg_tr_ptr->message_tr_id = common_read_24_bit(&msg_ptr[1]);
00329 
00330     if (0 != libdhcpv6_message_malformed_check(msg_ptr, msg_len)) {
00331         tr_error("Malformed packet");
00332         goto cleanup;
00333     }
00334     msg_tr_ptr->socket = sckt_data->socket_id;
00335     // call all receivers until found.
00336     ns_list_foreach(server_instance_t, cur_ptr, &dhcp_service->srv_list) {
00337         if (cur_ptr->interface_id == sckt_data->interface_id && cur_ptr->recv_req_cb != NULL) {
00338             msg_tr_ptr->instance_id = cur_ptr->instance_id;
00339             msg_tr_ptr->interface_id = sckt_data->interface_id;
00340             if ((RET_MSG_ACCEPTED ==
00341                     cur_ptr->recv_req_cb(cur_ptr->instance_id, msg_tr_ptr->msg_tr_id, msg_type, msg_ptr + 4, msg_len - 4))) {
00342                 // should not modify pointers but library requires.
00343                 msg_tr_ptr = NULL;
00344                 srv_ptr = cur_ptr;
00345                 break;
00346             }
00347         }
00348     }
00349 
00350 cleanup:
00351     dhcp_tr_delete(msg_tr_ptr);
00352     ns_dyn_mem_free(allocated_ptr);
00353     if (srv_ptr == NULL) {
00354         //no owner found
00355         tr_warn("No handler for this message found");
00356     }
00357 
00358     return;
00359 }
00360 
00361 void recv_dhcp_relay_msg(void *cb_res)
00362 {
00363     socket_callback_t *sckt_data;
00364     uint16_t msg_len;
00365 
00366     sckt_data = cb_res;
00367 
00368     if (sckt_data->event_type != SOCKET_DATA || sckt_data->d_len < 4) {
00369         return;
00370     }
00371 
00372     protocol_interface_info_entry_t *interface_ptr = protocol_stack_interface_info_get_by_id(sckt_data->interface_id);
00373 
00374     relay_instance_t *relay_srv = dhcp_service_relay_interface(sckt_data->interface_id);
00375 
00376     if (!interface_ptr || !relay_srv || !relay_srv->relay_activated) {
00377         return;
00378     }
00379     ns_address_t src_address;
00380 
00381     uint8_t relay_frame[DHCPV6_RELAY_LENGTH + 4];
00382     ns_iovec_t msg_iov[2];
00383     msg_iov[0].iov_base = relay_frame;
00384     msg_iov[0].iov_len = 34;
00385     msg_iov[1].iov_base = ns_dyn_mem_temporary_alloc(sckt_data->d_len);
00386     msg_iov[1].iov_len = sckt_data->d_len;
00387     if (msg_iov[1].iov_base == NULL) {
00388         // read actual message
00389         tr_error("Out of resources");
00390         goto cleanup;
00391     }
00392 
00393     ns_msghdr_t msghdr;
00394     //Set messages name buffer
00395     msghdr.msg_name = &src_address;
00396     msghdr.msg_namelen = sizeof(src_address);
00397     msghdr.msg_iov = &msg_iov[1];
00398     msghdr.msg_iovlen = 1;
00399     msghdr.msg_control = NULL;
00400     msghdr.msg_controllen = 0;
00401 
00402     msg_len = socket_recvmsg(sckt_data->socket_id, &msghdr, NS_MSG_LEGACY0);
00403 
00404 
00405     tr_debug("dhcp Relay recv msg");
00406 
00407     //Parse type
00408     uint8_t *ptr = msg_iov[1].iov_base;
00409     uint8_t msg_type = *ptr;
00410 
00411 
00412     if (msg_type == DHCPV6_RELAY_FORWARD) {
00413         tr_error("Drop not supported DHCPv6 forward at Agent");
00414         goto cleanup;
00415 
00416     } else if (msg_type == DHCPV6_RELAY_REPLY) {
00417         //Parse and validate Relay
00418         dhcpv6_relay_msg_t relay_msg;
00419         if (!libdhcpv6_relay_msg_read(ptr, msg_len, &relay_msg)) {
00420             tr_error("Not valid relay");
00421             goto cleanup;
00422         }
00423         if (0 != libdhcpv6_message_malformed_check(relay_msg.relay_options.msg_ptr, relay_msg.relay_options.len)) {
00424             tr_error("Malformed packet");
00425             goto cleanup;
00426         }
00427         //Copy DST address
00428         memcpy(src_address.address, relay_msg.peer_address, 16);
00429         src_address.type = ADDRESS_IPV6;
00430         src_address.identifier = DHCPV6_CLIENT_PORT;
00431         msghdr.msg_iov = &msg_iov[0];
00432         msghdr.msg_iovlen = 1;
00433         msg_iov[0].iov_base = relay_msg.relay_options.msg_ptr;
00434         msg_iov[0].iov_len = relay_msg.relay_options.len;
00435         tr_debug("Forward Original relay msg to client");
00436 
00437     } else {
00438         if (0 != libdhcpv6_message_malformed_check(ptr, msg_len)) {
00439             tr_error("Malformed packet");
00440             goto cleanup;
00441         }
00442         uint8_t gp_address[16];
00443         //Get blobal address from interface
00444         if (addr_interface_select_source(interface_ptr, gp_address, relay_srv->server_address, 0) != 0) {
00445             // No global prefix available
00446             tr_error("No GP address");
00447             goto cleanup;
00448         }
00449 
00450         //Build
00451         libdhcpv6_dhcp_relay_msg_write(relay_frame, DHCPV6_RELAY_FORWARD, 0, src_address.address, gp_address);
00452         libdhcpv6_dhcp_option_header_write(relay_frame + 34, msg_len);
00453 
00454         //Copy DST address
00455         memcpy(src_address.address, relay_srv->server_address, 16);
00456         src_address.type = ADDRESS_IPV6;
00457         src_address.identifier = DHCPV6_SERVER_PORT;
00458         //ADD relay frame vector front of original data
00459         msghdr.msg_iov = &msg_iov[0];
00460         msghdr.msg_iovlen = 2;
00461         msg_iov[0].iov_base = relay_frame;
00462         msg_iov[0].iov_len = 38;
00463         msg_iov[1].iov_len = msg_len;
00464         tr_debug("Forward Client msg to server");
00465     }
00466     socket_sendmsg(sckt_data->socket_id, &msghdr, NS_MSG_LEGACY0);
00467 cleanup:
00468     ns_dyn_mem_free(msg_iov[1].iov_base);
00469 
00470     return;
00471 }
00472 
00473 void recv_dhcp_client_msg(void *cb_res)
00474 {
00475     ns_address_t address;
00476     socket_callback_t *sckt_data;
00477     msg_tr_t *msg_tr_ptr = NULL;
00478     uint8_t *msg_ptr = NULL;
00479     int16_t msg_len = 0;
00480     uint_fast24_t tr_id = 0;
00481     int retVal = RET_MSG_ACCEPTED;
00482 
00483     sckt_data = cb_res;
00484 
00485     if (sckt_data->event_type != SOCKET_DATA || sckt_data->d_len < 4) {
00486         return;
00487     }
00488     tr_debug("dhcp recv response message");
00489     // read actual message
00490     msg_ptr = ns_dyn_mem_temporary_alloc(sckt_data->d_len);
00491 
00492     if (msg_ptr == NULL) {
00493         tr_error("Out of memory");
00494         goto cleanup;
00495     }
00496     msg_len = socket_read(sckt_data->socket_id, &address, msg_ptr, sckt_data->d_len);
00497 
00498     tr_id = common_read_24_bit(&msg_ptr[1]);
00499     msg_tr_ptr = dhcp_tr_find(tr_id);
00500 
00501     if (msg_tr_ptr == NULL) {
00502         tr_error("invalid tr id");
00503         goto cleanup;
00504     }
00505     if (0 != libdhcpv6_message_malformed_check(msg_ptr, msg_len)) {
00506         msg_tr_ptr->recv_resp_cb(msg_tr_ptr->instance_id, msg_tr_ptr->client_obj_ptr, 0, NULL, 0);
00507         tr_error("Malformed packet");
00508         goto cleanup;
00509     }
00510     // read msg tr id from message and find transaction. and then instance
00511     // TODO use real function from dhcp lib
00512 
00513     if (msg_tr_ptr != NULL && msg_tr_ptr->recv_resp_cb) {
00514         // call receive callback should not modify pointers but library requires
00515         retVal = msg_tr_ptr->recv_resp_cb(msg_tr_ptr->instance_id, msg_tr_ptr->client_obj_ptr, *msg_ptr, msg_ptr + 4, msg_len - 4);
00516     } else {
00517         tr_error("no receiver for this message found");
00518     }
00519 
00520 cleanup:
00521     ns_dyn_mem_free(msg_ptr);
00522     if (retVal != RET_MSG_WAIT_ANOTHER) {
00523         //Transaction is not killed yet
00524         dhcp_tr_delete(dhcp_tr_find(tr_id));
00525     }
00526     return ;
00527 }
00528 
00529 uint16_t dhcp_service_init(int8_t interface_id, dhcp_instance_type_e instance_type, dhcp_service_receive_req_cb *receive_req_cb)
00530 {
00531     uint16_t id = 1;
00532     server_instance_t *srv_ptr;
00533 
00534     if (!dhcp_service_allocate()) {
00535         tr_error("dhcp Sockets data base alloc fail");
00536         return 0;
00537     }
00538     if (instance_type == DHCP_INSTANCE_SERVER && dhcp_service->dhcp_server_socket < 0) {
00539         if (dhcp_service->dhcp_relay_socket >= 0) {
00540             tr_error("dhcp Server socket can't open because Agent open already");
00541         }
00542         dhcp_service->dhcp_server_socket = socket_open(SOCKET_UDP, DHCPV6_SERVER_PORT, recv_dhcp_server_msg);
00543     }
00544 
00545     if (instance_type == DHCP_INTANCE_RELAY_AGENT && dhcp_service->dhcp_relay_socket < 0) {
00546         if (dhcp_service->dhcp_server_socket >= 0) {
00547             tr_error("dhcp Relay agent can't open because server open already");
00548         }
00549         dhcp_service->dhcp_relay_socket = socket_open(SOCKET_UDP, DHCPV6_SERVER_PORT, recv_dhcp_relay_msg);
00550     }
00551 
00552     if (instance_type == DHCP_INSTANCE_CLIENT && dhcp_service->dhcp_client_socket < 0) {
00553         dhcp_service->dhcp_client_socket = socket_open(SOCKET_UDP, DHCPV6_CLIENT_PORT, recv_dhcp_client_msg);
00554     }
00555     if (instance_type == DHCP_INSTANCE_SERVER && dhcp_service->dhcp_server_socket < 0) {
00556         tr_error("No sockets available for DHCP server");
00557         return 0;
00558     }
00559     if (instance_type == DHCP_INSTANCE_CLIENT && dhcp_service->dhcp_client_socket < 0) {
00560         tr_error("No sockets available for DHCP client");
00561         return 0;
00562     }
00563 
00564     if (instance_type == DHCP_INTANCE_RELAY_AGENT) {
00565         if (dhcp_service->dhcp_relay_socket < 0) {
00566             tr_error("No sockets available for DHCP server");
00567         }
00568 
00569         uint16_t temp_id = dhcp_service_relay_interface_get(interface_id);
00570         if (temp_id) {
00571             return temp_id;
00572         }
00573     }
00574 
00575     for (; id < MAX_SERVERS; id++) {
00576         if (dhcp_service_client_find(id) == NULL) {
00577             break;
00578         }
00579     }
00580     srv_ptr = ns_dyn_mem_alloc(sizeof(server_instance_t));
00581     if (id == MAX_SERVERS || srv_ptr == NULL) {
00582         tr_error("Out of server instances");
00583         ns_dyn_mem_free(srv_ptr);
00584         return 0;
00585     }
00586 
00587     if (instance_type == DHCP_INTANCE_RELAY_AGENT) {
00588         //Allocate Realay Agent
00589         relay_instance_t *relay_srv = ns_dyn_mem_alloc(sizeof(relay_instance_t));
00590         if (!relay_srv) {
00591             tr_error("Out of realy instances");
00592             ns_dyn_mem_free(srv_ptr);
00593             return 0;
00594         }
00595         ns_list_add_to_start(&dhcp_service->relay_list, relay_srv);
00596         relay_srv->instance_id = id;
00597         relay_srv->interface_id = interface_id;
00598         relay_srv->relay_activated = false;
00599 
00600     }
00601 
00602     ns_list_add_to_start(&dhcp_service->srv_list, srv_ptr);
00603     srv_ptr->instance_id = id;
00604     srv_ptr->instance_type = instance_type;
00605     srv_ptr->interface_id = interface_id;
00606     srv_ptr->recv_req_cb = receive_req_cb;
00607     return srv_ptr->instance_id;
00608 }
00609 
00610 void dhcp_service_relay_instance_enable(uint16_t instance, uint8_t *server_address)
00611 {
00612     relay_instance_t *relay_srv = dhcp_service_relay_find(instance);
00613     if (relay_srv) {
00614         relay_srv->relay_activated = true;
00615         memcpy(relay_srv->server_address, server_address, 16);
00616     }
00617 }
00618 
00619 uint8_t *dhcp_service_relay_global_addres_get(uint16_t instance)
00620 {
00621     relay_instance_t *relay_srv = dhcp_service_relay_find(instance);
00622     if (!relay_srv || !relay_srv->relay_activated) {
00623         return NULL;
00624     }
00625 
00626     return relay_srv->server_address;
00627 }
00628 
00629 void dhcp_service_delete(uint16_t instance)
00630 {
00631     server_instance_t *srv_ptr;
00632     if (dhcp_service == NULL) {
00633         return;
00634     }
00635     srv_ptr = dhcp_service_client_find(instance);
00636     //TODO delete all transactions
00637     if (srv_ptr != NULL) {
00638         ns_list_remove(&dhcp_service->srv_list, srv_ptr);
00639         if (srv_ptr->instance_type == DHCP_INTANCE_RELAY_AGENT) {
00640             //Free relay service
00641             relay_instance_t *relay = dhcp_service_relay_find(instance);
00642             if (relay) {
00643                 ns_list_remove(&dhcp_service->relay_list, relay);
00644                 ns_dyn_mem_free(relay);
00645             }
00646         }
00647         ns_dyn_mem_free(srv_ptr);
00648 
00649     }
00650     ns_list_foreach_safe(msg_tr_t, cur_ptr, &dhcp_service->tr_list) {
00651         if (cur_ptr->instance_id == instance) {
00652             dhcp_tr_delete(cur_ptr);
00653         }
00654     }
00655 
00656     int8_t server_instances = 0, client_instances = 0, relay_instances = 0;
00657 
00658     ns_list_foreach(server_instance_t, srv, &dhcp_service->srv_list) {
00659         if (srv->instance_type == DHCP_INSTANCE_SERVER) {
00660             ++server_instances;
00661         } else if (srv->instance_type == DHCP_INSTANCE_CLIENT) {
00662             ++client_instances;
00663         } else if (srv->instance_type == DHCP_INTANCE_RELAY_AGENT) {
00664             ++relay_instances;
00665         }
00666     }
00667 
00668     if ((server_instances == 0 && relay_instances == 0) && dhcp_service->dhcp_server_socket > -1) {
00669         socket_close(dhcp_service->dhcp_server_socket);
00670         dhcp_service->dhcp_server_socket = -1;
00671     }
00672 
00673     if (client_instances == 0 && dhcp_service->dhcp_client_socket > -1) {
00674         socket_close(dhcp_service->dhcp_client_socket);
00675         dhcp_service->dhcp_client_socket = -1;
00676     }
00677     return;
00678 }
00679 
00680 int dhcp_service_send_resp(uint32_t msg_tr_id, uint8_t options, uint8_t *msg_ptr, uint16_t msg_len)
00681 {
00682     tr_debug("Send DHCPv6 response");
00683     msg_tr_t *msg_tr_ptr;
00684     server_instance_t *srv_instance;
00685     msg_tr_ptr = dhcp_tr_find(msg_tr_id);
00686     if (msg_tr_ptr == NULL) {
00687         tr_error("msg_tr_id not found");
00688         return -1;
00689     }
00690     srv_instance = dhcp_service_client_find(msg_tr_ptr->instance_id);
00691     if (srv_instance == NULL) {
00692         tr_error("Srv Instance not found");
00693         return -1;
00694     }
00695     ns_dyn_mem_free(msg_tr_ptr->msg_ptr);
00696 
00697     msg_tr_ptr->msg_ptr = msg_ptr;
00698     msg_tr_ptr->msg_len = msg_len;
00699     msg_tr_ptr->options = options;
00700     // set the received transaction id to message.
00701     common_write_24_bit(msg_tr_ptr->message_tr_id, &msg_tr_ptr->msg_ptr[1]);
00702 
00703     dhcp_service_send_message(msg_tr_ptr);
00704     msg_tr_ptr->msg_ptr = NULL; // pointer is the responsibility of client
00705     dhcp_tr_delete(msg_tr_ptr);
00706     return 0;
00707 }
00708 uint32_t dhcp_service_send_req(uint16_t instance_id, uint8_t options, void *ptr, const uint8_t addr[static 16], uint8_t *msg_ptr, uint16_t msg_len, dhcp_service_receive_resp_cb *receive_resp_cb)
00709 {
00710     tr_debug("Send DHCPv6 request");
00711     msg_tr_t *msg_tr_ptr;
00712     server_instance_t *srv_ptr;
00713     srv_ptr = dhcp_service_client_find(instance_id);
00714     msg_tr_ptr = dhcp_tr_create();
00715 
00716     if (msg_tr_ptr == NULL || srv_ptr == NULL || msg_ptr == NULL || receive_resp_cb == NULL || msg_len < 5) {
00717         tr_error("Request sending failed");
00718         return 0;
00719     }
00720 
00721     msg_tr_ptr->msg_ptr = msg_ptr;
00722     msg_tr_ptr->msg_len = msg_len;
00723     msg_tr_ptr->options = options;
00724     msg_tr_ptr->client_obj_ptr = ptr;
00725     memcpy(msg_tr_ptr->addr.address, addr, 16);
00726     msg_tr_ptr->addr.identifier = DHCPV6_SERVER_PORT;
00727     msg_tr_ptr->addr.type = ADDRESS_IPV6;
00728     msg_tr_ptr->interface_id = srv_ptr->interface_id;
00729     msg_tr_ptr->instance_id = instance_id;
00730     msg_tr_ptr->socket = dhcp_service->dhcp_client_socket;
00731     msg_tr_ptr->recv_resp_cb = receive_resp_cb;
00732     msg_tr_ptr->first_transmit_time = protocol_core_monotonic_time;
00733     dhcp_tr_set_retry_timers(msg_tr_ptr, msg_tr_ptr->msg_ptr[0]);
00734     common_write_24_bit(msg_tr_ptr->msg_tr_id, &msg_tr_ptr->msg_ptr[1]);
00735 
00736     dhcp_service_send_message(msg_tr_ptr);
00737     return msg_tr_ptr->msg_tr_id;
00738 }
00739 
00740 void dhcp_service_set_retry_timers(uint32_t msg_tr_id, uint16_t timeout_init, uint16_t timeout_max, uint8_t retrans_max)
00741 {
00742     msg_tr_t *msg_tr_ptr;
00743     msg_tr_ptr = dhcp_tr_find(msg_tr_id);
00744 
00745     if (msg_tr_ptr != NULL) {
00746         msg_tr_ptr->timeout_init = randLIB_randomise_base(timeout_init * 10, RAND1_LOW, RAND1_HIGH);
00747         msg_tr_ptr->timeout = msg_tr_ptr->timeout_init;
00748         msg_tr_ptr->timeout_max = timeout_max * 10;
00749         msg_tr_ptr->retrans_max = retrans_max;
00750     }
00751     return;
00752 }
00753 
00754 void dhcp_service_update_server_address(uint32_t msg_tr_id, uint8_t *server_address)
00755 {
00756     msg_tr_t *msg_tr_ptr;
00757     msg_tr_ptr = dhcp_tr_find(msg_tr_id);
00758 
00759     if (msg_tr_ptr != NULL) {
00760         memcpy(msg_tr_ptr->addr.address, server_address, 16);
00761     }
00762 }
00763 
00764 void dhcp_service_req_remove(uint32_t msg_tr_id)
00765 {
00766     if (dhcp_service) {
00767         dhcp_tr_delete(dhcp_tr_find(msg_tr_id));
00768     }
00769     return;
00770 }
00771 
00772 void dhcp_service_req_remove_all(void *msg_class_ptr)
00773 {
00774     if (dhcp_service) {
00775         ns_list_foreach_safe(msg_tr_t, cur_ptr, &dhcp_service->tr_list) {
00776             if (cur_ptr->client_obj_ptr == msg_class_ptr) {
00777                 dhcp_tr_delete(cur_ptr);
00778             }
00779         }
00780     }
00781 }
00782 
00783 void dhcp_service_send_message(msg_tr_t *msg_tr_ptr)
00784 {
00785     int8_t retval;
00786     int16_t multicast_hop_limit = -1;
00787     const uint32_t address_pref = SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT;
00788     dhcp_options_msg_t elapsed_time;
00789 
00790     if (libdhcpv6_message_option_discover((msg_tr_ptr->msg_ptr + 4), (msg_tr_ptr->msg_len - 4), DHCPV6_ELAPSED_TIME_OPTION, &elapsed_time) == 0 &&
00791             elapsed_time.len == 2) {
00792         uint32_t t = protocol_core_monotonic_time - msg_tr_ptr->first_transmit_time; // time in 1/10s ticks
00793         uint16_t cs;
00794         if (t > 0xffff / 10) {
00795             cs = 0xffff;
00796         } else {
00797             cs = (uint16_t) t * 10;
00798         }
00799         common_write_16_bit(cs, elapsed_time.msg_ptr);
00800     }
00801 
00802     if ((msg_tr_ptr->options & TX_OPT_USE_SHORT_ADDR) == TX_OPT_USE_SHORT_ADDR) {
00803         socket_setsockopt(msg_tr_ptr->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_ADDR_PREFERENCES, &address_pref, sizeof address_pref);
00804     }
00805     if ((msg_tr_ptr->options & TX_OPT_MULTICAST_HOP_LIMIT_64) == TX_OPT_MULTICAST_HOP_LIMIT_64) {
00806         multicast_hop_limit = 64;
00807     }
00808     socket_setsockopt(msg_tr_ptr->socket, SOCKET_IPPROTO_IPV6, SOCKET_IPV6_MULTICAST_HOPS, &multicast_hop_limit, sizeof multicast_hop_limit);
00809     socket_setsockopt(msg_tr_ptr->socket, SOCKET_IPPROTO_IPV6, SOCKET_INTERFACE_SELECT, &msg_tr_ptr->interface_id, sizeof(int8_t));
00810 
00811     if (msg_tr_ptr->relay_start) {
00812         //Build Relay Reply only server do this
00813         ns_iovec_t data_vector[2];
00814         ns_msghdr_t msghdr;
00815         memcpy(msg_tr_ptr->addr.address, msg_tr_ptr->relay_start + 2, 16);
00816         msg_tr_ptr->addr.identifier = DHCPV6_SERVER_PORT;
00817         //SET IOV vectors
00818         //Relay Reply
00819         data_vector[0].iov_base = (void *) msg_tr_ptr->relay_start;
00820         data_vector[0].iov_len = DHCPV6_RELAY_LENGTH + 4;
00821         //DHCPV normal message vector
00822         data_vector[1].iov_base = (void *) msg_tr_ptr->msg_ptr;
00823         data_vector[1].iov_len = msg_tr_ptr->msg_len;
00824 
00825         //Set message name
00826         msghdr.msg_name = (void *) &msg_tr_ptr->addr;
00827         msghdr.msg_namelen = sizeof(ns_address_t);
00828         msghdr.msg_iov = &data_vector[0];
00829         msghdr.msg_iovlen = 2;
00830         //No ancillary data
00831         msghdr.msg_control = NULL;
00832         msghdr.msg_controllen = 0;
00833 
00834         uint8_t *ptr = msg_tr_ptr->relay_start;
00835         *ptr = DHCPV6_RELAY_REPLY;
00836         libdhcpv6_dhcp_option_header_write(ptr + 34, msg_tr_ptr->msg_len);
00837         retval = socket_sendmsg(msg_tr_ptr->socket, &msghdr, NS_MSG_LEGACY0);
00838 
00839     } else {
00840         retval = socket_sendto(msg_tr_ptr->socket, &msg_tr_ptr->addr, msg_tr_ptr->msg_ptr, msg_tr_ptr->msg_len);
00841     }
00842     if (retval != 0) {
00843         tr_warn("dhcp service socket_sendto fails: %i", retval);
00844     } else {
00845         tr_debug("dhcp service socket_sendto %s", trace_ipv6(msg_tr_ptr->addr.address));
00846     }
00847 }
00848 bool dhcp_service_timer_tick(uint16_t ticks)
00849 {
00850     bool activeTimerNeed = false;
00851     ns_list_foreach_safe(msg_tr_t, cur_ptr, &dhcp_service->tr_list) {
00852         if (cur_ptr->timeout == 0) {
00853             continue;
00854         }
00855 
00856         if (cur_ptr->timeout <= ticks) {
00857             activeTimerNeed = true;
00858             cur_ptr->retrans++;
00859             if (cur_ptr->retrans_max != 0 && cur_ptr->retrans >= cur_ptr->retrans_max) {
00860                 // retransmission count exceeded.
00861                 cur_ptr->recv_resp_cb(cur_ptr->instance_id, cur_ptr->client_obj_ptr, 0, NULL, 0);
00862                 dhcp_tr_delete(cur_ptr);
00863                 continue;
00864             }
00865             dhcp_service_send_message(cur_ptr);
00866             // RFC 3315 says:
00867             //     RT = 2*RTprev + RAND*RTprev,
00868             // We calculate this as
00869             //     RT = RTprev + (1+RAND)*RTprev
00870             cur_ptr->timeout = cur_ptr->timeout_init + randLIB_randomise_base(cur_ptr->timeout_init, RAND1_LOW, RAND1_HIGH);
00871             // Catch 16-bit integer overflow
00872             if (cur_ptr->timeout < cur_ptr->timeout_init) {
00873                 cur_ptr->timeout = 0xFFFF;
00874             }
00875             // Check against MRT
00876             if (cur_ptr->timeout_max != 0 && cur_ptr->timeout > cur_ptr->timeout_max) {
00877                 cur_ptr->timeout = randLIB_randomise_base(cur_ptr->timeout_max, RAND1_LOW, RAND1_HIGH);
00878             }
00879             cur_ptr->timeout_init = cur_ptr->timeout;
00880         } else {
00881             cur_ptr->timeout -= ticks;
00882             activeTimerNeed = true;
00883         }
00884     }
00885     return activeTimerNeed;
00886 }
00887 #else
00888 uint16_t dhcp_service_init(int8_t interface_id, dhcp_instance_type_e instance_type, dhcp_service_receive_req_cb *receive_req_cb)
00889 {
00890     (void)interface_id;
00891     (void)instance_type;
00892     (void)receive_req_cb;
00893     return 0;
00894 }
00895 
00896 void dhcp_service_delete(uint16_t instance)
00897 {
00898     (void)instance;
00899 }
00900 
00901 void dhcp_service_relay_instance_enable(uint16_t instance, uint8_t *server_address)
00902 {
00903     (void)instance;
00904     (void)server_address;
00905 }
00906 
00907 int dhcp_service_send_resp(uint32_t msg_tr_id, uint8_t options, uint8_t *msg_ptr, uint16_t msg_len)
00908 {
00909     (void)msg_tr_id;
00910     (void)options;
00911     (void)msg_ptr;
00912     (void)msg_len;
00913     return -1;
00914 }
00915 
00916 uint32_t dhcp_service_send_req(uint16_t instance_id, uint8_t options, void *ptr, const uint8_t addr[static 16], uint8_t *msg_ptr, uint16_t msg_len, dhcp_service_receive_resp_cb *receive_resp_cb)
00917 {
00918     (void)instance_id;
00919     (void)options;
00920     (void)ptr;
00921     (void)addr;
00922     (void)msg_ptr;
00923     (void)msg_len;
00924     (void)receive_resp_cb;
00925     return 0;
00926 }
00927 
00928 void dhcp_service_set_retry_timers(uint32_t msg_tr_id, uint16_t timeout_init, uint16_t timeout_max, uint8_t retrans_max)
00929 {
00930     (void)msg_tr_id;
00931     (void)timeout_init;
00932     (void)timeout_max;
00933     (void)retrans_max;
00934 }
00935 void dhcp_service_req_remove(uint32_t msg_tr_id)
00936 {
00937     (void)msg_tr_id;
00938 }
00939 
00940 bool dhcp_service_timer_tick(uint16_t ticks)
00941 {
00942     (void)ticks;
00943     return false;
00944 }
00945 
00946 void dhcp_service_req_remove_all(void *msg_class_ptr)
00947 {
00948     (void)msg_class_ptr;
00949 }
00950 
00951 #endif