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
socket_api.c
00001 /* 00002 * Copyright (c) 2014-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_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/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 const socket_t *socket_ptr = socket_pointer_get(socket); 00262 if (!socket_ptr || !socket_is_ipv6(socket_ptr)) { 00263 return -1; 00264 } 00265 00266 const inet_pcb_t *inet_pcb = socket_ptr->inet_pcb ; 00267 address->identifier = inet_pcb->local_port ; 00268 address->type = ADDRESS_IPV6; 00269 memcpy(address->address, inet_pcb->local_address , 16); 00270 00271 return 0; 00272 } 00273 00274 int8_t socket_getpeername(int8_t socket, ns_address_t *address) 00275 { 00276 const socket_t *socket_ptr = socket_pointer_get(socket); 00277 if (!socket_ptr || !socket_is_ipv6(socket_ptr)) { 00278 return -1; 00279 } 00280 00281 const inet_pcb_t *inet_pcb = socket_ptr->inet_pcb ; 00282 address->identifier = inet_pcb->remote_port ; 00283 address->type = ADDRESS_IPV6; 00284 memcpy(address->address, inet_pcb->remote_address , 16); 00285 00286 if (addr_ipv6_equal(inet_pcb->remote_address , ns_in6addr_any)) { 00287 return -2; 00288 } 00289 00290 return 0; 00291 } 00292 00293 /* Extracts data from queue, copying to msg->msg_iov. 00294 * Data is removed from queue. msg->msg_iov pointers and lengths not modified. 00295 * msg->flags gets NS_MSG_TRUNC set if a datagram was truncated. 00296 * For non-streams, will return actual datagram length if flags & NS_MSG_TRUNC. 00297 * Otherwise, returns amount read. 00298 */ 00299 static uint_fast16_t socket_copy_queue_to_user(sockbuf_t *sb, ns_msghdr_t *msg, int flags, bool stream) 00300 { 00301 uint_fast16_t retVal = 0; 00302 00303 const ns_iovec_t *iovec_ptr = msg->msg_iov; 00304 uint_fast16_t iovec_cnt = msg->msg_iovlen; 00305 00306 uint8_t *out_ptr = iovec_ptr->iov_base; 00307 uint_fast16_t out_len = iovec_ptr->iov_len; 00308 buffer_t *buf_src = ns_list_get_first(&sb->bufs); 00309 const uint8_t *in_ptr = buffer_data_pointer(buf_src); 00310 uint_fast16_t in_len = buffer_data_length(buf_src); 00311 00312 for (;;) { 00313 /* Compute amount to copy in this chunk - smaller of current input and output block */ 00314 uint_fast16_t len = in_len; 00315 if (len > out_len) { 00316 len = out_len; 00317 } 00318 00319 memcpy(out_ptr, in_ptr, len); 00320 retVal += len; 00321 00322 /* Advance input pointer, consume buffer */ 00323 in_ptr += len; 00324 in_len -= len; 00325 if (!(flags & NS_MSG_PEEK)) { 00326 buffer_data_strip_header(buf_src, len); 00327 sb->data_bytes -= len; 00328 } 00329 if (in_len == 0) { 00330 /* Drop this buffer from queue, and advance to next buffer if stream */ 00331 if (flags & NS_MSG_PEEK) { 00332 buf_src = stream ? ns_list_get_next(&sb->bufs, buf_src) : NULL; 00333 } else { 00334 sockbuf_drop_first(sb); 00335 buf_src = stream ? ns_list_get_first(&sb->bufs) : NULL; 00336 } 00337 if (!buf_src) { 00338 break; 00339 } 00340 in_ptr = buffer_data_pointer(buf_src); 00341 in_len = buffer_data_length(buf_src); 00342 } 00343 00344 /* There's still more input - advance output pointer */ 00345 out_ptr += len; 00346 out_len -= len; 00347 if (out_len == 0) { 00348 /* Advance to next vector */ 00349 if (--iovec_cnt == 0) { 00350 break; 00351 } 00352 iovec_ptr++; 00353 out_ptr = iovec_ptr->iov_base; 00354 out_len = iovec_ptr->iov_len; 00355 } 00356 } 00357 00358 /* If there was anything left in buf_src, for not-stream need to drop it now */ 00359 if (buf_src && !stream) { 00360 msg->msg_flags |= NS_MSG_TRUNC; 00361 if (flags & NS_MSG_TRUNC) { 00362 // Return actual length, not read length 00363 retVal += in_len; 00364 } 00365 if (!(flags & NS_MSG_PEEK)) { 00366 sockbuf_drop_first(sb); 00367 } 00368 } 00369 return retVal; 00370 } 00371 00372 static uint8_t * socket_cmsg_ipv6_header_set(ns_cmsghdr_t *cmsg, uint8_t type, uint16_t length) 00373 { 00374 cmsg->cmsg_level = SOCKET_IPPROTO_IPV6; 00375 cmsg->cmsg_type = type; 00376 cmsg->cmsg_len = NS_CMSG_LEN(length); 00377 return NS_CMSG_DATA(cmsg); 00378 } 00379 00380 int16_t socket_read(int8_t socket, ns_address_t *src_addr, uint8_t *buffer, uint16_t length) 00381 { 00382 return socket_recvfrom(socket, buffer, length, NS_MSG_LEGACY0, src_addr); 00383 } 00384 00385 int16_t socket_recv(int8_t socket, void *buffer, uint16_t length, int flags) 00386 { 00387 return socket_recvfrom(socket, buffer, length, flags, NULL); 00388 } 00389 00390 int16_t socket_recvfrom(int8_t socket, void *buffer, uint16_t length, int flags, ns_address_t *src_addr) 00391 { 00392 ns_iovec_t msg_iov; 00393 ns_msghdr_t msghdr; 00394 00395 //Init message payload vector 00396 msg_iov.iov_base = buffer; 00397 msg_iov.iov_len = length; 00398 00399 //Set messages name buffer 00400 msghdr.msg_name = src_addr; 00401 msghdr.msg_namelen = src_addr ? sizeof(ns_address_t) : 0; 00402 msghdr.msg_iov = &msg_iov; 00403 msghdr.msg_iovlen = 1; 00404 msghdr.msg_control = NULL; 00405 msghdr.msg_controllen = 0; 00406 00407 return socket_recvmsg(socket, &msghdr, flags); 00408 } 00409 00410 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) 00411 { 00412 if (!msg->msg_control || msg->msg_controllen < (written_data + NS_CMSG_SPACE(length))) { 00413 msg->msg_flags |= NS_MSG_CTRUNC; 00414 return written_data; 00415 } 00416 uint8_t *msg_start = msg->msg_control; 00417 uint8_t *data_start = socket_cmsg_ipv6_header_set((ns_cmsghdr_t*) (msg_start + written_data) , type, length); 00418 memcpy(data_start, data_ptr, length); 00419 00420 return (written_data + NS_CMSG_SPACE(length)); 00421 } 00422 00423 int16_t socket_recvmsg(int8_t socket, ns_msghdr_t *msg, int flags) 00424 { 00425 if (!msg) { 00426 return -1; 00427 } 00428 msg->msg_flags = 0; 00429 /** 00430 * Validate socket id 00431 */ 00432 socket_t *socket_ptr = socket_pointer_get(socket); 00433 if (!socket_ptr) { 00434 return -1; 00435 } 00436 00437 //Read Buffer 00438 buffer_t *socket_buf = ns_list_get_first(&socket_ptr->rcvq.bufs); 00439 if (!socket_buf) { 00440 if (flags & NS_MSG_LEGACY0) { 00441 return 0; 00442 } else { 00443 return (socket_ptr->flags & SOCKET_FLAG_CANT_RECV_MORE) ? 0 : NS_EWOULDBLOCK; 00444 } 00445 } 00446 00447 /** 00448 * Validate message payload buffer size 00449 */ 00450 if (!socket_message_validate_iov(msg, NULL)) { 00451 return -1; 00452 } 00453 00454 /** 00455 * Write Ancillary 00456 */ 00457 uint_fast16_t cmsg_written = 0; 00458 if (socket_ptr->inet_pcb ->recvpktinfo) { 00459 ns_in6_pktinfo_t pktinfo; 00460 pktinfo.ipi6_ifindex = socket_buf->interface ->id; 00461 memcpy(pktinfo.ipi6_addr, socket_buf->dst_sa .address , 16); 00462 cmsg_written = copy_ancillary_to_user(msg, cmsg_written, SOCKET_IPV6_PKTINFO, &pktinfo, sizeof pktinfo); 00463 } 00464 00465 if (socket_ptr->inet_pcb ->recvhoplimit) { 00466 int16_t hoplimit = socket_buf->options .hop_limit ; 00467 cmsg_written = copy_ancillary_to_user(msg, cmsg_written, SOCKET_IPV6_HOPLIMIT, &hoplimit, sizeof hoplimit); 00468 } 00469 00470 if (socket_ptr->inet_pcb ->recvtclass) { 00471 int16_t tclass = socket_buf->options .traffic_class ; 00472 cmsg_written = copy_ancillary_to_user(msg, cmsg_written, SOCKET_IPV6_TCLASS, &tclass, sizeof tclass); 00473 } 00474 msg->msg_controllen = cmsg_written; 00475 00476 ns_address_t *src_addr = msg->msg_name; 00477 //Read src address 00478 if (src_addr) { 00479 00480 if (msg->msg_namelen != sizeof(ns_address_t)) { 00481 return -1; 00482 } 00483 00484 src_addr->identifier = socket_buf->src_sa .port ; 00485 src_addr->type = ADDRESS_IPV6; 00486 memcpy(src_addr->address, socket_buf->src_sa .address , 16); 00487 } 00488 00489 //Read Data to Buffer 00490 int16_t len = socket_copy_queue_to_user(&socket_ptr->rcvq, msg, flags, socket_ptr->type == SOCKET_TYPE_STREAM); 00491 00492 if (len > 0 && !(flags & NS_MSG_PEEK) && socket_is_ipv6(socket_ptr) && tcp_info(socket_ptr->inet_pcb )) { 00493 tcp_session_data_received(tcp_info(socket_ptr->inet_pcb )); 00494 } 00495 00496 return len; 00497 } 00498 00499 int16_t socket_sendmsg(int8_t socket, const ns_msghdr_t *msg, int flags) 00500 { 00501 if (!msg) { 00502 return -1; 00503 } 00504 00505 return socket_buffer_sendmsg(socket, NULL, msg, flags); 00506 } 00507 00508 int16_t socket_sendto(int8_t socket, const ns_address_t *address, const void *buffer, uint16_t length) 00509 { 00510 ns_iovec_t data_vector; 00511 ns_msghdr_t msghdr; 00512 00513 //SET IOV vector 00514 data_vector.iov_base = (void *) buffer; 00515 data_vector.iov_len = length; 00516 00517 //Set message name 00518 msghdr.msg_name = (void *) address; 00519 msghdr.msg_namelen = address ? sizeof(ns_address_t) : 0; 00520 msghdr.msg_iov = &data_vector; 00521 msghdr.msg_iovlen = 1; 00522 //No ancillary data 00523 msghdr.msg_control = NULL; 00524 msghdr.msg_controllen = 0; 00525 00526 return socket_sendmsg(socket, &msghdr, NS_MSG_LEGACY0); 00527 } 00528 00529 int8_t socket_connect(int8_t socket, ns_address_t *address, uint8_t randomly_take_src_number) 00530 { 00531 socket_t *socket_ptr = socket_pointer_get(socket); 00532 if (!address || !socket_ptr || !socket_is_ipv6(socket_ptr)) { 00533 return -1; 00534 } 00535 00536 switch (socket_ptr->type) { 00537 case SOCKET_TYPE_STREAM: 00538 case SOCKET_TYPE_DGRAM: 00539 break; 00540 default: 00541 return -5; 00542 } 00543 00544 if (socket_ptr->flags & SOCKET_LISTEN_STATE) { 00545 return -3; 00546 } 00547 00548 if (socket_ptr->flags & (SOCKET_FLAG_CONNECTED|SOCKET_FLAG_CONNECTING)) { 00549 return -4; 00550 } 00551 00552 inet_pcb_t *inet_pcb = socket_ptr->inet_pcb ; 00553 00554 /* Save hash computation time in IP layer by using a random flow for connected sockets */ 00555 if (inet_pcb->flow_label == IPV6_FLOW_AUTOGENERATE || 00556 (inet_pcb->flow_label == IPV6_FLOW_UNSPECIFIED && ipv6_flow_auto_label)) { 00557 inet_pcb->flow_label = ipv6_flow_random(); 00558 } 00559 00560 // Choose local port if not already bound 00561 (void) randomly_take_src_number; 00562 if (inet_pcb->local_port == 0) { 00563 inet_pcb->local_port = socket_generate_random_port(inet_pcb->protocol ); 00564 if (inet_pcb->local_port == 0) { 00565 return -7; 00566 } 00567 } 00568 00569 // Choose local address if not already bound 00570 int8_t status = socket_bind2addrsel(socket, address); 00571 switch(status) { 00572 case 0: //OK 00573 case -3: // already bound 00574 break; 00575 case -1: // invalid param 00576 case -2: //mem alloc fail 00577 return status; 00578 case -4: // no interface 00579 case -5: // addr selection fails 00580 default: 00581 return -7; 00582 } 00583 00584 memcpy(inet_pcb->remote_address , address->address, 16); 00585 inet_pcb->remote_port = address->identifier; 00586 status = 0; 00587 00588 #ifndef NO_TCP 00589 if (socket_ptr->type == SOCKET_TYPE_STREAM) { 00590 if (tcp_info(socket_ptr->inet_pcb )) { 00591 status = -4; // shouldn't happen - flags should cover it 00592 goto exit; 00593 } 00594 00595 //Allocate session here 00596 tcp_session_t *tcp_session = tcp_session_ptr_allocate(socket_ptr->inet_pcb , NULL); 00597 if (!tcp_session) { 00598 status = -2; 00599 goto exit; 00600 } 00601 00602 if (tcp_session_open(tcp_session) != TCP_ERROR_NO_ERROR) { 00603 tcp_session_ptr_free(tcp_session); 00604 status = -2; 00605 goto exit; 00606 } 00607 00608 socket_ptr->flags |= SOCKET_FLAG_CONNECTING; 00609 } 00610 #endif 00611 exit: 00612 if (status != 0) { 00613 memcpy(inet_pcb->remote_address , ns_in6addr_any, 16); 00614 inet_pcb->remote_port = 0; 00615 } 00616 return status; 00617 } 00618 00619 int8_t socket_bind(int8_t socket, const ns_address_t *address) 00620 { 00621 socket_t *socket_ptr = socket_pointer_get(socket); 00622 if (!address || !socket_ptr || !socket_is_ipv6(socket_ptr)) { 00623 return -1; 00624 } 00625 00626 switch (socket_ptr->type) { 00627 case SOCKET_TYPE_STREAM: 00628 case SOCKET_TYPE_DGRAM: 00629 break; 00630 default: 00631 return -5; 00632 } 00633 00634 inet_pcb_t *inet_pcb = socket_ptr->inet_pcb ; 00635 00636 // are they specifying a new port? 00637 if (address->identifier && address->identifier != inet_pcb->local_port ) { 00638 // don't let them do so if a port was already chosen 00639 if (inet_pcb->local_port != 0) { 00640 return -4; 00641 } 00642 if (socket_port_validate(address->identifier, inet_pcb->protocol ) == eOK) { 00643 inet_pcb->local_port = address->identifier; 00644 } 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 (protcol_interface_address_compare(NULL, 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 Fri Jul 22 2022 04:54:00 by
1.7.2
