Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ns_socket.c Source File

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 }