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.
Fork of OmniWheels by
ns_socket.c
00001 /* 00002 * Copyright (c) 2008-2015, 2017, 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 * \file socket.c 00019 * \brief Socket API 00020 * 00021 * The socket API functions 00022 */ 00023 #include "nsconfig.h" 00024 #include "ns_trace.h" 00025 #include <stdio.h> 00026 #include "string.h" 00027 #include "ns_types.h" 00028 #include "randLIB.h" 00029 #include "eventOS_event.h" 00030 #include "eventOS_scheduler.h" 00031 #include "nsdynmemLIB.h" 00032 #include "Core/include/socket.h" 00033 #include "socket_api.h" 00034 #include "NWK_INTERFACE/Include/protocol.h" 00035 #include "Common_Protocols/tcp.h" 00036 #include "Common_Protocols/ipv6.h" 00037 #include "Common_Protocols/icmpv6.h" 00038 #include "ip6string.h" 00039 #include "common_functions.h" 00040 00041 #define TRACE_GROUP "sck" 00042 00043 #define RANDOM_PORT_NUMBER_START 49152 00044 #define RANDOM_PORT_NUMBER_END 65535 00045 #define RANDOM_PORT_NUMBER_COUNT (RANDOM_PORT_NUMBER_END - RANDOM_PORT_NUMBER_START + 1) 00046 #define RANDOM_PORT_NUMBER_MAX_STEP 500 00047 00048 static uint16_t port_counter; 00049 00050 static socket_t *socket_instance[SOCKETS_MAX]; 00051 00052 typedef struct socket_cb_data_t { 00053 int8_t tasklet; 00054 int8_t net_interface_id; 00055 socket_t *socket; 00056 buffer_t *buf; 00057 } socket_cb_data_t; 00058 00059 00060 typedef struct socket_cb_event_t { 00061 socket_t *socket; 00062 uint8_t socket_event; 00063 int8_t interface_id; 00064 uint16_t length; 00065 void *session_ptr; 00066 } socket_cb_event_t; 00067 00068 socket_list_t socket_list = NS_LIST_INIT(socket_list); 00069 00070 static int8_t socket_event_handler = -1; 00071 static uint8_t last_allocated_socket = SOCKETS_MAX - 1; 00072 00073 /** 00074 * Generate random port number between RANDOM_PORT_NUMBER_START and RANDOM_PORT_NUMBER_END. 00075 * 00076 * \return random port number 00077 */ 00078 uint16_t socket_generate_random_port(uint8_t protocol) 00079 { 00080 uint16_t count = RANDOM_PORT_NUMBER_COUNT; 00081 00082 do { 00083 port_counter += randLIB_get_random_in_range(1, RANDOM_PORT_NUMBER_MAX_STEP); 00084 while (port_counter >= RANDOM_PORT_NUMBER_COUNT) { 00085 port_counter -= RANDOM_PORT_NUMBER_COUNT; 00086 } 00087 uint16_t port = RANDOM_PORT_NUMBER_START + port_counter; 00088 if (socket_port_validate(port, protocol) == eOK) { 00089 return port; 00090 } 00091 } while (--count > 0); 00092 00093 return 0; 00094 } 00095 00096 int8_t socket_event_handler_id_get(void) 00097 { 00098 return socket_event_handler; 00099 } 00100 00101 socket_t *socket_pointer_get(int8_t socket) 00102 { 00103 if (socket < 0 || socket >= SOCKETS_MAX) { 00104 return NULL; 00105 } 00106 if (!socket_instance[socket] || socket_instance[socket]->family == SOCKET_FAMILY_NONE) { 00107 return NULL; 00108 } 00109 00110 return socket_instance[socket]; 00111 00112 } 00113 00114 static void socket_data_event_push(buffer_t *buf) 00115 { 00116 arm_event_s event = { 00117 .receiver = socket_event_handler, 00118 .sender = 0, 00119 .event_type = ARM_SOCKET_DATA_CB, 00120 .data_ptr = buf, 00121 .priority = ARM_LIB_HIGH_PRIORITY_EVENT, 00122 }; 00123 00124 if (eventOS_event_send(&event) != 0) { 00125 buffer_free(buf); 00126 } 00127 } 00128 00129 bool socket_data_queued_event_push(socket_t *socket) 00130 { 00131 arm_event_s event = { 00132 .receiver = socket_event_handler, 00133 .sender = 0, 00134 .event_type = ARM_SOCKET_DATA_QUEUED_CB, 00135 .data_ptr = socket_reference(socket), 00136 .priority = ARM_LIB_HIGH_PRIORITY_EVENT, 00137 }; 00138 00139 if (eventOS_event_send(&event) != 0) { 00140 return false; 00141 } 00142 return true; 00143 } 00144 00145 static void socket_cb_event_run(const socket_cb_event_t *event) 00146 { 00147 if (event->socket->id != -1) { 00148 eventOS_scheduler_set_active_tasklet(event->socket->tasklet); 00149 00150 if (event->socket->flags & SOCKET_BUFFER_CB) { 00151 static socket_buffer_callback_t socket_cb_event_buffer; 00152 socket_cb_event_buffer.session_ptr = event->session_ptr; 00153 socket_cb_event_buffer.event_type = event->socket_event; 00154 socket_cb_event_buffer.socket_id = event->socket->id; 00155 socket_cb_event_buffer.buf = 0; 00156 socket_cb_event_buffer.interface_id = event->interface_id; 00157 event->socket->u.live.fptr(&socket_cb_event_buffer); 00158 socket_cb_event_buffer.session_ptr = 0; 00159 } else { 00160 static socket_callback_t socket_cb_event_stucture; 00161 socket_cb_event_stucture.event_type = event->socket_event; 00162 socket_cb_event_stucture.socket_id = event->socket->id; 00163 socket_cb_event_stucture.d_len = event->length; 00164 socket_cb_event_stucture.interface_id = event->interface_id; 00165 event->socket->u.live.fptr(&socket_cb_event_stucture); 00166 } 00167 } 00168 } 00169 00170 void socket_buffer_cb_run(socket_t *socket, buffer_t *buffer) 00171 { 00172 if (socket->id == -1 || !socket->u.live.fptr) { 00173 buffer_free(buffer); 00174 return; 00175 } 00176 00177 eventOS_scheduler_set_active_tasklet(socket->tasklet ); 00178 00179 static socket_buffer_callback_t socket_cb_buffer; 00180 socket_cb_buffer.event_type = SOCKET_DATA; 00181 socket_cb_buffer.socket_id = socket->id ; 00182 socket_cb_buffer.interface_id = buffer->interface ->id; 00183 socket_cb_buffer.buf = buffer; 00184 socket_cb_buffer.session_ptr = NULL; 00185 00186 socket->u.live.fptr(&socket_cb_buffer); 00187 } 00188 00189 void socket_cb_run(socket_t *socket) 00190 { 00191 if (socket->id == -1 || !socket->u.live.fptr) { 00192 return; 00193 } 00194 00195 buffer_t *buf = ns_list_get_first(&socket->rcvq.bufs); 00196 00197 eventOS_scheduler_set_active_tasklet(socket->tasklet ); 00198 00199 static socket_callback_t socket_cb_structure; 00200 00201 socket_cb_structure.event_type = SOCKET_DATA; 00202 socket_cb_structure.socket_id = socket->id ; 00203 socket_cb_structure.interface_id = buf ? buf->interface ->id : 0; 00204 socket_cb_structure.LINK_LQI = buf ? buf->options .lqi : 0; 00205 socket_cb_structure.d_len = socket->rcvq.data_bytes; 00206 00207 socket->u.live.fptr(&socket_cb_structure); 00208 } 00209 00210 void socket_tasklet_event_handler(arm_event_s *event) 00211 { 00212 switch (event->event_type) { 00213 case ARM_SOCKET_INIT: 00214 tr_debug("Socket Tasklet Generated"); 00215 break; 00216 case ARM_SOCKET_EVENT_CB: { 00217 socket_cb_event_t *cb_event_ptr = event->data_ptr; 00218 socket_cb_event_run(cb_event_ptr); 00219 socket_dereference(cb_event_ptr->socket); 00220 ns_dyn_mem_free(cb_event_ptr); 00221 break; 00222 } 00223 case ARM_SOCKET_DATA_CB: { 00224 buffer_t *buf = event->data_ptr; 00225 /* Reference the socket here*/ 00226 socket_t *socket = socket_reference(buf->socket ); 00227 if (socket->flags & SOCKET_BUFFER_CB) { 00228 // They just take ownership of the buffer. No read calls. 00229 socket_buffer_cb_run(socket, buf); 00230 } else { 00231 // Emulate old one-callback-per-buffer behavior. Make sure 00232 // the recv queue is empty, then put this buffer on it, then 00233 // make the callback. Their read calls then read from the 00234 // recv queue. After the callback, flush the receive queue again. 00235 sockbuf_flush(&socket->rcvq); 00236 sockbuf_append(&socket->rcvq, buf); 00237 socket_cb_run(socket); 00238 sockbuf_flush(&socket->rcvq); 00239 } 00240 /* Dereference the socket here*/ 00241 socket_dereference(socket); 00242 break; 00243 } 00244 case ARM_SOCKET_DATA_QUEUED_CB: { 00245 socket_t *socket = event->data_ptr; 00246 socket_cb_run(socket); 00247 socket_dereference(socket); 00248 break; 00249 } 00250 case ARM_SOCKET_TCP_TIMER_CB: 00251 tcp_handle_time_event((uint16_t)event->event_data); 00252 break; 00253 00254 default: 00255 break; 00256 } 00257 } 00258 /** 00259 * Initialize API 00260 */ 00261 void socket_init(void) 00262 { 00263 if (socket_event_handler == -1) { 00264 socket_event_handler = eventOS_event_handler_create(&socket_tasklet_event_handler, ARM_SOCKET_INIT); 00265 } 00266 00267 port_counter = randLIB_get_random_in_range(0, RANDOM_PORT_NUMBER_COUNT - 1); 00268 } 00269 00270 /** 00271 * Release a socket (detaching from application) 00272 * 00273 * We are either releasing directly from an application close (ID being freed, 00274 * reference being removed from ID table), or indirectly - a pending socket 00275 * attached to a listening socket being closed. 00276 * 00277 * \param socket socket pointer 00278 */ 00279 void socket_release(socket_t *socket) 00280 { 00281 socket->flags |= SOCKET_FLAG_CLOSED | SOCKET_FLAG_SHUT_WR | SOCKET_FLAG_CANT_RECV_MORE; 00282 00283 if (socket_is_ipv6(socket)) { 00284 // Do TCP cleanup first, while we have one reference count of our own, 00285 // so it can't make socket vanish. 00286 // Take care never to put tcp_info in local variable - these calls can delete it 00287 if (tcp_info(socket->inet_pcb )) { 00288 /* This may trigger a reset if pending data. Do it first so you 00289 * get just the reset, rather than a FIN. */ 00290 tcp_session_shutdown_read(tcp_info(socket->inet_pcb )); 00291 /* This can also cause TCP deletion */ 00292 if (tcp_info(socket->inet_pcb )) { 00293 tcp_session_close(tcp_info(socket->inet_pcb )); 00294 } 00295 if (tcp_info(socket->inet_pcb )) { 00296 tcp_socket_released(tcp_info(socket->inet_pcb )); 00297 } 00298 } else { 00299 /* Unbind the internet control block - ensures users are not prevented 00300 * from binding a new socket to the same port if the socket lingers 00301 * on due to pending events/buffers. (And also means the new socket 00302 * gets any such packets, with this getting none). 00303 */ 00304 memcpy(socket->inet_pcb ->local_address , ns_in6addr_any, 16); 00305 memcpy(socket->inet_pcb ->remote_address , ns_in6addr_any, 16); 00306 socket->inet_pcb ->local_port = 0; 00307 socket->inet_pcb ->remote_port = 0; 00308 socket->inet_pcb ->protocol = 0; 00309 } 00310 sockbuf_flush(&socket->rcvq); 00311 } 00312 00313 if (!(socket->flags & SOCKET_FLAG_PENDING)) { 00314 // Release any pending sockets in a listening socket's queue 00315 ns_list_foreach_safe(socket_t, pending, &socket->u.live.queue) { 00316 // Release of a pending socket will make it non-pending and 00317 // hence take it off our queue (see immediately below) making 00318 // this loop work. (And maybe it will free it too). 00319 socket_release(pending); 00320 } 00321 } else { 00322 // This may make socket vanish, as leaving pending decrements count 00323 socket_leave_pending_state(socket, NULL); 00324 } 00325 } 00326 00327 static void socket_free(socket_t *socket) 00328 { 00329 if (socket->refcount != 0) { 00330 tr_err("free refed"); 00331 } 00332 if (socket->flags & SOCKET_FLAG_PENDING) { 00333 tr_err("free pending"); 00334 } 00335 ns_list_remove(&socket_list, socket); 00336 sockbuf_flush(&socket->rcvq); 00337 sockbuf_flush(&socket->sndq); 00338 00339 socket_inet_pcb_free(socket->inet_pcb ); 00340 ns_dyn_mem_free(socket); 00341 } 00342 00343 error_t socket_port_validate(uint16_t port, uint8_t protocol) 00344 { 00345 ns_list_foreach(socket_t, socket, &socket_list) { 00346 if (!socket_is_ipv6(socket)) { 00347 continue; 00348 } 00349 if (socket->inet_pcb ->local_port == port && socket->inet_pcb ->protocol == protocol) { 00350 return eFALSE; 00351 } 00352 } 00353 return eOK; 00354 } 00355 00356 int8_t socket_id_assign_and_attach(socket_t *socket) 00357 { 00358 int pos = last_allocated_socket + 1; 00359 00360 for (int i=0; i < SOCKETS_MAX; i++, pos++) { 00361 if (pos >= SOCKETS_MAX) { 00362 pos = 0; 00363 } 00364 if (socket_instance[pos] == NULL) { 00365 socket->id = pos; 00366 socket_instance[pos] = socket_reference(socket); 00367 last_allocated_socket = pos; 00368 return pos; 00369 } 00370 } 00371 return -1; 00372 } 00373 00374 void socket_id_detach(int8_t sid) 00375 { 00376 socket_t *socket = socket_instance[sid]; 00377 socket->id = -1; 00378 socket_release(socket); 00379 socket_instance[sid] = socket_dereference(socket); 00380 } 00381 00382 inet_pcb_t *socket_inet_pcb_allocate(void) 00383 { 00384 inet_pcb_t *inet_pcb = ns_dyn_mem_alloc(sizeof(inet_pcb_t)); 00385 if (!inet_pcb) { 00386 return NULL; 00387 } 00388 00389 memset(inet_pcb, 0, sizeof(inet_pcb_t)); 00390 #ifndef NO_TCP 00391 inet_pcb->session = NULL; 00392 #endif 00393 inet_pcb->unicast_hop_limit = -1; 00394 inet_pcb->multicast_hop_limit = 1; 00395 inet_pcb->multicast_if = 0; 00396 inet_pcb->multicast_loop = true; 00397 inet_pcb->socket = NULL; 00398 inet_pcb->addr_preferences = 0; 00399 inet_pcb->recvhoplimit = false; 00400 inet_pcb->recvpktinfo = false; 00401 inet_pcb->recvtclass = false; 00402 inet_pcb->link_layer_security = -1; 00403 #ifndef NO_IPV6_PMTUD 00404 inet_pcb->use_min_mtu = -1; 00405 #endif 00406 #ifndef NO_IP_FRAGMENT_TX 00407 inet_pcb->dontfrag = 0; 00408 #endif 00409 inet_pcb->tclass = SOCKET_IPV6_TCLASS_DEFAULT; 00410 inet_pcb->flow_label = IPV6_FLOW_UNSPECIFIED; 00411 ns_list_init(&inet_pcb->mc_groups); 00412 00413 return inet_pcb; 00414 } 00415 00416 inet_pcb_t *socket_inet_pcb_clone(const inet_pcb_t *orig) 00417 { 00418 inet_pcb_t *inet_pcb = ns_dyn_mem_alloc(sizeof(inet_pcb_t)); 00419 if (!inet_pcb) { 00420 return NULL; 00421 } 00422 *inet_pcb = *orig; 00423 inet_pcb->socket = NULL; 00424 #ifndef NO_TCP 00425 inet_pcb->session = NULL; 00426 #endif 00427 return inet_pcb; 00428 } 00429 00430 00431 socket_t *socket_allocate(socket_type_t type) 00432 { 00433 socket_t *socket = ns_dyn_mem_alloc(sizeof(socket_t)); 00434 if (!socket) { 00435 return NULL; 00436 } 00437 memset(socket, 0, sizeof *socket); 00438 socket->id = -1; 00439 socket->type = type; 00440 socket->family = SOCKET_FAMILY_NONE; 00441 sockbuf_init(&socket->rcvq); 00442 sockbuf_init(&socket->sndq); 00443 if (type == SOCKET_TYPE_STREAM) { 00444 socket->sndq.low_water_mark = SOCKET_DEFAULT_STREAM_SNDLOWAT; 00445 sockbuf_reserve(&socket->rcvq, SOCKET_DEFAULT_STREAM_RCVBUF); 00446 sockbuf_reserve(&socket->sndq, SOCKET_DEFAULT_STREAM_SNDBUF); 00447 } 00448 00449 ns_list_add_to_end(&socket_list, socket); 00450 return socket; 00451 } 00452 00453 /* Increase reference counter on socket, returning now-owned pointer */ 00454 socket_t *socket_reference(socket_t *socket_ptr) 00455 { 00456 if (!socket_ptr) { 00457 return NULL; 00458 } 00459 00460 socket_ptr->refcount++; 00461 if (socket_ptr->refcount == 0) { 00462 socket_ptr->refcount--; 00463 tr_error("ref overflow"); 00464 } 00465 00466 return socket_ptr; 00467 } 00468 00469 /* Decrease reference counter on socket, releasing if it hits zero */ 00470 /* Always returns NULL to indicate caller no longer owns it */ 00471 socket_t *socket_dereference(socket_t *socket_ptr) 00472 { 00473 if (!socket_ptr) { 00474 return NULL; 00475 } 00476 00477 if (socket_ptr->refcount == 0) { 00478 tr_error("ref underflow"); 00479 return NULL; 00480 } 00481 if (--socket_ptr->refcount == 0) { 00482 socket_free(socket_ptr); 00483 } 00484 return NULL; 00485 } 00486 00487 00488 /** 00489 * Allocate a socket 00490 * 00491 * \param sid pointer to socket ID which will contain socket ID 00492 * \param port listen port for socket 00493 * 00494 * \return eOK socket opened 00495 * \return eFALSE no free sockets 00496 * \return eBUSY port reserved 00497 */ 00498 error_t socket_create(socket_family_t family, socket_type_t type, uint8_t protocol, int8_t *sid, uint16_t port, void (*passed_fptr)(void *), bool buffer_type) 00499 { 00500 if (sid) { 00501 *sid = -1; 00502 } 00503 00504 if (passed_fptr == 0) { 00505 return eFALSE; 00506 } 00507 00508 /* Note that IPv6 socket lookup implementation assumes we don't have raw 00509 * TCP or UDP sockets, thus we ensure protocol=UDP iff type=DGRAM, 00510 * and protocol=TCP iff type=STREAM. 00511 */ 00512 if (family == SOCKET_FAMILY_IPV6) { 00513 switch (type) { 00514 case SOCKET_TYPE_DGRAM: 00515 protocol = IPV6_NH_UDP; 00516 break; 00517 case SOCKET_TYPE_STREAM: 00518 protocol = IPV6_NH_TCP; 00519 break; 00520 default: 00521 if (protocol == 0 || protocol == IPV6_NH_TCP || protocol == IPV6_NH_UDP) { 00522 return eFALSE; 00523 } 00524 port = 0xFFFF; 00525 break; 00526 } 00527 } else { 00528 /* SOCKET_FAMILY_LOCAL still has inet_pcb - give it 0 protocol */ 00529 protocol = 0; 00530 port = 0xFFFF; 00531 } 00532 00533 if (port != 0 && socket_port_validate(port, protocol) == eFALSE) { 00534 return eBUSY; 00535 } 00536 00537 socket_t *socket = socket_allocate(type); 00538 if (socket == NULL) { 00539 tr_error("Socket allocation fail"); 00540 return eFALSE; 00541 } 00542 inet_pcb_t *inet_pcb = socket_inet_pcb_allocate(); 00543 if (inet_pcb == NULL) { 00544 socket_free(socket); // don't leave half initialized sockets behind 00545 tr_error("inet_pcb allocation fail"); 00546 return eFALSE; 00547 } 00548 socket->inet_pcb = inet_pcb; 00549 00550 *sid = socket_id_assign_and_attach(socket); 00551 if (*sid == -1) { 00552 tr_error("Socket IDs exhausted"); 00553 socket_free(socket); 00554 return eFALSE; 00555 } 00556 00557 00558 socket->flags = 0; 00559 00560 tr_debug("Socket id %d allocated", socket->id ); 00561 socket->tasklet = eventOS_scheduler_get_active_tasklet(); 00562 socket->family = family; 00563 socket->u.live.fptr = passed_fptr; 00564 ns_list_init(&socket->u.live.queue); 00565 socket->default_interface_id = -1; 00566 socket->broadcast_pan = 0; 00567 if (buffer_type) { 00568 socket->flags |= SOCKET_BUFFER_CB; 00569 } 00570 00571 // Fill Internet protocol control block 00572 inet_pcb->protocol = protocol; 00573 inet_pcb->local_port = port; 00574 inet_pcb->socket = socket; 00575 00576 return eOK; 00577 } 00578 00579 socket_t *socket_new_incoming_connection(socket_t *listen_socket) 00580 { 00581 if (!socket_validate_listen_backlog(listen_socket)) { 00582 return NULL; 00583 } 00584 socket_t *new_socket = socket_allocate(listen_socket->type); 00585 if (!new_socket) { 00586 return NULL; 00587 } 00588 inet_pcb_t *inet_pcb = socket_inet_pcb_clone(listen_socket->inet_pcb ); 00589 if (!inet_pcb) { 00590 socket_free(new_socket); 00591 return NULL; 00592 } 00593 inet_pcb->socket = new_socket; 00594 // They can fill this in on return 00595 new_socket->inet_pcb = inet_pcb; 00596 new_socket->flags = SOCKET_FLAG_PENDING | SOCKET_FLAG_CONNECTING; 00597 new_socket->family = listen_socket->family; 00598 new_socket->type = listen_socket->type; 00599 new_socket->default_interface_id = listen_socket->default_interface_id; 00600 new_socket->broadcast_pan = listen_socket->broadcast_pan; 00601 new_socket->tasklet = listen_socket->tasklet ; 00602 new_socket->u.pending.listen_head = listen_socket; 00603 ns_list_add_to_end(&listen_socket->u.live.queue, socket_reference(new_socket)); 00604 00605 return new_socket; 00606 } 00607 00608 /* Connection did not complete or was abandoned - notification from transport */ 00609 void socket_connection_abandoned(socket_t *socket, int8_t interface_id, uint8_t reason) 00610 { 00611 if (!(socket->flags & (SOCKET_FLAG_CONNECTING|SOCKET_FLAG_CONNECTED))) { 00612 tr_err("abandoned: not connecting/connected"); 00613 return; 00614 } 00615 socket->flags &=~ SOCKET_FLAG_CONNECTING; 00616 // leaving CONNECTED flag set prevents weirdness like reconnecting. Good idea? 00617 socket->flags |= SOCKET_FLAG_SHUT_WR | SOCKET_FLAG_CANT_RECV_MORE | SOCKET_FLAG_CONNECTED; 00618 sockbuf_flush(&socket->sndq); 00619 if (socket->flags & SOCKET_FLAG_PENDING) { 00620 // By leaving pending state, without any remaining reference, 00621 // we just let the failed connection go away, without notifying user 00622 socket_leave_pending_state(socket, NULL); 00623 // Hard to say if this is right if it was fully connected, but seems the best 00624 // we can do for the minute - we can't queue up the reset/whatever event. 00625 } else if (reason != 0) { 00626 socket_event_push(reason, socket, interface_id, NULL, 0); 00627 } 00628 } 00629 00630 /* Connection has completed - notification from transport */ 00631 void socket_connection_complete(socket_t *socket, int8_t interface_id) 00632 { 00633 if (!(socket->flags & SOCKET_FLAG_CONNECTING)) { 00634 tr_err("complete: not connecting"); 00635 return; 00636 } 00637 if (socket->flags & SOCKET_FLAG_CONNECTED) { 00638 tr_err("complete: already connected"); 00639 return; 00640 } 00641 socket->flags &=~ SOCKET_FLAG_CONNECTING; 00642 socket->flags |= SOCKET_FLAG_CONNECTED; 00643 if (socket->flags & SOCKET_FLAG_PENDING) { 00644 socket_event_push(SOCKET_INCOMING_CONNECTION, socket->u.pending.listen_head, interface_id, NULL, 0); 00645 } else { 00646 socket_event_push(SOCKET_CONNECT_DONE, socket, interface_id, NULL, 0); 00647 } 00648 } 00649 00650 /* Socket is to leave pending state - either being accepted or released */ 00651 void socket_leave_pending_state(socket_t *socket, void (*fptr)(void *)) 00652 { 00653 if (!(socket->flags & SOCKET_FLAG_PENDING)) { 00654 tr_err("not pending"); 00655 return; 00656 } 00657 ns_list_remove(&socket->u.pending.listen_head->u.live.queue, socket); 00658 socket->flags &= ~SOCKET_FLAG_PENDING; 00659 ns_list_init(&socket->u.live.queue); 00660 socket->u.live.fptr = fptr; 00661 socket_dereference(socket); 00662 } 00663 00664 void socket_cant_recv_more(socket_t *socket, int8_t interface_id) 00665 { 00666 socket->flags |= SOCKET_FLAG_CANT_RECV_MORE; 00667 socket_event_push(SOCKET_DATA, socket, interface_id, 0, 0); 00668 } 00669 00670 socket_t *socket_lookup_ipv6(uint8_t protocol, const sockaddr_t *local_addr, const sockaddr_t *remote_addr, bool allow_wildcards) 00671 { 00672 //tr_debug("socket_lookup() local=%s [%d] remote=%s [%d]", trace_ipv6(local_addr->address), local_addr->port, trace_ipv6(remote_addr->address), remote_addr->port); 00673 ns_list_foreach(socket_t, socket, &socket_list) { 00674 if (!socket_is_ipv6(cur)) { 00675 continue; 00676 } 00677 inet_pcb_t *cur = socket->inet_pcb ; 00678 //tr_debug("cur local=%s [%d] remote=%s [%d]", trace_ipv6(cur->local_address), cur->local_port, trace_ipv6(cur->remote_address), cur->remote_port); 00679 /* Protocol must match */ 00680 if (cur->protocol != protocol) { 00681 continue; 00682 } 00683 00684 /* For TCP and UDP only, ports must match */ 00685 if (protocol == IPV6_NH_UDP || protocol == IPV6_NH_TCP) { 00686 if (cur->local_port == 0 || cur->local_port != local_addr->port ) { 00687 continue; 00688 } 00689 if (!(allow_wildcards && cur->remote_port == 0) && cur->remote_port != remote_addr->port ) { 00690 continue; 00691 } 00692 } 00693 00694 if (!(allow_wildcards && addr_ipv6_equal(cur->local_address , ns_in6addr_any))) { 00695 if (!addr_ipv6_equal(cur->local_address , local_addr->address )) { 00696 continue; 00697 } 00698 } 00699 00700 if (!(allow_wildcards && addr_ipv6_equal(cur->remote_address , ns_in6addr_any))) { 00701 if (!addr_ipv6_equal(cur->remote_address , remote_addr->address )) { 00702 continue; 00703 } 00704 } 00705 00706 return socket; 00707 } 00708 00709 return NULL; 00710 } 00711 00712 /* Write address + port neatly to out, returning characters written */ 00713 /* Maximum output length is 48, including the terminator, assuming ip6tos limited to 39 */ 00714 static int sprint_addr(char *out, const uint8_t addr[static 16], uint16_t port) 00715 { 00716 char *init_out = out; 00717 if (addr_is_ipv6_unspecified(addr)) { 00718 *out++ = '*'; 00719 } else { 00720 *out++ = '['; 00721 out += ip6tos(addr, out); 00722 *out++ = ']'; 00723 } 00724 00725 *out++ = ':'; 00726 if (port == 0) { 00727 *out++ = '*'; 00728 } else { 00729 out += sprintf(out, "%"PRIu16, port); 00730 } 00731 *out = '\0'; 00732 return (int) (out - init_out); 00733 } 00734 00735 static void socket_print(const socket_t *socket, int lwidth, int rwidth, route_print_fn_t *print_fn, char sep) 00736 { 00737 if (!socket_is_ipv6(socket)) { 00738 return; 00739 } 00740 const inet_pcb_t *pcb = socket->inet_pcb ; 00741 char remote_str[48]; 00742 char local_str[48]; 00743 00744 char proto_buf[4]; 00745 const char *proto_str; 00746 switch (pcb->protocol ) { 00747 case IPV6_NH_TCP: 00748 proto_str = "TCP"; 00749 break; 00750 case IPV6_NH_UDP: 00751 proto_str = "UDP"; 00752 break; 00753 case IPV6_NH_ICMPV6: 00754 proto_str = "ICMP6"; 00755 break; 00756 default: 00757 sprintf(proto_buf, "%"PRIu8, pcb->protocol ); 00758 proto_str = proto_buf; 00759 break; 00760 } 00761 sprint_addr(local_str, pcb->local_address , pcb->local_port ); 00762 sprint_addr(remote_str, pcb->remote_address , pcb->remote_port ); 00763 00764 const char *state = ""; 00765 if (pcb->protocol == IPV6_NH_TCP) { 00766 if (tcp_info(pcb)) { 00767 state = tcp_state_name(tcp_info(pcb)); 00768 } else if (socket->flags & SOCKET_LISTEN_STATE) { 00769 state = "LISTEN"; 00770 } else { 00771 state = "CLOSED"; 00772 } 00773 } 00774 print_fn("%3.*"PRId8"%c%3u%c%6"PRId32/*"%c%6"PRId32*/"%c%6"PRId32"%c%-5.5s%c%-*s%c%-*s%c%s", 00775 socket->id >= 0 ? 1 : 0, socket->id >= 0 ? socket->id : 0, sep, 00776 socket->refcount, sep, 00777 socket->rcvq.data_bytes,sep, 00778 /*socket->rcvq.buf_overhead_bytes, sep,*/ 00779 socket->sndq.data_bytes, sep, 00780 proto_str, sep, 00781 lwidth, local_str, sep, 00782 rwidth, remote_str, sep, 00783 state); 00784 } 00785 00786 void socket_list_print(route_print_fn_t *print_fn, char sep) 00787 { 00788 int lwidth = 18, rwidth = 18; 00789 ns_list_foreach(const socket_t, socket, &socket_list) { 00790 if (!socket_is_ipv6(socket)) { 00791 continue; 00792 } 00793 const inet_pcb_t *pcb = socket->inet_pcb ; 00794 char addr[48]; 00795 int len; 00796 len = sprint_addr(addr, pcb->local_address , pcb->local_port ); 00797 if (lwidth < len) { 00798 lwidth = len; 00799 } 00800 len = sprint_addr(addr, pcb->remote_address , pcb->remote_port ); 00801 if (rwidth < len) { 00802 rwidth = len; 00803 } 00804 } 00805 print_fn("Sck%cRef%cRecv-Q%c"/*"Recv-B%c"*/"Send-Q%cProto%c%-*s%c%-*s%c(state)", sep, sep, sep, /*sep,*/ sep, sep, lwidth, "Local Address", sep, rwidth, "Remote Address", sep); 00806 ns_list_foreach(const socket_t, socket, &socket_list) { 00807 socket_print(socket, lwidth, rwidth, print_fn, sep); 00808 } 00809 00810 /* Chuck in a consistency check */ 00811 for (int i = 0; i < SOCKETS_MAX; i++) { 00812 if (socket_instance[i] && socket_instance[i]->id != i) { 00813 tr_err("ID %d points to %p with id %d\n", i, (void *)socket_instance[i], socket_instance[i]->id); 00814 } 00815 } 00816 ns_list_foreach(socket_t, socket, &socket_list) { 00817 if (socket->id != -1 && socket_pointer_get(socket->id ) != socket) { 00818 tr_err("Socket %p has invalid ID %d\n", (void *)socket, socket->id ); 00819 } 00820 sockbuf_check(&socket->rcvq); 00821 sockbuf_check(&socket->sndq); 00822 } 00823 } 00824 00825 socket_t *socket_lookup(socket_family_t family, uint8_t protocol, const sockaddr_t *local_addr, const sockaddr_t *remote_addr) 00826 { 00827 switch (family) { 00828 case SOCKET_FAMILY_IPV6: 00829 return socket_lookup_ipv6(protocol, local_addr, remote_addr, true); 00830 default: 00831 return NULL; 00832 } 00833 } 00834 00835 /** 00836 * Push a buffer to a socket 00837 * 00838 * Used by the protocol core to push buffers to sockets. 00839 * 00840 * To determine the socket to send to, transport layer must ensure either: 00841 * a) buf->socket_id already filled in, or 00842 * b) buf->options.type is socket family (IPv6/Local) 00843 * buf->options.code is protocol (IPv6=NH,Local=n/a) 00844 * 00845 * \param buf buffer to push 00846 * 00847 * \return eOK socket opened 00848 * \return eFALSE no socket found 00849 * \return eBUSY socket full 00850 */ 00851 error_t socket_up(buffer_t *buf) 00852 { 00853 socket_t *socket = buf->socket ; 00854 00855 if (!socket) { 00856 socket = socket_lookup((socket_family_t) buf->options .type , buf->options .code , &buf->dst_sa , &buf->src_sa ); 00857 00858 if (!socket) { 00859 //tr_debug("Socket:Drop"); 00860 goto drop; 00861 } 00862 buffer_socket_set(buf, socket); 00863 } 00864 00865 if ((socket->flags & (SOCKET_FLAG_PENDING|SOCKET_FLAG_CLOSED)) || socket->id == -1) { 00866 goto drop; 00867 } 00868 00869 if (socket->rcvq.data_byte_limit == 0) { 00870 // Old-style one event per buffer 00871 socket_data_event_push(buf); 00872 } else { 00873 // Queuing enabled - new-style events 00874 if (sockbuf_space(&socket->rcvq) < buffer_data_length(buf)) { 00875 tr_debug("Socket %d Recv-Q full", socket->id ); 00876 goto drop; 00877 } 00878 bool pushed = socket_data_queued_event_push(socket); 00879 // if this failed, it means total memory exhaustion - safest to drop the packet 00880 if (!pushed) { 00881 goto drop; 00882 } 00883 sockbuf_append(&socket->rcvq, buf); 00884 } 00885 return eOK; 00886 00887 drop: 00888 buffer_free(buf); 00889 return eFALSE; 00890 } 00891 00892 void socket_event_push(uint8_t sock_event, socket_t *socket, int8_t interface_id, void *session_ptr, uint16_t length) 00893 { 00894 if (socket->flags & (SOCKET_FLAG_PENDING|SOCKET_FLAG_CLOSED)) { 00895 return; 00896 } 00897 00898 socket_cb_event_t *cb_event = ns_dyn_mem_temporary_alloc(sizeof(socket_cb_event_t)); 00899 if (cb_event) { 00900 cb_event->socket = socket_reference(socket); 00901 cb_event->socket_event = sock_event; 00902 cb_event->session_ptr = session_ptr; 00903 cb_event->interface_id = interface_id; 00904 cb_event->length = length; 00905 arm_event_s event = { 00906 .receiver = socket_event_handler, 00907 .sender = 0, 00908 .data_ptr = cb_event, 00909 .event_type = ARM_SOCKET_EVENT_CB, 00910 .priority = ARM_LIB_HIGH_PRIORITY_EVENT, 00911 }; 00912 if (eventOS_event_send(&event) != 0) { 00913 socket_dereference(socket); 00914 ns_dyn_mem_free(cb_event); 00915 } 00916 } 00917 } 00918 00919 00920 /* Fill in a buffer's hop limit, based on the user's socket options */ 00921 void socket_inet_pcb_set_buffer_hop_limit(const inet_pcb_t *inet_pcb, buffer_t *buf, const int16_t *msg_hoplimit) 00922 { 00923 /* If hop limit specified by ancillary data, obey that over socket options */ 00924 if (msg_hoplimit) { 00925 if (*msg_hoplimit != -1) { 00926 /* Use the value they gave for this message */ 00927 buf->options .hop_limit = *msg_hoplimit; 00928 return; 00929 } 00930 /* If -1, we will go with the default, ignoring socket options */ 00931 } else if (addr_is_ipv6_multicast(buf->dst_sa .address )) { 00932 /* Multicasts have a fixed default - multicast_hop_limit will be user-specified, or that default */ 00933 buf->options .hop_limit = inet_pcb->multicast_hop_limit; 00934 return; 00935 } else if (inet_pcb->unicast_hop_limit != -1) { 00936 /* If the user specified a unicast hop limit, use it */ 00937 buf->options .hop_limit = inet_pcb->unicast_hop_limit ; 00938 return; 00939 } 00940 00941 /* User didn't specify a unicast hop limit, get the per-interface default */ 00942 /* At the moment we can only rely on if_index in the down direction, not id */ 00943 protocol_interface_info_entry_t *cur = buf->interface ; 00944 buf->options .hop_limit = cur->cur_hop_limit; 00945 } 00946 00947 /** 00948 * Calculate message payload length and validate message header iov vectors 00949 */ 00950 bool socket_message_validate_iov(const ns_msghdr_t *msg, uint16_t *length_out) 00951 { 00952 if (msg->msg_iovlen != 0 && !msg->msg_iov) { 00953 return false; 00954 } 00955 00956 uint16_t msg_length = 0; 00957 ns_iovec_t *msg_iov = msg->msg_iov; 00958 for (uint_fast16_t i = 0; i < msg->msg_iovlen; i++) { 00959 if (msg_iov->iov_len != 0 && !msg_iov->iov_base) { 00960 return false; 00961 } 00962 msg_length += msg_iov->iov_len; 00963 if (msg_length < msg_iov->iov_len) { 00964 return false; 00965 } 00966 msg_iov++; 00967 } 00968 00969 if (length_out) { 00970 *length_out = msg_length; 00971 } 00972 00973 return true; 00974 } 00975 00976 /** 00977 * Write a data buffer to a socket 00978 * 00979 * Used by the application to send data with meta data from msg 00980 * 00981 * Data will be taken either from buf if non-NULL else from msg->msg_iov. 00982 * 00983 * Using buf is not permitted for stream sockets. 00984 * 00985 * \param sid socket id 00986 * \param buf pointer to buffer is plain buffer with payload only - all metadata ignored 00987 * \param msg pointer to message-specific data message name define destination address and control message define ancillary data 00988 * 00989 * \return 0 Ok done 00990 * \return -1 Unsupported socket or message parameter 00991 * \return -5 Socket not properly connected 00992 * \return -6 Packet too short 00993 */ 00994 int16_t socket_buffer_sendmsg(int8_t sid, buffer_t *buf, const struct ns_msghdr *msg, int flags) 00995 { 00996 int8_t ret_val; 00997 int8_t interface_id = -1; 00998 00999 const int16_t *msg_hoplimit = NULL; 01000 uint16_t payload_length; 01001 01002 //Validate socket id 01003 socket_t *socket_ptr = socket_pointer_get(sid); 01004 01005 if (!socket_ptr || !socket_ptr->inet_pcb ) { 01006 tr_warn("Socket Id %i", sid); 01007 ret_val = -1; 01008 goto fail; 01009 } 01010 inet_pcb_t *inet_pcb = socket_ptr->inet_pcb ; 01011 01012 if (buf) { 01013 payload_length = buffer_data_length(buf); 01014 } else { 01015 if (!socket_message_validate_iov(msg, &payload_length)) { 01016 return -1; 01017 } 01018 } 01019 01020 #ifndef NO_TCP 01021 /* Special handling for stream - basically no advanced features of sendmsg operate. 01022 * Can't set address, can't set ancilliary data. 01023 * Don't want to fill in other sticky options into buffer - TCP must handle this itself, 01024 * as it must do it for all packets, not just those coming from sendmsg. 01025 */ 01026 if (socket_ptr->type == SOCKET_TYPE_STREAM) { 01027 /* Stream sockets must be connected and not shutdown for write */ 01028 if ((socket_ptr->flags & (SOCKET_FLAG_CONNECTED|SOCKET_FLAG_SHUT_WR)) != SOCKET_FLAG_CONNECTED) { 01029 ret_val = -5; 01030 goto fail; 01031 } 01032 01033 /* Stream sockets cannot have address specified (POSIX "EISCONN") */ 01034 if (msg && msg->msg_name && msg->msg_namelen) { 01035 ret_val = -5; 01036 goto fail; 01037 } 01038 01039 if (payload_length == 0) { 01040 goto success; // Sending nothing is a no-op 01041 } 01042 01043 // Figure out how much we can actually take, and reduce 01044 // payload_length if necessary (but if fed a buffer, we always just 01045 // accept the whole thing). 01046 if (!buf) { 01047 int32_t space = sockbuf_space(&socket_ptr->sndq); 01048 if (space < payload_length) { 01049 if (space < (int32_t) socket_ptr->sndq.low_water_mark) { 01050 ret_val = NS_EWOULDBLOCK; 01051 goto fail; 01052 } 01053 if (flags & NS_MSG_LEGACY0) { 01054 // Can't do a partial write, as we can't actually 01055 // indicate that we've done so. For compatibility, 01056 // accept a write of any size if there is some buffer 01057 // space available. This could make us massively go 01058 // over the buffer size limit. 01059 } else { 01060 payload_length = space; 01061 } 01062 } 01063 } 01064 } 01065 #endif // NO_TCP 01066 01067 // Now copy (some of) the data into a buffer 01068 if (!buf) { 01069 buf = buffer_get(payload_length); 01070 if (!buf) { 01071 ret_val = -2; 01072 goto fail; 01073 } 01074 01075 const ns_iovec_t *msg_iov = msg->msg_iov; 01076 uint16_t to_copy = payload_length; 01077 for (uint_fast16_t i = 0; i < msg->msg_iovlen; i++, msg_iov++) { 01078 uint16_t len = msg_iov->iov_len < to_copy ? msg_iov->iov_len : to_copy; 01079 buffer_data_add(buf, msg_iov->iov_base, len); 01080 to_copy -= len; 01081 if (to_copy == 0) { 01082 break; 01083 } 01084 } 01085 } 01086 01087 buf->payload_length = payload_length; 01088 01089 #ifndef NO_TCP 01090 if (socket_ptr->type == SOCKET_TYPE_STREAM) { 01091 tcp_session_t *tcp_info = tcp_info(inet_pcb); 01092 if (!tcp_info) { 01093 tr_warn("No TCP session for cur Socket"); 01094 ret_val = -3; 01095 goto fail; 01096 } 01097 01098 switch (tcp_session_send(tcp_info, buf)) { 01099 case TCP_ERROR_NO_ERROR: 01100 break; 01101 case TCP_ERROR_WRONG_STATE: 01102 default: 01103 ret_val = -3; 01104 goto fail; 01105 } 01106 goto success; 01107 } 01108 // TCP system has taken ownership of buffer, or we've failed 01109 // Everything below this point is non-TCP 01110 #endif //NO_TCP 01111 01112 /** 01113 * Mark Socket id to buffer meta data 01114 */ 01115 buffer_socket_set(buf, socket_ptr); 01116 01117 /** 01118 * Allocate random port if port is not defined. 01119 */ 01120 if (inet_pcb->local_port == 0) { 01121 inet_pcb->local_port = socket_generate_random_port(inet_pcb->protocol ); 01122 if (inet_pcb->local_port == 0) { 01123 ret_val = -2; 01124 goto fail; 01125 } 01126 } 01127 01128 /** 01129 * Set socket configured parameters 01130 */ 01131 buf->options .traffic_class = inet_pcb->tclass; 01132 buf->options .ipv6_use_min_mtu = inet_pcb->use_min_mtu ; 01133 buf->options .ipv6_dontfrag = inet_pcb->dontfrag; 01134 buf->options .multicast_loop = inet_pcb->multicast_loop; 01135 01136 /* Set default remote address from PCB */ 01137 if (inet_pcb->remote_port != 0 && !addr_ipv6_equal(inet_pcb->remote_address , ns_in6addr_any)) { 01138 memcpy(buf->dst_sa .address , inet_pcb->remote_address , 16); 01139 buf->dst_sa .port = inet_pcb->remote_port ; 01140 buf->dst_sa .addr_type = ADDR_IPV6 ; 01141 } else { 01142 buf->dst_sa .addr_type = ADDR_NONE ; 01143 } 01144 01145 /** 01146 * validate Message name and Parse Ancillary Data when Message header is shared. 01147 */ 01148 if (msg) { 01149 /** 01150 * Validate message name (destination) and set address to buffer 01151 */ 01152 if (msg->msg_namelen) { 01153 if (!msg->msg_name || msg->msg_namelen != sizeof(ns_address_t)) { 01154 ret_val = -1; 01155 goto fail; 01156 } 01157 01158 ns_address_t *address = msg->msg_name; 01159 buf->dst_sa .port = address->identifier; 01160 buf->dst_sa .addr_type = ADDR_IPV6 ; 01161 memcpy(buf->dst_sa .address , address->address, 16); 01162 } 01163 01164 ns_cmsghdr_t *cmsg = NS_CMSG_FIRSTHDR(msg); 01165 //Stay at while when full ancillary data is analyzed 01166 while (cmsg) { 01167 if (cmsg->cmsg_level == SOCKET_IPPROTO_IPV6) { 01168 const void *data_ptr = NS_CMSG_DATA(cmsg); 01169 switch (cmsg->cmsg_type) { 01170 case SOCKET_IPV6_PKTINFO: { 01171 if (cmsg->cmsg_len != NS_CMSG_LEN(sizeof(ns_in6_pktinfo_t))) { 01172 ret_val = -1; 01173 goto fail; 01174 } 01175 const ns_in6_pktinfo_t *packetinfo = data_ptr; 01176 memcpy(buf->src_sa .address , packetinfo->ipi6_addr, 16); 01177 buf->src_sa .addr_type = addr_ipv6_equal(packetinfo->ipi6_addr, ns_in6addr_any) ? ADDR_NONE : ADDR_IPV6 ; 01178 /** 01179 * Set interface id when it is configured >0 01180 */ 01181 if (packetinfo->ipi6_ifindex > 0) { 01182 interface_id = packetinfo->ipi6_ifindex; 01183 } 01184 break; 01185 } 01186 01187 case SOCKET_IPV6_HOPLIMIT: 01188 if (cmsg->cmsg_len != NS_CMSG_LEN(sizeof(int16_t))) { 01189 ret_val = -1; 01190 goto fail; 01191 } 01192 msg_hoplimit = data_ptr; 01193 if (*msg_hoplimit < -1 || *msg_hoplimit > 255) { 01194 ret_val = -1; 01195 goto fail; 01196 } 01197 break; 01198 01199 case SOCKET_IPV6_TCLASS: { 01200 if (cmsg->cmsg_len != NS_CMSG_LEN(sizeof(int16_t))) { 01201 ret_val = -1; 01202 goto fail; 01203 } 01204 int16_t tclass = *(const int16_t*)data_ptr; 01205 01206 if (tclass == -1) { 01207 buf->options .traffic_class = SOCKET_IPV6_TCLASS_DEFAULT; 01208 } else if (tclass >= 0 && tclass <= 255) { 01209 buf->options .traffic_class = tclass; 01210 } else { 01211 ret_val = -1; 01212 goto fail; 01213 } 01214 break; 01215 } 01216 #ifndef NO_IPV6_PMTUD 01217 case SOCKET_IPV6_USE_MIN_MTU: { 01218 if (cmsg->cmsg_len != NS_CMSG_LEN(sizeof(int8_t))) { 01219 ret_val = -1; 01220 goto fail; 01221 } 01222 int8_t use_min_mtu = *(const int8_t *) data_ptr; 01223 if (use_min_mtu < -1 || use_min_mtu > 1) { 01224 ret_val = -1; 01225 goto fail; 01226 } 01227 buf->options .ipv6_use_min_mtu = use_min_mtu; 01228 break; 01229 } 01230 #endif 01231 #ifndef NO_IP_FRAGMENT_TX 01232 case SOCKET_IPV6_DONTFRAG: { 01233 if (cmsg->cmsg_len != NS_CMSG_LEN(sizeof(int8_t))) { 01234 ret_val = -1; 01235 goto fail; 01236 } 01237 int8_t dont_frag = *(const int8_t *) data_ptr; 01238 if (dont_frag < 0 || dont_frag > 1) { 01239 ret_val = -1; 01240 goto fail; 01241 } 01242 buf->options .ipv6_dontfrag = dont_frag; 01243 break; 01244 } 01245 #endif 01246 case SOCKET_IPV6_MULTICAST_LOOP: { 01247 if (cmsg->cmsg_len != NS_CMSG_LEN(sizeof(bool))) { 01248 ret_val = -1; 01249 goto fail; 01250 } 01251 buf->options .multicast_loop = *(const bool *) data_ptr; 01252 break; 01253 } 01254 default: 01255 break; 01256 } 01257 } 01258 cmsg = NS_CMSG_NXTHDR(msg, cmsg); 01259 } 01260 } 01261 01262 /* Should have destination address by now */ 01263 if (buf->dst_sa .addr_type == ADDR_NONE ) { 01264 return -5; 01265 } 01266 01267 switch (socket_ptr->type) { 01268 case SOCKET_TYPE_DGRAM: 01269 buf->info = (buffer_info_t)(B_DIR_DOWN + B_FROM_APP + B_TO_UDP); 01270 break; 01271 01272 case SOCKET_TYPE_RAW: 01273 if (inet_pcb->protocol == IPV6_NH_ICMPV6) { 01274 if (buffer_data_length(buf) < 4) { 01275 ret_val = -6; 01276 goto fail; 01277 } 01278 uint8_t *ptr = buffer_data_pointer(buf); 01279 buf->options .type = ptr[0]; 01280 buf->options .code = ptr[1]; 01281 buffer_data_strip_header(buf, 4); 01282 buf->info = (buffer_info_t)(B_DIR_DOWN + B_FROM_APP + B_TO_ICMP); 01283 } else { 01284 buf->options .type = inet_pcb->protocol ; 01285 buf->info = (buffer_info_t)(B_DIR_DOWN + B_FROM_APP + B_TO_IPV6); 01286 } 01287 break; 01288 default: 01289 ret_val = -1; 01290 goto fail; 01291 } 01292 01293 /* If no address in packet info, use bound address, if any. Set before interface selection - 01294 * socket_interface_determine could otherwise auto-select source as a side-effect. */ 01295 if (buf->src_sa .addr_type == ADDR_NONE && !addr_ipv6_equal(inet_pcb->local_address , ns_in6addr_any)) { 01296 memcpy(buf->src_sa .address , inet_pcb->local_address , 16); 01297 buf->src_sa .addr_type = ADDR_IPV6 ; 01298 } 01299 01300 /* If address is specified manually we must validate that the 01301 * address is valid in one of the available interfaces 01302 * */ 01303 if (buf->src_sa .addr_type == ADDR_IPV6 && 01304 protcol_interface_address_compare(NULL, buf->src_sa .address ) != 0) { 01305 tr_warn("Specified source address %s is not valid",trace_ipv6(buf->src_sa .address )); 01306 ret_val = -3; 01307 goto fail; 01308 } 01309 01310 /** 01311 * Select outgoing interface for this message 01312 */ 01313 protocol_interface_info_entry_t *cur_interface; 01314 if (interface_id > 0) { 01315 cur_interface = protocol_stack_interface_info_get_by_id(interface_id); 01316 } else { 01317 cur_interface = socket_interface_determine(socket_ptr, buf); 01318 } 01319 01320 if (!cur_interface) { 01321 tr_warn("sendto:No interface"); 01322 ret_val = -4; 01323 goto fail; 01324 } 01325 01326 buf->interface = cur_interface; 01327 01328 /** 01329 * Link-specific configuration 01330 */ 01331 buf->options .ll_security_bypass_tx = (inet_pcb->link_layer_security == 0); 01332 if (socket_ptr->broadcast_pan > 0) { 01333 buf->link_specific.ieee802_15_4.useDefaultPanId = false; 01334 buf->link_specific.ieee802_15_4.dstPanId = 0xffff; 01335 } 01336 01337 /** 01338 * Set Hop Limit 01339 */ 01340 socket_inet_pcb_set_buffer_hop_limit(inet_pcb, buf, msg_hoplimit); 01341 /** 01342 * Flow label set 01343 */ 01344 buf->options .flow_label = inet_pcb->flow_label; 01345 01346 /** 01347 * Select source address for this message 01348 */ 01349 if (buf->src_sa .addr_type == ADDR_NONE ) { 01350 const uint8_t *ipv6_ptr = addr_select_source(cur_interface, buf->dst_sa .address , inet_pcb->addr_preferences); 01351 if (!ipv6_ptr) { 01352 tr_warn("No address"); 01353 ret_val = -3; 01354 goto fail; 01355 } 01356 01357 memcpy(buf->src_sa .address , ipv6_ptr, 16); 01358 buf->src_sa .addr_type = ADDR_IPV6 ; 01359 } 01360 01361 buf->src_sa .port = inet_pcb->local_port ; 01362 01363 protocol_push(buf); 01364 01365 /* TCP jumps back to here */ 01366 success: 01367 if (flags & NS_MSG_LEGACY0) { 01368 return 0; 01369 } else { 01370 return payload_length; 01371 } 01372 01373 fail: 01374 tr_warn("fail: socket_buffer_sendmsg"); 01375 if (buf) 01376 { 01377 buffer_free(buf); 01378 } 01379 01380 return ret_val; 01381 } 01382 01383 void socket_tx_buffer_event_and_free(buffer_t *buf, uint8_t status) 01384 { 01385 buf = socket_tx_buffer_event(buf, status); 01386 if (buf) { 01387 buffer_free(buf); 01388 } 01389 } 01390 01391 buffer_t *socket_tx_buffer_event(buffer_t *buf, uint8_t status) 01392 { 01393 /* TODO here - if not a locally generated packet, and it's a TX_FAIL 01394 * (when we finally implement it), should probably generate ICMP 01395 * address unreachable. (Kind of needed if address resolution was skipped 01396 * and we mapped straight to MAC address). 01397 */ 01398 01399 /* Suppress events once socket orphaned */ 01400 if (!buf->socket || (buf->socket ->flags & (SOCKET_FLAG_PENDING|SOCKET_FLAG_CLOSED))) { 01401 return buf; 01402 } 01403 01404 protocol_interface_info_entry_t *cur_interface = buf->interface ; 01405 01406 socket_event_push(status, buf->socket , cur_interface ? cur_interface->id : -1, buf->session_ptr, buf->payload_length ); 01407 01408 return buf; 01409 } 01410 01411 static void mc_group_free(inet_pcb_t *inet_pcb, inet_group_t *mc) 01412 { 01413 protocol_interface_info_entry_t *cur_interface = protocol_stack_interface_info_get_by_id(mc->interface_id); 01414 if (cur_interface) { 01415 addr_delete_group(cur_interface, mc->group_addr); 01416 } 01417 01418 ns_list_remove(&inet_pcb->mc_groups, mc); 01419 ns_dyn_mem_free(mc); 01420 } 01421 01422 /* 01423 * validate that socket backlog allows new connection. 01424 * Incoming socket needs to be listening socket. 01425 * 01426 * \return true if incoming connection can proceed 01427 * */ 01428 bool socket_validate_listen_backlog(const socket_t *socket_ptr) 01429 { 01430 if (!(socket_ptr->flags & SOCKET_LISTEN_STATE)) { 01431 return false; 01432 } 01433 01434 return ns_list_count(&socket_ptr->u.live.queue) < socket_ptr->listen_backlog ; 01435 } 01436 01437 inet_pcb_t *socket_inet_pcb_free(inet_pcb_t *inet_pcb) 01438 { 01439 if (inet_pcb) { 01440 ns_list_foreach_safe(inet_group_t, mc, &inet_pcb->mc_groups) { 01441 mc_group_free(inet_pcb, mc); 01442 } 01443 ns_dyn_mem_free(inet_pcb); 01444 } 01445 return NULL; 01446 } 01447 01448 int8_t socket_inet_pcb_join_group(inet_pcb_t *inet_pcb, int8_t interface_id, const uint8_t group[static 16]) 01449 { 01450 ns_list_foreach(inet_group_t, mc, &inet_pcb->mc_groups) { 01451 if ((interface_id == 0 || mc->interface_id == interface_id) && addr_ipv6_equal(mc->group_addr, group)) { 01452 return -3; 01453 } 01454 } 01455 if (interface_id == 0) { 01456 ipv6_route_t *route = ipv6_route_choose_next_hop(group, -1, NULL); 01457 if (!route) { 01458 return -3; 01459 } 01460 interface_id = route->info.interface_id; 01461 } 01462 protocol_interface_info_entry_t *cur_interface = protocol_stack_interface_info_get_by_id(interface_id); 01463 if (!cur_interface) { 01464 return -3; 01465 } 01466 inet_group_t *mc = ns_dyn_mem_alloc(sizeof *mc); 01467 if (!mc) { 01468 return -3; 01469 } 01470 memcpy(mc->group_addr, group, 16); 01471 mc->interface_id = interface_id; 01472 if (!addr_add_group(cur_interface, group)) { 01473 /* This could also happen due to being an implicit group member, eg ff02::1 */ 01474 /* In that case, doesn't seem unreasonable to return the same error as "already a member on this socket" */ 01475 ns_dyn_mem_free(mc); 01476 return -3; 01477 } 01478 01479 ns_list_add_to_end(&inet_pcb->mc_groups, mc); 01480 return 0; 01481 } 01482 01483 int8_t socket_inet_pcb_leave_group(inet_pcb_t *inet_pcb, int8_t interface_id, const uint8_t group[static 16]) 01484 { 01485 inet_group_t *mc = NULL; 01486 ns_list_foreach(inet_group_t, cur, &inet_pcb->mc_groups) { 01487 if ((interface_id == 0 || cur->interface_id == interface_id) && addr_ipv6_equal(cur->group_addr, group)) { 01488 mc = cur; 01489 break; 01490 } 01491 } 01492 if (!mc) { 01493 return -3; 01494 } 01495 01496 mc_group_free(inet_pcb, mc); 01497 01498 return 0; 01499 } 01500 01501 struct protocol_interface_info_entry *socket_interface_determine(const socket_t *socket_ptr, buffer_t *buf) 01502 { 01503 protocol_interface_info_entry_t *cur_interface; 01504 01505 /* Link or realm-local scope uses default interface id if set (as if dest scope id), else multicast if, else choose 6LoWPAN, else IPv6(Ethernet) */ 01506 /* Also for packets addressed to ourself (not needed any more - have loopback routes? */ 01507 if (addr_ipv6_scope(buf->dst_sa .address , NULL) <= IPV6_SCOPE_REALM_LOCAL) { 01508 if (socket_ptr->default_interface_id != -1) { 01509 cur_interface = protocol_stack_interface_info_get_by_id(socket_ptr->default_interface_id); 01510 if (cur_interface) { 01511 return cur_interface; 01512 } 01513 } 01514 } 01515 01516 /* Sockets can specify an interface for multicast packets */ 01517 if (addr_is_ipv6_multicast(buf->dst_sa .address ) && socket_ptr->inet_pcb ->multicast_if > 0) { 01518 cur_interface = protocol_stack_interface_info_get_by_id(socket_ptr->inet_pcb ->multicast_if); 01519 if (cur_interface && ipv6_buffer_route_to(buf, buf->dst_sa .address , cur_interface)) { 01520 return cur_interface; 01521 } else { 01522 return NULL; 01523 } 01524 } 01525 01526 /* Try a routing table entry for greater-than-realm scope */ 01527 if (addr_ipv6_scope(buf->dst_sa .address , NULL) > IPV6_SCOPE_REALM_LOCAL) { 01528 if (ipv6_buffer_route(buf)) { 01529 return buf->interface ; 01530 } 01531 } 01532 01533 /* Realm-local scope or lower now chooses an interface - 6LoWPAN default */ 01534 if (addr_ipv6_scope(buf->dst_sa .address , NULL) <= IPV6_SCOPE_REALM_LOCAL) { 01535 buf->interface = protocol_stack_interface_info_get(IF_6LoWPAN); 01536 if (buf->interface ) { 01537 return buf->interface ; 01538 } 01539 buf->interface = protocol_stack_interface_info_get(IF_IPV6); 01540 if (buf->interface ) { 01541 return buf->interface ; 01542 } 01543 return NULL; 01544 } 01545 01546 return NULL; 01547 }
Generated on Fri Jul 22 2022 04:53:58 by
 1.7.2
 1.7.2 
    