Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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
Generated on Tue Jul 12 2022 13:54:16 by
