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
socket_api.c
00001 /* 00002 * Copyright (c) 2014-2019, 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_api.c 00019 * \brief Socket API for library model 00020 * 00021 * The socket API functions for library model 00022 */ 00023 00024 #include "nsconfig.h" 00025 #include "ns_types.h" 00026 #include "eventOS_scheduler.h" 00027 #include "platform/arm_hal_phy.h" 00028 #ifndef BUILD_LIBRARY 00029 #define BUILD_LIBRARY 00030 #endif 00031 #include "ns_address.h" 00032 #include "socket_api.h" 00033 #include "ns_trace.h" 00034 #include "string.h" 00035 #include "nsdynmemLIB.h" 00036 #include "Core/include/ns_socket.h" 00037 #include "NWK_INTERFACE/Include/protocol.h" 00038 #include "Common_Protocols/ipv6_constants.h" 00039 #include "Common_Protocols/ipv6_flow.h" 00040 #include "Common_Protocols/tcp.h" 00041 #include "Common_Protocols/udp.h" 00042 #include "common_functions.h" 00043 00044 #define TRACE_GROUP "sckA" 00045 00046 const uint8_t ns_in6addr_any[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; 00047 00048 int8_t socket_open(uint8_t protocol, uint16_t identifier, void (*passed_fptr)(void *)) 00049 { 00050 int8_t sid = -1; 00051 socket_family_t family; 00052 socket_type_t type; 00053 00054 switch (protocol) { 00055 case SOCKET_ICMP: 00056 family = SOCKET_FAMILY_IPV6; 00057 type = SOCKET_TYPE_RAW; 00058 protocol = IPV6_NH_ICMPV6; 00059 break; 00060 case SOCKET_UDP: 00061 family = SOCKET_FAMILY_IPV6; 00062 type = SOCKET_TYPE_DGRAM; 00063 protocol = IPV6_NH_UDP; 00064 break; 00065 #ifndef NO_TCP 00066 case SOCKET_TCP: 00067 family = SOCKET_FAMILY_IPV6; 00068 type = SOCKET_TYPE_STREAM; 00069 protocol = IPV6_NH_TCP; 00070 break; 00071 #endif /* NO_TCP */ 00072 case SOCKET_RAW: 00073 if (identifier > 0xff) { 00074 return -1; 00075 } 00076 family = SOCKET_FAMILY_IPV6; 00077 type = SOCKET_TYPE_RAW; 00078 protocol = identifier; 00079 break; 00080 default: 00081 return -1; 00082 } 00083 00084 switch (socket_create(family, type, protocol, &sid, identifier, passed_fptr, false)) { 00085 case eOK: 00086 return sid; 00087 case eBUSY: 00088 return -2; 00089 case eFALSE: 00090 default: 00091 break; 00092 } 00093 00094 return sid; 00095 } 00096 00097 int8_t socket_close(int8_t sid) 00098 { 00099 socket_t *socket = socket_pointer_get(sid); 00100 if (!socket) { 00101 return -1; 00102 } 00103 00104 socket_id_detach(sid); 00105 return 0; 00106 } 00107 00108 int8_t socket_listen(int8_t socket, uint8_t backlog) 00109 { 00110 #ifdef NO_TCP 00111 return -1; 00112 #else 00113 socket_t *socket_ptr = socket_pointer_get(socket); 00114 if (!socket_ptr || !socket_is_ipv6(socket_ptr) || socket_ptr->inet_pcb ->local_port == 0) { 00115 return -1; 00116 } 00117 00118 switch (socket_ptr->type) { 00119 case SOCKET_TYPE_STREAM: 00120 break; 00121 default: 00122 return -1; 00123 } 00124 00125 if (socket_ptr->u.live.fptr == NULL) { 00126 return -2; 00127 } 00128 00129 socket_ptr->flags |= SOCKET_LISTEN_STATE; 00130 if (backlog < 1) { 00131 backlog = 1; 00132 } else if (backlog > SOCKET_LISTEN_BACKLOG_MAX) { 00133 backlog = SOCKET_LISTEN_BACKLOG_MAX; 00134 } 00135 socket_ptr->listen_backlog = backlog; 00136 00137 return 0; 00138 #endif 00139 } 00140 00141 int8_t socket_accept(int8_t listen_socket_id, ns_address_t *addr, void (*passed_fptr)(void *)) 00142 { 00143 #ifdef NO_TCP 00144 return -1; 00145 #else 00146 socket_t *socket_ptr = socket_pointer_get(listen_socket_id); 00147 if (!socket_ptr || !socket_is_ipv6(socket_ptr) || !(socket_ptr->flags & SOCKET_LISTEN_STATE) || passed_fptr == NULL) { 00148 return -1; 00149 } 00150 00151 /* Queue contains both partial and complete connections - find a complete one */ 00152 socket_t *pending_socket = NULL; 00153 ns_list_foreach(socket_t, so, &socket_ptr->u.live.queue) { 00154 if (so->flags & SOCKET_FLAG_CONNECTED) { 00155 pending_socket = so; 00156 break; 00157 } 00158 } 00159 if (!pending_socket) { 00160 tr_warn("No pending complete connection for socket %d", listen_socket_id); 00161 return NS_EWOULDBLOCK; 00162 } 00163 00164 int8_t new_sid = socket_id_assign_and_attach(pending_socket); 00165 if (new_sid == -1) { 00166 tr_error("Socket id allocation failed, s=%d", listen_socket_id); 00167 return -1; 00168 } 00169 00170 // This takes it off the pending queue, and releases one reference count, 00171 // but the ID assignment above took one, so it stays live. 00172 socket_leave_pending_state(pending_socket, passed_fptr); 00173 00174 // Make a data-received event if anything already pending - some may expect this 00175 if (pending_socket->rcvq.data_bytes != 0) { 00176 socket_data_queued_event_push(pending_socket); 00177 } 00178 00179 if (addr) { 00180 addr->type = ADDRESS_IPV6; 00181 memcpy(addr->address, pending_socket->inet_pcb ->remote_address , 16); 00182 addr->identifier = pending_socket->inet_pcb ->remote_port ; 00183 } 00184 00185 return new_sid; 00186 #endif 00187 } 00188 00189 int8_t socket_shutdown(int8_t socket, uint8_t how) 00190 { 00191 #ifdef NO_TCP 00192 return -1; 00193 #else 00194 socket_t *socket_ptr = socket_pointer_get(socket); 00195 if (!socket_ptr || !socket_is_ipv6(socket_ptr)) { 00196 return -1; 00197 } 00198 00199 if (socket_ptr->type != SOCKET_TYPE_STREAM) { 00200 return -1; 00201 } 00202 00203 if (!(socket_ptr->flags & SOCKET_FLAG_CONNECTED)) { 00204 return -2; 00205 } 00206 00207 uint8_t flags; 00208 00209 switch (how) { 00210 case SOCKET_SHUT_WR: 00211 flags = SOCKET_FLAG_SHUT_WR; 00212 break; 00213 case SOCKET_SHUT_RD: 00214 flags = SOCKET_FLAG_CANT_RECV_MORE; 00215 break; 00216 case SOCKET_SHUT_RDWR: 00217 flags = SOCKET_FLAG_CANT_RECV_MORE | SOCKET_FLAG_SHUT_WR; 00218 break; 00219 default: 00220 return -1; 00221 } 00222 00223 socket_ptr->flags |= flags; 00224 00225 // Take care never to put tcp_info in local variable - these calls can delete it 00226 int8_t ret = 0; 00227 00228 // If we've shutdown writing, signal close to TCP if it exists 00229 if (tcp_info(socket_ptr->inet_pcb ) && (flags & SOCKET_FLAG_SHUT_WR)) { 00230 switch (tcp_session_close(tcp_info(socket_ptr->inet_pcb ))) { 00231 case TCP_ERROR_NO_ERROR: 00232 break; 00233 default: 00234 ret = -1; 00235 break; 00236 } 00237 } 00238 00239 // Likewise for the read shutdown 00240 if (flags & SOCKET_FLAG_CANT_RECV_MORE) { 00241 if (tcp_info(socket_ptr->inet_pcb )) { 00242 switch (tcp_session_shutdown_read(tcp_info(socket_ptr->inet_pcb ))) { 00243 case TCP_ERROR_NO_ERROR: 00244 break; 00245 default: 00246 ret = -1; 00247 break; 00248 } 00249 } 00250 // Note sockbuf flush after tcp shutdown - this allows TCP to see 00251 // that we are binning unread data, and send a RESET to indicate. 00252 sockbuf_flush(&socket_ptr->rcvq); 00253 } 00254 00255 return ret; 00256 #endif 00257 } 00258 00259 int8_t socket_getsockname(int8_t socket, ns_address_t *address) 00260 { 00261 00262 const socket_t *socket_ptr = socket_pointer_get(socket); 00263 if (!socket_ptr || !socket_is_ipv6(socket_ptr)) { 00264 return -1; 00265 } 00266 00267 const inet_pcb_t *inet_pcb = socket_ptr->inet_pcb ; 00268 address->identifier = inet_pcb->local_port ; 00269 address->type = ADDRESS_IPV6; 00270 memcpy(address->address, inet_pcb->local_address , 16); 00271 00272 return 0; 00273 } 00274 00275 int8_t socket_getpeername(int8_t socket, ns_address_t *address) 00276 { 00277 const socket_t *socket_ptr = socket_pointer_get(socket); 00278 if (!socket_ptr || !socket_is_ipv6(socket_ptr)) { 00279 return -1; 00280 } 00281 00282 const inet_pcb_t *inet_pcb = socket_ptr->inet_pcb ; 00283 address->identifier = inet_pcb->remote_port ; 00284 address->type = ADDRESS_IPV6; 00285 memcpy(address->address, inet_pcb->remote_address , 16); 00286 00287 if (addr_ipv6_equal(inet_pcb->remote_address , ns_in6addr_any)) { 00288 return -2; 00289 } 00290 00291 return 0; 00292 } 00293 00294 /* Extracts data from queue, copying to msg->msg_iov. 00295 * Data is removed from queue. msg->msg_iov pointers and lengths not modified. 00296 * msg->flags gets NS_MSG_TRUNC set if a datagram was truncated. 00297 * For non-streams, will return actual datagram length if flags & NS_MSG_TRUNC. 00298 * Otherwise, returns amount read. 00299 */ 00300 static uint_fast16_t socket_copy_queue_to_user(sockbuf_t *sb, ns_msghdr_t *msg, int flags, bool stream) 00301 { 00302 uint_fast16_t retVal = 0; 00303 00304 const ns_iovec_t *iovec_ptr = msg->msg_iov; 00305 uint_fast16_t iovec_cnt = msg->msg_iovlen; 00306 00307 uint8_t *out_ptr = iovec_ptr->iov_base; 00308 uint_fast16_t out_len = iovec_ptr->iov_len; 00309 buffer_t *buf_src = ns_list_get_first(&sb->bufs); 00310 const uint8_t *in_ptr = buffer_data_pointer(buf_src); 00311 uint_fast16_t in_len = buffer_data_length(buf_src); 00312 00313 for (;;) { 00314 /* Compute amount to copy in this chunk - smaller of current input and output block */ 00315 uint_fast16_t len = in_len; 00316 if (len > out_len) { 00317 len = out_len; 00318 } 00319 00320 memcpy(out_ptr, in_ptr, len); 00321 retVal += len; 00322 00323 /* Advance input pointer, consume buffer */ 00324 in_ptr += len; 00325 in_len -= len; 00326 if (!(flags & NS_MSG_PEEK)) { 00327 buffer_data_strip_header(buf_src, len); 00328 sb->data_bytes -= len; 00329 } 00330 if (in_len == 0) { 00331 /* Drop this buffer from queue, and advance to next buffer if stream */ 00332 if (flags & NS_MSG_PEEK) { 00333 buf_src = stream ? ns_list_get_next(&sb->bufs, buf_src) : NULL; 00334 } else { 00335 sockbuf_drop_first(sb); 00336 buf_src = stream ? ns_list_get_first(&sb->bufs) : NULL; 00337 } 00338 if (!buf_src) { 00339 break; 00340 } 00341 in_ptr = buffer_data_pointer(buf_src); 00342 in_len = buffer_data_length(buf_src); 00343 } 00344 00345 /* There's still more input - advance output pointer */ 00346 out_ptr += len; 00347 out_len -= len; 00348 if (out_len == 0) { 00349 /* Advance to next vector */ 00350 if (--iovec_cnt == 0) { 00351 break; 00352 } 00353 iovec_ptr++; 00354 out_ptr = iovec_ptr->iov_base; 00355 out_len = iovec_ptr->iov_len; 00356 } 00357 } 00358 00359 /* If there was anything left in buf_src, for not-stream need to drop it now */ 00360 if (buf_src && !stream) { 00361 msg->msg_flags |= NS_MSG_TRUNC; 00362 if (flags & NS_MSG_TRUNC) { 00363 // Return actual length, not read length 00364 retVal += in_len; 00365 } 00366 if (!(flags & NS_MSG_PEEK)) { 00367 sockbuf_drop_first(sb); 00368 } 00369 } 00370 return retVal; 00371 } 00372 00373 static uint8_t *socket_cmsg_ipv6_header_set(ns_cmsghdr_t *cmsg, uint8_t type, uint16_t length) 00374 { 00375 cmsg->cmsg_level = SOCKET_IPPROTO_IPV6; 00376 cmsg->cmsg_type = type; 00377 cmsg->cmsg_len = NS_CMSG_LEN(length); 00378 return NS_CMSG_DATA(cmsg); 00379 } 00380 00381 int16_t socket_read(int8_t socket, ns_address_t *src_addr, uint8_t *buffer, uint16_t length) 00382 { 00383 return socket_recvfrom(socket, buffer, length, NS_MSG_LEGACY0, src_addr); 00384 } 00385 00386 int16_t socket_recv(int8_t socket, void *buffer, uint16_t length, int flags) 00387 { 00388 return socket_recvfrom(socket, buffer, length, flags, NULL); 00389 } 00390 00391 int16_t socket_recvfrom(int8_t socket, void *buffer, uint16_t length, int flags, ns_address_t *src_addr) 00392 { 00393 ns_iovec_t msg_iov; 00394 ns_msghdr_t msghdr; 00395 00396 //Init message payload vector 00397 msg_iov.iov_base = buffer; 00398 msg_iov.iov_len = length; 00399 00400 //Set messages name buffer 00401 msghdr.msg_name = src_addr; 00402 msghdr.msg_namelen = src_addr ? sizeof(ns_address_t) : 0; 00403 msghdr.msg_iov = &msg_iov; 00404 msghdr.msg_iovlen = 1; 00405 msghdr.msg_control = NULL; 00406 msghdr.msg_controllen = 0; 00407 00408 return socket_recvmsg(socket, &msghdr, flags); 00409 } 00410 00411 static uint_fast16_t copy_ancillary_to_user(ns_msghdr_t *msg, uint_fast16_t written_data, uint8_t type, void *data_ptr, uint16_t length) 00412 { 00413 if (!msg->msg_control || msg->msg_controllen < (written_data + NS_CMSG_SPACE(length))) { 00414 msg->msg_flags |= NS_MSG_CTRUNC; 00415 return written_data; 00416 } 00417 uint8_t *msg_start = msg->msg_control; 00418 uint8_t *data_start = socket_cmsg_ipv6_header_set((ns_cmsghdr_t *)(msg_start + written_data), type, length); 00419 memcpy(data_start, data_ptr, length); 00420 00421 return (written_data + NS_CMSG_SPACE(length)); 00422 } 00423 00424 int16_t socket_recvmsg(int8_t socket, ns_msghdr_t *msg, int flags) 00425 { 00426 if (!msg) { 00427 return -1; 00428 } 00429 msg->msg_flags = 0; 00430 /** 00431 * Validate socket id 00432 */ 00433 socket_t *socket_ptr = socket_pointer_get(socket); 00434 if (!socket_ptr) { 00435 return -1; 00436 } 00437 00438 //Read Buffer 00439 buffer_t *socket_buf = ns_list_get_first(&socket_ptr->rcvq.bufs); 00440 if (!socket_buf) { 00441 if (flags & NS_MSG_LEGACY0) { 00442 return 0; 00443 } else { 00444 return (socket_ptr->flags & SOCKET_FLAG_CANT_RECV_MORE) ? 0 : NS_EWOULDBLOCK; 00445 } 00446 } 00447 00448 /** 00449 * Validate message payload buffer size 00450 */ 00451 if (!socket_message_validate_iov(msg, NULL)) { 00452 return -1; 00453 } 00454 00455 /** 00456 * Write Ancillary 00457 */ 00458 uint_fast16_t cmsg_written = 0; 00459 if (socket_ptr->inet_pcb ->recvpktinfo) { 00460 ns_in6_pktinfo_t pktinfo; 00461 pktinfo.ipi6_ifindex = socket_buf->interface ->id; 00462 memcpy(pktinfo.ipi6_addr, socket_buf->dst_sa .address , 16); 00463 cmsg_written = copy_ancillary_to_user(msg, cmsg_written, SOCKET_IPV6_PKTINFO, &pktinfo, sizeof pktinfo); 00464 } 00465 00466 if (socket_ptr->inet_pcb ->recvhoplimit) { 00467 int16_t hoplimit = socket_buf->options .hop_limit ; 00468 cmsg_written = copy_ancillary_to_user(msg, cmsg_written, SOCKET_IPV6_HOPLIMIT, &hoplimit, sizeof hoplimit); 00469 } 00470 00471 if (socket_ptr->inet_pcb ->recvtclass) { 00472 int16_t tclass = socket_buf->options .traffic_class ; 00473 cmsg_written = copy_ancillary_to_user(msg, cmsg_written, SOCKET_IPV6_TCLASS, &tclass, sizeof tclass); 00474 } 00475 msg->msg_controllen = cmsg_written; 00476 00477 ns_address_t *src_addr = msg->msg_name; 00478 //Read src address 00479 if (src_addr) { 00480 00481 if (msg->msg_namelen != sizeof(ns_address_t)) { 00482 return -1; 00483 } 00484 00485 src_addr->identifier = socket_buf->src_sa .port ; 00486 src_addr->type = ADDRESS_IPV6; 00487 memcpy(src_addr->address, socket_buf->src_sa .address , 16); 00488 } 00489 00490 //Read Data to Buffer 00491 int16_t len = socket_copy_queue_to_user(&socket_ptr->rcvq, msg, flags, socket_ptr->type == SOCKET_TYPE_STREAM); 00492 00493 if (len > 0 && !(flags & NS_MSG_PEEK) && socket_is_ipv6(socket_ptr) && tcp_info(socket_ptr->inet_pcb )) { 00494 tcp_session_data_received(tcp_info(socket_ptr->inet_pcb )); 00495 } 00496 00497 return len; 00498 } 00499 00500 int16_t socket_sendmsg(int8_t socket, const ns_msghdr_t *msg, int flags) 00501 { 00502 if (!msg) { 00503 return -1; 00504 } 00505 00506 return socket_buffer_sendmsg(socket, NULL, msg, flags); 00507 } 00508 00509 int16_t socket_sendto(int8_t socket, const ns_address_t *address, const void *buffer, uint16_t length) 00510 { 00511 ns_iovec_t data_vector; 00512 ns_msghdr_t msghdr; 00513 00514 //SET IOV vector 00515 data_vector.iov_base = (void *) buffer; 00516 data_vector.iov_len = length; 00517 00518 //Set message name 00519 msghdr.msg_name = (void *) address; 00520 msghdr.msg_namelen = address ? sizeof(ns_address_t) : 0; 00521 msghdr.msg_iov = &data_vector; 00522 msghdr.msg_iovlen = 1; 00523 //No ancillary data 00524 msghdr.msg_control = NULL; 00525 msghdr.msg_controllen = 0; 00526 00527 return socket_sendmsg(socket, &msghdr, NS_MSG_LEGACY0); 00528 } 00529 00530 int8_t socket_connect(int8_t socket, ns_address_t *address, uint8_t randomly_take_src_number) 00531 { 00532 socket_t *socket_ptr = socket_pointer_get(socket); 00533 if (!address || !socket_ptr || !socket_is_ipv6(socket_ptr)) { 00534 return -1; 00535 } 00536 00537 switch (socket_ptr->type) { 00538 case SOCKET_TYPE_STREAM: 00539 case SOCKET_TYPE_DGRAM: 00540 break; 00541 default: 00542 return -5; 00543 } 00544 00545 if (socket_ptr->flags & SOCKET_LISTEN_STATE) { 00546 return -3; 00547 } 00548 00549 if (socket_ptr->flags & (SOCKET_FLAG_CONNECTED | SOCKET_FLAG_CONNECTING)) { 00550 return -4; 00551 } 00552 00553 inet_pcb_t *inet_pcb = socket_ptr->inet_pcb ; 00554 00555 /* Save hash computation time in IP layer by using a random flow for connected sockets */ 00556 if (inet_pcb->flow_label == IPV6_FLOW_AUTOGENERATE || 00557 (inet_pcb->flow_label == IPV6_FLOW_UNSPECIFIED && ipv6_flow_auto_label)) { 00558 inet_pcb->flow_label = ipv6_flow_random(); 00559 } 00560 00561 // Choose local port if not already bound 00562 (void) randomly_take_src_number; 00563 if (inet_pcb->local_port == 0) { 00564 inet_pcb->local_port = socket_generate_random_port(inet_pcb->protocol ); 00565 if (inet_pcb->local_port == 0) { 00566 return -7; 00567 } 00568 } 00569 00570 // Choose local address if not already bound 00571 int8_t status = socket_bind2addrsel(socket, address); 00572 switch (status) { 00573 case 0: //OK 00574 case -3: // already bound 00575 break; 00576 case -1: // invalid param 00577 case -2: //mem alloc fail 00578 return status; 00579 case -4: // no interface 00580 case -5: // addr selection fails 00581 default: 00582 return -7; 00583 } 00584 00585 memcpy(inet_pcb->remote_address , address->address, 16); 00586 inet_pcb->remote_port = address->identifier; 00587 status = 0; 00588 00589 #ifndef NO_TCP 00590 if (socket_ptr->type == SOCKET_TYPE_STREAM) { 00591 if (tcp_info(socket_ptr->inet_pcb )) { 00592 status = -4; // shouldn't happen - flags should cover it 00593 goto exit; 00594 } 00595 00596 //Allocate session here 00597 tcp_session_t *tcp_session = tcp_session_ptr_allocate(socket_ptr->inet_pcb , NULL); 00598 if (!tcp_session) { 00599 status = -2; 00600 goto exit; 00601 } 00602 00603 if (tcp_session_open(tcp_session) != TCP_ERROR_NO_ERROR) { 00604 tcp_session_ptr_free(tcp_session); 00605 status = -2; 00606 goto exit; 00607 } 00608 00609 socket_ptr->flags |= SOCKET_FLAG_CONNECTING; 00610 } 00611 #endif 00612 exit: 00613 if (status != 0) { 00614 memcpy(inet_pcb->remote_address , ns_in6addr_any, 16); 00615 inet_pcb->remote_port = 0; 00616 } 00617 return status; 00618 } 00619 00620 int8_t socket_bind(int8_t socket, const ns_address_t *address) 00621 { 00622 socket_t *socket_ptr = socket_pointer_get(socket); 00623 if (!address || !socket_ptr || !socket_is_ipv6(socket_ptr)) { 00624 return -1; 00625 } 00626 00627 switch (socket_ptr->type) { 00628 case SOCKET_TYPE_STREAM: 00629 case SOCKET_TYPE_DGRAM: 00630 break; 00631 default: 00632 return -5; 00633 } 00634 00635 inet_pcb_t *inet_pcb = socket_ptr->inet_pcb ; 00636 00637 // are they specifying a new port? 00638 if (address->identifier && address->identifier != inet_pcb->local_port ) { 00639 // don't let them do so if a port was already chosen 00640 if (inet_pcb->local_port != 0) { 00641 return -4; 00642 } 00643 if (socket_port_validate(address->identifier, inet_pcb->protocol ) == eOK) { 00644 inet_pcb->local_port = address->identifier; 00645 } else { 00646 return -2; 00647 } 00648 } 00649 // we don't actually allocate ephemeral ports until later when we know 00650 // the destination (potentially useful to follow RFC 6056 some day) 00651 00652 // are they specifying a new address? 00653 if (!addr_ipv6_equal(address->address, ns_in6addr_any) && !addr_ipv6_equal(address->address, inet_pcb->local_address )) { 00654 // don't let them do so if an address was already chosen 00655 if (!addr_ipv6_equal(inet_pcb->local_address , ns_in6addr_any)) { 00656 return -4; 00657 } 00658 00659 if (protocol_interface_address_compare(address->address) != 0) { 00660 return -3; 00661 } 00662 00663 memcpy(inet_pcb->local_address , address->address, 16); 00664 } 00665 00666 return 0; 00667 } 00668 00669 int8_t socket_bind2addrsel(int8_t socket, const ns_address_t *dst_address) 00670 { 00671 protocol_interface_info_entry_t *if_info; 00672 00673 socket_t *socket_ptr = socket_pointer_get(socket); 00674 if (!dst_address || !socket_ptr || !socket_is_ipv6(socket_ptr)) { 00675 return -1; 00676 } 00677 00678 switch (socket_ptr->type) { 00679 case SOCKET_TYPE_STREAM: 00680 case SOCKET_TYPE_DGRAM: 00681 break; 00682 default: 00683 return -6; 00684 } 00685 00686 inet_pcb_t *inet_pcb = socket_ptr->inet_pcb ; 00687 00688 if (!addr_ipv6_equal(inet_pcb->local_address , ns_in6addr_any)) { 00689 return -3; 00690 } 00691 00692 // select source address based on destination 00693 buffer_t *buf = buffer_get(20); 00694 if (!buf) { 00695 return -2; 00696 } 00697 00698 memcpy(&buf->dst_sa .address , dst_address->address, 16); 00699 buf->dst_sa .port = dst_address->identifier; 00700 if_info = socket_interface_determine(socket_ptr, buf); 00701 00702 if (!if_info) { 00703 tr_error("socket_bind2addrsel: No interface"); 00704 buffer_free(buf); 00705 return -4; 00706 } 00707 00708 if (addr_interface_select_source(if_info, inet_pcb->local_address , dst_address->address, inet_pcb->addr_preferences) < 0) { 00709 tr_error("src_addr selection failed"); 00710 buffer_free(buf); 00711 return -5; 00712 } 00713 00714 buffer_free(buf); 00715 00716 /* Could choose an ephemeral port here, but no point - see bind() */ 00717 00718 return 0; 00719 } 00720 00721 int16_t socket_send(int8_t socket, const void *buffer, uint16_t length) 00722 { 00723 return socket_sendto(socket, NULL, buffer, length); 00724 } 00725 00726 static int8_t ipv6_setsockopt(socket_t *socket_ptr, uint8_t opt_name, const void *opt_value, uint16_t opt_len) 00727 { 00728 inet_pcb_t *inet_pcb = socket_ptr->inet_pcb ; 00729 00730 switch (opt_name) { 00731 00732 /* These first few aren't really IPv6, but hey... */ 00733 case SOCKET_INTERFACE_SELECT: { 00734 if (opt_len != sizeof(int8_t)) { 00735 return -3; 00736 } 00737 int8_t interface_id = *(const int8_t *) opt_value; 00738 socket_ptr->default_interface_id = interface_id; 00739 00740 return 0; 00741 } 00742 case SOCKET_LINK_LAYER_SECURITY: { 00743 if (opt_len != sizeof(int8_t)) { 00744 return -3; 00745 } 00746 int8_t securityEnabled = *(const int8_t *) opt_value; 00747 inet_pcb->link_layer_security = securityEnabled; 00748 00749 return 0; 00750 } 00751 case SOCKET_BROADCAST_PAN: { 00752 if (opt_len != sizeof(int8_t)) { 00753 return -3; 00754 } 00755 socket_ptr->broadcast_pan = *(const int8_t *) opt_value; 00756 00757 return 0; 00758 } 00759 case SOCKET_IPV6_TCLASS: { 00760 /* Supporting TCP properly is fiddly, and not yet needed */ 00761 if (socket_ptr->type == SOCKET_TYPE_STREAM) { 00762 return -2; 00763 } 00764 00765 if (opt_len != sizeof(int16_t)) { 00766 return -3; 00767 } 00768 00769 int16_t tclass = *(const int16_t *) opt_value; 00770 if (tclass == -1) { 00771 inet_pcb->tclass = SOCKET_IPV6_TCLASS_DEFAULT; 00772 } else if (tclass >= 0 && tclass <= 255) { 00773 inet_pcb->tclass = tclass; 00774 } else { 00775 return -3; 00776 } 00777 00778 return 0; 00779 } 00780 case SOCKET_IPV6_FLOW_LABEL: { 00781 if (opt_len != sizeof(int32_t)) { 00782 return -3; 00783 } 00784 00785 int32_t flow = *(const int32_t *) opt_value; 00786 if (flow >= -2 && flow <= 0xfffff) { 00787 inet_pcb->flow_label = flow; 00788 } else { 00789 return -3; 00790 } 00791 00792 return 0; 00793 } 00794 case SOCKET_IPV6_UNICAST_HOPS: { 00795 if (opt_len != sizeof(int16_t)) { 00796 return -3; 00797 } 00798 00799 int16_t hops = *(const int16_t *) opt_value; 00800 if (hops >= -1 && hops <= 255) { 00801 inet_pcb->unicast_hop_limit = hops; 00802 } else { 00803 return -3; 00804 } 00805 00806 return 0; 00807 } 00808 case SOCKET_IPV6_MULTICAST_HOPS: { 00809 if (opt_len != sizeof(int16_t)) { 00810 return -3; 00811 } 00812 00813 int16_t hops = *(const int16_t *) opt_value; 00814 if (hops == -1) { 00815 inet_pcb->multicast_hop_limit = 1; 00816 } else if (hops >= 0 && hops <= 255) { 00817 inet_pcb->multicast_hop_limit = hops; 00818 } else { 00819 return -3; 00820 } 00821 00822 return 0; 00823 } 00824 case SOCKET_IPV6_MULTICAST_IF: { 00825 if (opt_len != sizeof(int8_t)) { 00826 return -3; 00827 } 00828 int8_t interface_id = *(const int8_t *) opt_value; 00829 if (interface_id != 0 && !protocol_stack_interface_info_get_by_id(interface_id)) { 00830 return -3; 00831 } 00832 inet_pcb->multicast_if = interface_id; 00833 00834 return 0; 00835 } 00836 case SOCKET_IPV6_MULTICAST_LOOP: { 00837 if (opt_len != sizeof(bool)) { 00838 return -3; 00839 } 00840 inet_pcb->multicast_loop = *(const bool *) opt_value; 00841 00842 return 0; 00843 } 00844 case SOCKET_IPV6_JOIN_GROUP: 00845 case SOCKET_IPV6_LEAVE_GROUP: { 00846 if (opt_len != sizeof(ns_ipv6_mreq_t)) { 00847 return -3; 00848 } 00849 const ns_ipv6_mreq_t *mreq = opt_value; 00850 if (!addr_is_ipv6_multicast(mreq->ipv6mr_multiaddr)) { 00851 return -3; 00852 } 00853 if (opt_name == SOCKET_IPV6_JOIN_GROUP) { 00854 return socket_inet_pcb_join_group(inet_pcb, mreq->ipv6mr_interface, mreq->ipv6mr_multiaddr); 00855 } else { 00856 return socket_inet_pcb_leave_group(inet_pcb, mreq->ipv6mr_interface, mreq->ipv6mr_multiaddr); 00857 } 00858 } 00859 case SOCKET_IPV6_ADDR_PREFERENCES: { 00860 if (opt_len != sizeof(uint32_t)) { 00861 return -3; 00862 } 00863 00864 uint32_t flags = *(const uint32_t *) opt_value; 00865 00866 /* Fault contradictory flags */ 00867 if (flags & (flags >> 16)) { 00868 return -3; 00869 } 00870 00871 /* Set specified flags, clear opposite flags */ 00872 inet_pcb->addr_preferences |= flags; 00873 inet_pcb->addr_preferences &= ~((flags >> 16) | (flags << 16)); 00874 00875 return 0; 00876 } 00877 #ifndef NO_IPV6_PMTUD 00878 case SOCKET_IPV6_USE_MIN_MTU: { 00879 if (opt_len != sizeof(int8_t)) { 00880 return -3; 00881 } 00882 00883 int8_t mode = *(const int8_t *) opt_value; 00884 if (mode < -1 || mode > 1) { 00885 return -3; 00886 } 00887 00888 inet_pcb->use_min_mtu = mode; 00889 00890 return 0; 00891 } 00892 #endif 00893 #ifndef NO_IP_FRAGMENT_TX 00894 case SOCKET_IPV6_DONTFRAG: { 00895 if (opt_len != sizeof(int8_t)) { 00896 return -3; 00897 } 00898 00899 int8_t mode = *(const int8_t *) opt_value; 00900 if (mode < 0 || mode > 1) { 00901 return -3; 00902 } 00903 00904 inet_pcb->dontfrag = mode; 00905 00906 return 0; 00907 } 00908 #endif 00909 /* Are there any users of this yet? Can we remove it? */ 00910 case SOCKET_IPV6_ADDRESS_SELECT: { 00911 if (opt_len != sizeof(int16_t)) { 00912 return -3; 00913 } 00914 00915 int16_t address_mode = *(const int16_t *) opt_value; 00916 00917 if (address_mode == SOCKET_SRC_ADDRESS_MODE_PRIMARY) { 00918 inet_pcb->addr_preferences |= SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT; 00919 inet_pcb->addr_preferences &= ~(uint32_t) SOCKET_IPV6_PREFER_SRC_6LOWPAN_LONG; 00920 } else if (address_mode == SOCKET_SRC_ADDRESS_MODE_SECONDARY) { 00921 inet_pcb->addr_preferences |= SOCKET_IPV6_PREFER_SRC_6LOWPAN_LONG; 00922 inet_pcb->addr_preferences &= ~(uint32_t) SOCKET_IPV6_PREFER_SRC_6LOWPAN_SHORT; 00923 } else { 00924 return -3; 00925 } 00926 00927 return 0; 00928 } 00929 00930 case SOCKET_IPV6_RECVPKTINFO: { 00931 if (opt_len != sizeof(bool)) { 00932 return -3; 00933 } 00934 inet_pcb->recvpktinfo = *(const bool *) opt_value; 00935 return 0; 00936 } 00937 case SOCKET_IPV6_RECVHOPLIMIT: { 00938 if (opt_len != sizeof(bool)) { 00939 return -3; 00940 } 00941 inet_pcb->recvhoplimit = *(const bool *) opt_value; 00942 return 0; 00943 } 00944 00945 case SOCKET_IPV6_RECVTCLASS: { 00946 if (opt_len != sizeof(bool)) { 00947 return -3; 00948 } 00949 inet_pcb->recvtclass = *(const bool *) opt_value; 00950 return 0; 00951 } 00952 default: 00953 return -2; 00954 } 00955 } 00956 00957 int8_t socket_setsockopt(int8_t socket, uint8_t level, uint8_t opt_name, const void *opt_value, uint16_t opt_len) 00958 { 00959 socket_t *socket_ptr = socket_pointer_get(socket); 00960 if (!opt_value || !socket_ptr) { 00961 return -1; 00962 } 00963 00964 if (level == SOCKET_IPPROTO_IPV6 && socket_is_ipv6(socket_ptr)) { 00965 return ipv6_setsockopt(socket_ptr, opt_name, opt_value, opt_len); 00966 } 00967 00968 if (level != SOCKET_SOL_SOCKET) { 00969 return -2; 00970 } 00971 00972 switch (opt_name) { 00973 case SOCKET_SO_SNDBUF: 00974 case SOCKET_SO_RCVBUF: { 00975 if (opt_len != sizeof(int32_t)) { 00976 return -3; 00977 } 00978 int32_t value = *(const int32_t *) opt_value; 00979 if (value < 0) { 00980 return -3; 00981 } 00982 sockbuf_t *sb = opt_name == SOCKET_SO_SNDBUF ? &socket_ptr->sndq 00983 : &socket_ptr->rcvq; 00984 return sockbuf_reserve(sb, value) ? 0 : -3; 00985 } 00986 case SOCKET_SO_SNDLOWAT: { 00987 if (opt_len != sizeof(int32_t)) { 00988 return -3; 00989 } 00990 int32_t value = *(const int32_t *) opt_value; 00991 if (value < 1) { 00992 return -3; 00993 } 00994 sockbuf_t *sb = &socket_ptr->sndq; 00995 if ((uint32_t) value > sb->data_byte_limit) { 00996 value = sb->data_byte_limit; 00997 } 00998 sb->low_water_mark = value; 00999 return 0; 01000 } 01001 default: 01002 return -2; 01003 } 01004 } 01005 01006 static union { 01007 int8_t s8; 01008 uint16_t u16; 01009 int16_t s16; 01010 uint32_t u32; 01011 int32_t s32; 01012 bool boolean; 01013 } opt_temp; 01014 01015 static int8_t ipv6_getsockopt(const socket_t *socket_ptr, uint8_t opt_name, const void **value, uint16_t *len) 01016 { 01017 const inet_pcb_t *inet_pcb = socket_ptr->inet_pcb ; 01018 01019 switch (opt_name) { 01020 case SOCKET_INTERFACE_SELECT: { 01021 const int8_t *p = &socket_ptr->default_interface_id; 01022 *value = p; 01023 *len = sizeof * p; 01024 break; 01025 } 01026 case SOCKET_LINK_LAYER_SECURITY: { 01027 const int8_t *p = &inet_pcb->link_layer_security; 01028 *value = p; 01029 *len = sizeof * p; 01030 break; 01031 } 01032 case SOCKET_BROADCAST_PAN: { 01033 const int8_t *p = &socket_ptr->broadcast_pan; 01034 *value = p; 01035 *len = sizeof * p; 01036 break; 01037 } 01038 case SOCKET_IPV6_TCLASS: { 01039 opt_temp.s16 = inet_pcb->tclass; 01040 *value = &opt_temp.s16; 01041 *len = sizeof(int16_t); 01042 break; 01043 } 01044 case SOCKET_IPV6_FLOW_LABEL: { 01045 opt_temp.s32 = inet_pcb->flow_label; 01046 *value = &opt_temp.s32; 01047 *len = sizeof(int32_t); 01048 break; 01049 } 01050 case SOCKET_IPV6_UNICAST_HOPS: { 01051 opt_temp.s16 = inet_pcb->unicast_hop_limit ; 01052 if (opt_temp.s16 == -1) { 01053 /* Hop limit is determined dynamically on TX - try to work out 01054 * a sensible number for the caller; we can't just say -1. 01055 */ 01056 opt_temp.s16 = UNICAST_HOP_LIMIT_DEFAULT; 01057 01058 /* Try to look at interface for connected sockets */ 01059 if (socket_ptr->type == SOCKET_TYPE_STREAM) { 01060 tcp_session_t *info = tcp_info(socket_ptr->inet_pcb ); 01061 if (info) { 01062 opt_temp.s16 = info->interface->cur_hop_limit; 01063 } 01064 } 01065 } 01066 *value = &opt_temp.s16; 01067 *len = sizeof(int16_t); 01068 break; 01069 } 01070 case SOCKET_IPV6_MULTICAST_HOPS: { 01071 opt_temp.s16 = inet_pcb->multicast_hop_limit; 01072 /* Unlike unicast hop limit, this can't be -1 */ 01073 *value = &opt_temp.s16; 01074 *len = sizeof(int16_t); 01075 break; 01076 } 01077 case SOCKET_IPV6_MULTICAST_IF: { 01078 opt_temp.s8 = inet_pcb->multicast_if; 01079 *value = &opt_temp.s8; 01080 *len = sizeof(int8_t); 01081 break; 01082 } 01083 case SOCKET_IPV6_MULTICAST_LOOP: { 01084 opt_temp.boolean = inet_pcb->multicast_loop; 01085 *value = &opt_temp.boolean; 01086 *len = sizeof(bool); 01087 break; 01088 } 01089 case SOCKET_IPV6_ADDR_PREFERENCES: { 01090 const uint32_t *p = &inet_pcb->addr_preferences; 01091 *value = p; 01092 *len = sizeof * p; 01093 break; 01094 } 01095 #ifndef NO_IPV6_PMTUD 01096 case SOCKET_IPV6_USE_MIN_MTU: { 01097 const int8_t *p = &inet_pcb->use_min_mtu ; 01098 *value = p; 01099 *len = sizeof * p; 01100 break; 01101 } 01102 #endif 01103 #ifndef NO_IP_FRAGMENT_TX 01104 case SOCKET_IPV6_DONTFRAG: { 01105 const int8_t *p = &inet_pcb->dontfrag; 01106 *value = p; 01107 *len = sizeof * p; 01108 break; 01109 } 01110 #endif 01111 case SOCKET_IPV6_RECVPKTINFO: 01112 opt_temp.boolean = inet_pcb->recvpktinfo; 01113 *value = &opt_temp.boolean; 01114 *len = sizeof(bool); 01115 break; 01116 case SOCKET_IPV6_RECVHOPLIMIT: 01117 opt_temp.boolean = inet_pcb->recvhoplimit; 01118 *value = &opt_temp.boolean; 01119 *len = sizeof(bool); 01120 break; 01121 case SOCKET_IPV6_RECVTCLASS: 01122 opt_temp.boolean = inet_pcb->recvtclass; 01123 *value = &opt_temp.boolean; 01124 *len = sizeof(bool); 01125 break; 01126 01127 default: 01128 return -2; 01129 } 01130 01131 return 0; 01132 } 01133 01134 int8_t socket_getsockopt(int8_t socket, uint8_t level, uint8_t opt_name, void *opt_value, uint16_t *opt_len) 01135 { 01136 const socket_t *socket_ptr = socket_pointer_get(socket); 01137 if (!opt_value || !opt_len || !socket_ptr) { 01138 return -1; 01139 } 01140 01141 const void *value; 01142 uint16_t len; 01143 01144 if (level == SOCKET_IPPROTO_IPV6 && socket_is_ipv6(socket_ptr)) { 01145 int8_t ret = ipv6_getsockopt(socket_ptr, opt_name, &value, &len); 01146 if (ret != 0) { 01147 return ret; 01148 } 01149 } else if (level == SOCKET_SOL_SOCKET) { 01150 switch (opt_name) { 01151 case SOCKET_SO_SNDBUF: 01152 opt_temp.s32 = socket_ptr->sndq.data_byte_limit; 01153 value = &opt_temp.s32; 01154 len = sizeof(int32_t); 01155 break; 01156 case SOCKET_SO_RCVBUF: 01157 opt_temp.s32 = socket_ptr->rcvq.data_byte_limit; 01158 value = &opt_temp.s32; 01159 len = sizeof(int32_t); 01160 break; 01161 case SOCKET_SO_SNDLOWAT: 01162 opt_temp.s32 = socket_ptr->rcvq.low_water_mark; 01163 value = &opt_temp.s32; 01164 len = sizeof(int32_t); 01165 break; 01166 default: 01167 return -2; 01168 } 01169 } else { 01170 return -2; 01171 } 01172 01173 if (*opt_len > len) { 01174 *opt_len = len; 01175 } 01176 01177 memcpy(opt_value, value, *opt_len); 01178 01179 return 0; 01180 } 01181 01182 ns_cmsghdr_t *NS_CMSG_NXTHDR(const ns_msghdr_t *msgh, const ns_cmsghdr_t *cmsg) 01183 { 01184 if (!cmsg) { 01185 return NS_CMSG_FIRSTHDR(msgh); 01186 } 01187 uint8_t *start_of_next_header = (uint8_t *)(cmsg) + NS_ALIGN_SIZE(cmsg->cmsg_len, CMSG_HEADER_ALIGN); 01188 uint8_t *end_of_next_header = start_of_next_header + NS_ALIGN_SIZE(sizeof(ns_cmsghdr_t), CMSG_DATA_ALIGN); 01189 if (end_of_next_header > (uint8_t *)(msgh)->msg_control + (msgh)->msg_controllen) { 01190 return NULL; 01191 } 01192 return (ns_cmsghdr_t *) start_of_next_header; 01193 } 01194
Generated on Tue Jul 12 2022 13:54:51 by
1.7.2