CDC/ECM driver for mbed, based on USBDevice by mbed-official. Uses PicoTCP to access Ethernet USB device. License: GPLv2

Dependents:   USBEthernet_TEST

Fork of USB_Ethernet by Daniele Lacamera

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pico_socket.c Source File

pico_socket.c

00001 /*********************************************************************
00002 PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved.
00003 See LICENSE and COPYING for usage.
00004 
00005 
00006 Authors: Daniele Lacamera
00007 *********************************************************************/
00008 
00009 
00010 #include "pico_config.h"
00011 #include "pico_queue.h"
00012 #include "pico_socket.h"
00013 #include "pico_ipv4.h"
00014 #include "pico_ipv6.h"
00015 #include "pico_udp.h"
00016 #include "pico_tcp.h"
00017 #include "pico_stack.h"
00018 #include "pico_icmp4.h"
00019 #include "pico_nat.h"
00020 #include "pico_tree.h"
00021 #include "pico_device.h"
00022 
00023 #if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6)
00024 #if defined (PICO_SUPPORT_TCP) || defined (PICO_SUPPORT_UDP)
00025 
00026 
00027 #ifdef PICO_SUPPORT_MUTEX
00028 static void * Mutex = NULL;
00029 #define LOCK(x) {\
00030   if (x == NULL) \
00031     x = pico_mutex_init(); \
00032   pico_mutex_lock(x); \
00033 }
00034 #define UNLOCK(x) pico_mutex_unlock(x);
00035 
00036 #else
00037 #define LOCK(x) do{}while(0)
00038 #define UNLOCK(x) do{}while(0)
00039 #endif
00040 
00041 
00042 #define PROTO(s) ((s)->proto->proto_number)
00043 
00044 #ifdef PICO_SUPPORT_TCP
00045 # define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY)))))
00046 #endif
00047 
00048 #define PICO_SOCKET_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */
00049 
00050 #ifdef PICO_SUPPORT_IPV4
00051 # define IS_SOCK_IPV4(s) ((s->net == &pico_proto_ipv4))
00052 #else
00053 # define IS_SOCK_IPV4(s) (0)
00054 #endif
00055 
00056 #ifdef PICO_SUPPORT_IPV6
00057 # define IS_SOCK_IPV6(s) ((s->net == &pico_proto_ipv6))
00058 #else
00059 # define IS_SOCK_IPV6(s) (0)
00060 #endif
00061 
00062 #ifdef PICO_SUPPORT_IPFRAG
00063 # define frag_dbg(...) do{}while(0) 
00064 #endif
00065 
00066 #ifdef PICO_SUPPORT_MCAST 
00067 # define so_mcast_dbg(...) do{}while(0) /* ip_mcast_dbg in pico_ipv4.c */
00068 #endif
00069 
00070 static struct pico_sockport *sp_udp = NULL ,*sp_tcp = NULL;
00071 
00072 struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, int len);
00073 
00074 static int socket_cmp(void * ka, void * kb)
00075 {
00076   struct pico_socket *a = ka, *b = kb;
00077   int a_is_ip6 = is_sock_ipv6(a);
00078   int b_is_ip6 = is_sock_ipv6(b);
00079 
00080   int diff;
00081 
00082   /* First, order by network ver */
00083   if (a_is_ip6 < b_is_ip6)
00084     return -1;
00085   if (a_is_ip6 > b_is_ip6)
00086     return 1;
00087 
00088   /* If either socket is PICO_IPV4_INADDR_ANY mode, skip local address comparison */
00089 
00090   /* At this point, sort by local host */
00091 
00092   if (0) {
00093 #ifdef PICO_SUPPORT_IPV6
00094   } else if (a_is_ip6) {
00095     if ((memcmp(a->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6)==0) || memcmp((b->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0))
00096       diff = 0;
00097     else
00098       diff = memcmp(a->local_addr.ip6.addr, b->local_addr.ip6.addr, PICO_SIZE_IP6);
00099 #endif
00100   } else {
00101     if ((a->local_addr.ip4.addr == PICO_IP4_ANY) || (b->local_addr.ip4.addr == PICO_IP4_ANY))
00102       diff = 0;
00103     else
00104       diff = a->local_addr.ip4.addr - b->local_addr.ip4.addr;
00105   }
00106 
00107   if (diff)
00108     return diff;
00109 
00110 
00111   /* Sort by remote host */
00112   if (a_is_ip6)
00113     diff = memcmp(a->remote_addr.ip6.addr, b->remote_addr.ip6.addr, PICO_SIZE_IP6);
00114   else
00115     diff = a->remote_addr.ip4.addr - b->remote_addr.ip4.addr;
00116 
00117   if (diff)
00118     return diff;
00119 
00120   /* And finally by remote port. The two sockets are coincident if the quad is the same. */
00121   return b->remote_port - a->remote_port;
00122 }
00123 
00124 struct pico_sockport
00125 {
00126   struct pico_tree socks; // how you make the connection ?
00127   uint16_t number;
00128   uint16_t proto;
00129 };
00130 
00131 #define INIT_SOCKPORT { {&LEAF , socket_cmp}, 0, 0 }
00132 
00133 int sockport_cmp(void * ka, void * kb)
00134 {
00135   struct pico_sockport *a = ka, *b = kb;
00136   if (a->number < b->number)
00137     return -1;
00138   if (a->number > b->number)
00139     return 1;
00140   return 0;
00141 }
00142 
00143 PICO_TREE_DECLARE(UDPTable,sockport_cmp);
00144 PICO_TREE_DECLARE(TCPTable,sockport_cmp);
00145 
00146 #ifdef PICO_SUPPORT_MCAST
00147 /*                       socket
00148  *                         |  
00149  *                    MCASTListen
00150  *                    |    |     |
00151  *         ------------    |     ------------
00152  *         |               |                |
00153  *   MCASTSources    MCASTSources     MCASTSources    
00154  *   |  |  |  |      |  |  |  |       |  |  |  |
00155  *   S  S  S  S      S  S  S  S       S  S  S  S
00156  *
00157  *   MCASTListen: RBTree(mcast_link, mcast_group)
00158  *   MCASTSources: RBTree(source)
00159  */
00160 struct pico_mcast_listen
00161 {
00162   uint8_t filter_mode;
00163   struct pico_ip4 mcast_link;
00164   struct pico_ip4 mcast_group;
00165   struct pico_tree MCASTSources;
00166 };
00167 
00168 static int mcast_listen_cmp(void *ka, void *kb)
00169 {
00170   struct pico_mcast_listen *a = ka, *b = kb;
00171   if (a->mcast_group.addr < b->mcast_group.addr)
00172     return -1;
00173   if (a->mcast_group.addr > b->mcast_group.addr)
00174     return 1;
00175 
00176   if (a->mcast_link.addr < b->mcast_link.addr)
00177     return -1;
00178   if (a->mcast_link.addr > b->mcast_link.addr)
00179     return 1;
00180 
00181   return 0;
00182 }
00183 
00184 static int mcast_sources_cmp(void *ka, void *kb)
00185 {
00186   struct pico_ip4 *a = ka, *b = kb;
00187   if (a->addr < b->addr)
00188     return -1;
00189   if (a->addr > b->addr)
00190     return 1;
00191   return 0;
00192 }
00193 
00194 static int mcast_socket_cmp(void *ka, void *kb)
00195 {
00196   struct pico_socket *a = ka, *b = kb;
00197   if (a < b)
00198     return -1;
00199   if (a > b)
00200     return 1;
00201   return 0;
00202 }
00203 /* gather all multicast sockets to hasten filter aggregation */
00204 PICO_TREE_DECLARE(MCASTSockets, mcast_socket_cmp);
00205 
00206 static int mcast_filter_cmp(void *ka, void *kb)
00207 {
00208   struct pico_ip4 *a = ka, *b = kb;
00209   if (a->addr < b->addr)
00210     return -1;
00211   if (a->addr > b->addr)
00212     return 1;
00213   return 0;
00214 }
00215 /* gather sources to be filtered */
00216 PICO_TREE_DECLARE(MCASTFilter, mcast_filter_cmp);
00217 
00218 /* MCASTFilter will be empty if no socket is listening on mcast_group on mcast_link anymore */
00219 static int pico_socket_aggregate_mcastfilters(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group)
00220 {
00221   uint8_t filter_mode = PICO_IP_MULTICAST_INCLUDE;
00222   struct pico_mcast_listen *listen = NULL, ltest = {0};
00223   struct pico_ip4 *source = NULL;
00224   struct pico_socket *mcast_sock = NULL;
00225   struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
00226 
00227   ltest.mcast_link = *mcast_link;
00228   ltest.mcast_group = *mcast_group;
00229 
00230   /* cleanup old filter */
00231   pico_tree_foreach_safe(index, &MCASTFilter, _tmp)
00232   {
00233     pico_tree_delete(&MCASTFilter, index->keyValue);
00234   }
00235 
00236   /* construct new filter */
00237   pico_tree_foreach(index, &MCASTSockets)
00238   {
00239     mcast_sock = index->keyValue;
00240     listen = pico_tree_findKey(mcast_sock->MCASTListen, &ltest);
00241     if (listen) {
00242       /* aggregate filter */
00243       switch(filter_mode)
00244       {
00245         case PICO_IP_MULTICAST_INCLUDE:
00246           switch (listen->filter_mode)
00247           {
00248             case PICO_IP_MULTICAST_INCLUDE:
00249               /* filter = summation of INCLUDEs */
00250               /* mode stays INCLUDE, add all sources to filter */
00251               pico_tree_foreach(index2, &listen->MCASTSources)
00252               {
00253                 source = index2->keyValue;
00254                 pico_tree_insert(&MCASTFilter, source); 
00255               }
00256               break;
00257 
00258             case PICO_IP_MULTICAST_EXCLUDE:
00259               /* filter = EXCLUDE - INCLUDE */
00260               /* delete from the interface INCLUDE filter any source NOT in the socket EXCLUDE filter */
00261               pico_tree_foreach_safe(index2, &MCASTFilter, _tmp2)
00262               {
00263                 source = pico_tree_findKey(&listen->MCASTSources, index2->keyValue);
00264                 if (!source)
00265                   pico_tree_delete(&MCASTFilter, index2->keyValue);
00266               }
00267               /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
00268               filter_mode = PICO_IP_MULTICAST_EXCLUDE;
00269               /* add to the interface EXCLUDE filter any socket source NOT in the former interface INCLUDE filter */
00270               pico_tree_foreach(index2, &listen->MCASTSources)
00271               {
00272                 source = pico_tree_insert(&MCASTFilter, index2->keyValue); 
00273                 if (source) 
00274                   pico_tree_delete(&MCASTFilter, source);
00275               }
00276               break;
00277 
00278             default:
00279               return -1;
00280           }
00281           break;
00282 
00283         case PICO_IP_MULTICAST_EXCLUDE:
00284           switch (listen->filter_mode)
00285           {
00286             case PICO_IP_MULTICAST_INCLUDE:
00287               /* filter = EXCLUDE - INCLUDE */
00288               /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
00289               /* remove from the interface EXCLUDE filter any source in the socket INCLUDE filter */
00290               pico_tree_foreach(index2, &listen->MCASTSources)
00291               {
00292                 source = pico_tree_findKey(&MCASTFilter, index2->keyValue);
00293                 if (source)
00294                   pico_tree_delete(&MCASTFilter, source);
00295               }
00296               break;
00297 
00298             case PICO_IP_MULTICAST_EXCLUDE:
00299               /* filter = intersection of EXCLUDEs */
00300               /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */
00301               /* remove from the interface EXCLUDE filter any source not in the socket EXCLUDE filter */
00302               pico_tree_foreach_safe(index2, &MCASTFilter, _tmp2)
00303               {
00304                 source = pico_tree_findKey(&listen->MCASTSources, index2->keyValue);
00305                 if (!source)
00306                   pico_tree_delete(&MCASTFilter, index2->keyValue);
00307               }
00308               break;
00309 
00310             default:
00311               return -1;
00312           }
00313           break;
00314 
00315         default:
00316           return -1;
00317       }
00318     }
00319   }
00320   return filter_mode;
00321 }
00322 
00323 static int pico_socket_mcast_filter(struct pico_socket *s, struct pico_ip4 *mcast_group, struct pico_ip4 *src)
00324 {
00325   struct pico_ipv4_link *mcast_link = NULL;
00326   struct pico_mcast_listen *listen = NULL, ltest = {0};
00327   struct pico_tree_node *index = NULL;
00328 
00329   /* no multicast enabled on socket */
00330   if (!s->MCASTListen)
00331     return 0;
00332 
00333   mcast_link = pico_ipv4_link_get(&s->local_addr.ip4);
00334   if (!mcast_link) 
00335     return -1;
00336 
00337   ltest.mcast_link.addr = mcast_link->address.addr;
00338   ltest.mcast_group = *mcast_group;
00339   listen = pico_tree_findKey(s->MCASTListen, &ltest);
00340   if (!listen)
00341     return -1;
00342 
00343   /* perform source filtering */
00344   switch (listen->filter_mode)
00345   {
00346     case PICO_IP_MULTICAST_INCLUDE:
00347       pico_tree_foreach(index, &listen->MCASTSources)
00348       {
00349         if (src->addr == ((struct pico_ip4 *)index->keyValue)->addr) {
00350           so_mcast_dbg("MCAST: IP %08X in included socket source list\n", src->addr);
00351           return 0;
00352         }
00353       }
00354       so_mcast_dbg("MCAST: IP %08X NOT in included socket source list\n", src->addr);
00355       return -1;
00356       break;
00357 
00358     case PICO_IP_MULTICAST_EXCLUDE:
00359       pico_tree_foreach(index, &listen->MCASTSources)
00360       {
00361         if (src->addr == ((struct pico_ip4 *)index->keyValue)->addr) {
00362           so_mcast_dbg("MCAST: IP %08X in excluded socket source list\n", src->addr);
00363           return -1;
00364         }
00365       }
00366       so_mcast_dbg("MCAST: IP %08X NOT in excluded socket source list\n", src->addr);
00367       return 0;
00368       break;
00369 
00370     default:
00371       return -1;
00372       break;
00373   }
00374   return -1;
00375 }
00376 
00377 static inline struct pico_ipv4_link *pico_socket_setoption_mcastargs_validation(struct pico_ip_mreq *mreq, struct pico_ip_mreq_source *mreq_source)
00378 {
00379   struct pico_ipv4_link *mcast_link = NULL;
00380 
00381   if (!mreq && !mreq_source)
00382     return NULL;
00383 
00384   if (mreq) {
00385     if (!mreq->mcast_group_addr.addr)
00386       return NULL;
00387     if (pico_ipv4_is_unicast(mreq->mcast_group_addr.addr))
00388       return NULL;
00389 
00390     if (!mreq->mcast_link_addr.addr) {
00391       mcast_link = pico_ipv4_get_default_mcastlink();
00392       if (!mcast_link)
00393         return NULL;
00394     } else {
00395       mcast_link = pico_ipv4_link_get(&mreq->mcast_link_addr);
00396       if (!mcast_link)
00397         return NULL;
00398     }
00399   }
00400   if (mreq_source) {
00401     if (!mreq_source->mcast_group_addr.addr)
00402       return NULL;
00403     if (pico_ipv4_is_unicast(mreq_source->mcast_group_addr.addr))
00404       return NULL;
00405 
00406     if (!mreq_source->mcast_source_addr.addr)
00407       return NULL;
00408     if (!pico_ipv4_is_unicast(mreq_source->mcast_source_addr.addr))
00409       return NULL;
00410 
00411     if (!mreq_source->mcast_link_addr.addr) {
00412       mcast_link = pico_ipv4_get_default_mcastlink();
00413       if (!mcast_link)
00414         return NULL;
00415     } else {
00416       mcast_link = pico_ipv4_link_get(&mreq_source->mcast_link_addr);
00417       if (!mcast_link)
00418         return NULL;
00419     }
00420   }
00421   return mcast_link;
00422 }
00423 #else
00424 static int pico_socket_mcast_filter(struct pico_socket *s, struct pico_ip4 *mcast_group, struct pico_ip4 *src) {
00425   return 0;
00426 }
00427 #endif /* PICO_SUPPORT_MCAST */
00428 
00429 static struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port)
00430 {
00431   struct pico_sockport test = INIT_SOCKPORT;
00432   test.number = port;
00433 
00434   if (proto == PICO_PROTO_UDP)
00435     return pico_tree_findKey(&UDPTable,&test);
00436 
00437   else if (proto == PICO_PROTO_TCP)
00438     return pico_tree_findKey(&TCPTable,&test);
00439 
00440   else return NULL;
00441 }
00442 
00443 int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net)
00444 {
00445   struct pico_sockport *sp;
00446   struct pico_ip4 ip;
00447   sp = pico_get_sockport(proto, port);
00448 
00449   if (!net)
00450     net = &pico_proto_ipv4;
00451 
00452   /** IPv6 (wip) ***/
00453   if (net != &pico_proto_ipv4) {
00454     dbg("IPV6!!!!!\n");
00455     return (!sp);
00456   }
00457 
00458   /* IPv4 */
00459 #ifdef PICO_SUPPORT_NAT
00460   if (pico_ipv4_nat_find(port,NULL, 0,proto) == 0) {
00461     dbg("In use by nat....\n");
00462     return 0;
00463   }
00464 #endif
00465   if (addr)
00466     ip.addr = ((struct pico_ip4 *)addr)->addr;
00467   else
00468     ip.addr = PICO_IPV4_INADDR_ANY;
00469 
00470   if (ip.addr == PICO_IPV4_INADDR_ANY) {
00471     if (!sp) return 1;
00472       else {
00473         dbg("In use, and asked for ANY\n");
00474         return 0;
00475       }
00476   }
00477   if (sp) {
00478     struct pico_ip4 *s_local;
00479     struct pico_tree_node *idx;
00480     struct pico_socket *s;
00481     pico_tree_foreach(idx, &sp->socks) {
00482       s = idx->keyValue;
00483       if (s->net == &pico_proto_ipv4) {
00484         s_local = (struct pico_ip4*) &s->local_addr;
00485         if ((s_local->addr == PICO_IPV4_INADDR_ANY) || (s_local->addr == ip.addr))
00486           return 0;
00487       }
00488     }
00489   }
00490   return 1;
00491 }
00492 
00493 static int pico_check_socket(struct pico_socket *s)
00494 {
00495   struct pico_sockport *test;
00496   struct pico_socket *found;
00497   struct pico_tree_node * index;
00498 
00499   test = pico_get_sockport(PROTO(s), s->local_port);
00500   
00501   if (!test) {
00502     return -1;
00503   }
00504 
00505   pico_tree_foreach(index,&test->socks){
00506     found = index->keyValue;
00507     if (s == found) {
00508       return 0;
00509     }
00510   }
00511 
00512   return -1;
00513 }
00514 
00515 
00516 int pico_socket_add(struct pico_socket *s)
00517 {
00518   struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
00519   LOCK(Mutex);
00520   if (!sp) {
00521     //dbg("Creating sockport..%04x\n", s->local_port); /* In comment due to spam during test */
00522     sp = pico_zalloc(sizeof(struct pico_sockport));
00523 
00524     if (!sp) {
00525       pico_err = PICO_ERR_ENOMEM;
00526       UNLOCK(Mutex);
00527       return -1;
00528     }
00529     sp->proto = PROTO(s);
00530     sp->number = s->local_port;
00531     sp->socks.root = &LEAF;
00532     sp->socks.compare = socket_cmp;
00533 
00534     if (PROTO(s) == PICO_PROTO_UDP)
00535     {
00536       pico_tree_insert(&UDPTable,sp);
00537     }
00538     else if (PROTO(s) == PICO_PROTO_TCP)
00539     {
00540       pico_tree_insert(&TCPTable,sp);
00541     }
00542   }
00543 
00544   pico_tree_insert(&sp->socks,s);
00545   s->state |= PICO_SOCKET_STATE_BOUND;
00546     UNLOCK(Mutex);
00547 #if DEBUG_SOCKET_TREE
00548   {
00549     struct pico_tree_node * index;
00550     //RB_FOREACH(s, socket_tree, &sp->socks) {
00551     pico_tree_foreach(index,&sp->socks){
00552       s = index->keyValue;
00553       dbg(">>>> List Socket lc=%hu rm=%hu\n", short_be(s->local_port), short_be(s->remote_port));
00554     }
00555 
00556   }
00557 #endif
00558   return 0;
00559 }
00560 
00561 static void socket_garbage_collect(unsigned long now, void *arg)
00562 {
00563   struct pico_socket *s = (struct pico_socket *) arg;
00564   pico_free(s);
00565 }
00566 
00567 int pico_socket_del(struct pico_socket *s)
00568 {
00569   struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port);
00570 
00571   if (!sp) {
00572     pico_err = PICO_ERR_ENXIO;
00573     return -1;
00574   }
00575 
00576   LOCK(Mutex);
00577   pico_tree_delete(&sp->socks,s);
00578   s->net = NULL;
00579   if(pico_tree_empty(&sp->socks)){
00580     if (PROTO(s) == PICO_PROTO_UDP)
00581     {
00582       pico_tree_delete(&UDPTable,sp);
00583     }
00584     else if (PROTO(s) == PICO_PROTO_TCP)
00585     {
00586       pico_tree_delete(&TCPTable,sp);
00587     }
00588 
00589     if(sp_tcp == sp)  sp_tcp = NULL;
00590 
00591     if(sp_udp == sp)   sp_udp = NULL;
00592 
00593     pico_free(sp);
00594 
00595   }
00596 
00597 #ifdef PICO_SUPPORT_MCAST
00598   do {
00599     uint8_t filter_mode = 0;
00600     struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL;
00601     struct pico_mcast_listen *listen = NULL;
00602     struct pico_ip4 *source = NULL;
00603     if (s->MCASTListen) {
00604       pico_tree_delete(&MCASTSockets, s);
00605       pico_tree_foreach_safe(index, s->MCASTListen, _tmp)
00606       {
00607         listen = index->keyValue;
00608         pico_tree_foreach_safe(index2, &listen->MCASTSources, _tmp2)
00609         {
00610           source = index->keyValue;
00611           pico_tree_delete(&listen->MCASTSources, source);
00612           pico_free(source);
00613         }
00614         filter_mode = pico_socket_aggregate_mcastfilters(&listen->mcast_link, &listen->mcast_group);
00615         pico_ipv4_mcast_leave(&listen->mcast_link, &listen->mcast_group, 1, filter_mode, &MCASTFilter);
00616         pico_tree_delete(s->MCASTListen, listen);
00617         pico_free(listen);
00618       }
00619       pico_free(s->MCASTListen);
00620     }
00621   } while (0);
00622 #endif
00623 
00624   s->state = PICO_SOCKET_STATE_CLOSED;
00625   pico_timer_add(3000, socket_garbage_collect, s);
00626     UNLOCK(Mutex);
00627   return 0;
00628 }
00629 
00630 static int pico_socket_alter_state(struct pico_socket *s, uint16_t more_states, uint16_t less_states, uint16_t tcp_state)
00631 {
00632   struct pico_sockport *sp;
00633   if (more_states & PICO_SOCKET_STATE_BOUND)
00634     return pico_socket_add(s);
00635 
00636   if (less_states & PICO_SOCKET_STATE_BOUND)
00637     return pico_socket_del(s);
00638 
00639   sp = pico_get_sockport(PROTO(s), s->local_port);
00640   if (!sp) {
00641     pico_err = PICO_ERR_ENXIO;
00642     return -1;
00643   }
00644 
00645   s->state |= more_states;
00646   s->state &= (~less_states);
00647   if (tcp_state) {
00648     s->state &= 0x00FF;
00649     s->state |= tcp_state;
00650   }
00651 
00652   return 0;
00653 }
00654 
00655 static int pico_socket_deliver(struct pico_protocol *p, struct pico_frame *f, uint16_t localport)
00656 {
00657   struct pico_frame *cpy = NULL;
00658   struct pico_sockport *sp = NULL;
00659   struct pico_socket *s = NULL, *found = NULL;
00660   struct pico_tree_node *index = NULL;
00661   struct pico_tree_node *_tmp;
00662   struct pico_trans *tr = (struct pico_trans *) f->transport_hdr;
00663   #ifdef PICO_SUPPORT_IPV4
00664   struct pico_ipv4_hdr *ip4hdr;
00665   #endif
00666   #ifdef PICO_SUPPORT_IPV6
00667   struct pico_ipv6_hdr *ip6hdr;
00668   #endif
00669 
00670   if (!tr)
00671     return -1;
00672 
00673   sp = pico_get_sockport(p->proto_number, localport);
00674 
00675   if (!sp) {
00676     dbg("No such port %d\n",short_be(localport));
00677     return -1;
00678   }
00679 
00680   #ifdef PICO_SUPPORT_TCP
00681   if (p->proto_number == PICO_PROTO_TCP) {
00682     pico_tree_foreach_safe(index,&sp->socks, _tmp){
00683       s = index->keyValue;
00684       /* 4-tuple identification of socket (port-IP) */
00685       #ifdef PICO_SUPPORT_IPV4
00686       if (IS_IPV4(f)) {
00687         struct pico_ip4 s_local, s_remote, p_src, p_dst;
00688         ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
00689         s_local.addr = s->local_addr.ip4.addr;
00690         s_remote.addr = s->remote_addr.ip4.addr;
00691         p_src.addr = ip4hdr->src.addr;
00692         p_dst.addr = ip4hdr->dst.addr;
00693         if (  (s->remote_port == tr->sport) && /* remote port check */
00694               (s_remote.addr == p_src.addr) && /* remote addr check */ 
00695               ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
00696           found = s;
00697           break;
00698         } else if ( (s->remote_port == 0)  && /* not connected... listening */
00699          ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */
00700           /* listen socket */
00701           found = s;
00702         }
00703       }
00704       #endif
00705       #ifdef PICO_SUPPORT_IPV6    /* XXX TODO make compare for ipv6 addresses */
00706       if (IS_IPV6(f)) {
00707         ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr);
00708         if ( (s->remote_port == localport) ) { // && (((struct pico_ip6) s->remote_addr.ip6).addr == ((struct pico_ip6)(ip6hdr->src)).addr) ) {
00709           found = s;
00710           break;
00711         } else if (s->remote_port == 0) {
00712           /* listen socket */
00713           found = s;
00714         }
00715       }
00716       #endif 
00717     } /* FOREACH */
00718     if (found != NULL) {
00719       pico_tcp_input(found,f);
00720       if ((found->ev_pending) && found->wakeup) {
00721         found->wakeup(found->ev_pending, found);
00722       }
00723       return 0;
00724     } else {
00725       dbg("SOCKET> mmm something wrong (prob sockport)\n");
00726       return -1;
00727     }
00728   } /* TCP CASE */
00729 #endif
00730 
00731 #ifdef PICO_SUPPORT_UDP
00732   if (p->proto_number == PICO_PROTO_UDP) {
00733     pico_tree_foreach_safe(index,&sp->socks, _tmp){
00734       s = index->keyValue;
00735       if (IS_IPV4(f)) { /* IPV4 */
00736         struct pico_ip4 s_local, p_dst;
00737         ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
00738         s_local.addr = s->local_addr.ip4.addr;
00739         p_dst.addr = ip4hdr->dst.addr;
00740         if ((pico_ipv4_is_broadcast(p_dst.addr)) || pico_ipv4_is_multicast(p_dst.addr)) {
00741           struct pico_device *dev = pico_ipv4_link_find(&s->local_addr.ip4);
00742           if (pico_ipv4_is_multicast(p_dst.addr) && (pico_socket_mcast_filter(s, &ip4hdr->dst, &ip4hdr->src) < 0))
00743             return -1;
00744           if ((s_local.addr == PICO_IPV4_INADDR_ANY) || /* If our local ip is ANY, or.. */
00745             (dev == f->dev) ) { /* the source of the bcast packet is a neighbor... */
00746             cpy = pico_frame_copy(f);
00747             if (!cpy)
00748               return -1;
00749             if (pico_enqueue(&s->q_in, cpy) > 0) {
00750               if (s->wakeup)
00751                 s->wakeup(PICO_SOCK_EV_RD, s);
00752             }
00753           }
00754         } else if ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))
00755         { /* Either local socket is ANY, or matches dst */
00756           cpy = pico_frame_copy(f);
00757           if (!cpy)
00758             return -1;
00759           if (pico_enqueue(&s->q_in, cpy) > 0) {
00760             if (s->wakeup)
00761               s->wakeup(PICO_SOCK_EV_RD, s);
00762           }
00763         }
00764       } else {
00765         /*... IPv6 */
00766       }
00767     } /* FOREACH */
00768     pico_frame_discard(f);
00769     if (s)
00770       return 0;
00771     else
00772       return -1;
00773   }
00774 #endif
00775   return -1;
00776 }
00777 
00778 struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *))
00779 {
00780 
00781   struct pico_socket *s = NULL;
00782 
00783 #ifdef PICO_SUPPORT_UDP
00784   if (proto == PICO_PROTO_UDP) {
00785     s = pico_udp_open();
00786     s->proto = &pico_proto_udp;
00787   }
00788 #endif
00789 
00790 #ifdef PICO_SUPPORT_TCP
00791   if (proto == PICO_PROTO_TCP) {
00792     s = pico_tcp_open();
00793     s->proto = &pico_proto_tcp;
00794     /*check if Nagle enabled */
00795     if (!IS_NAGLE_ENABLED(s))
00796       dbg("ERROR Nagle should be enabled here\n\n");
00797   }
00798 #endif
00799 
00800   if (!s) {
00801     pico_err = PICO_ERR_EPROTONOSUPPORT;
00802     return NULL;
00803   }
00804 
00805 #ifdef PICO_SUPPORT_IPV4
00806   if (net == PICO_PROTO_IPV4)
00807     s->net = &pico_proto_ipv4;
00808 #endif
00809 
00810 #ifdef PICO_SUPPORT_IPV6
00811   if (net == PICO_PROTO_IPV6)
00812     s->net = &pico_proto_ipv6;
00813 #endif
00814 
00815   s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
00816   s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
00817   s->wakeup = wakeup;
00818 
00819   if (!s->net) {
00820     pico_free(s);
00821     pico_err = PICO_ERR_ENETUNREACH;
00822     return NULL;
00823   }
00824   return s;
00825 }
00826 
00827 
00828 struct pico_socket *pico_socket_clone(struct pico_socket *facsimile)
00829 {
00830   struct pico_socket *s = NULL;
00831 
00832 #ifdef PICO_SUPPORT_UDP
00833   if (facsimile->proto->proto_number == PICO_PROTO_UDP) {
00834     s = pico_udp_open();
00835     s->proto = &pico_proto_udp;
00836   }
00837 #endif
00838 
00839 #ifdef PICO_SUPPORT_TCP
00840   if (facsimile->proto->proto_number == PICO_PROTO_TCP) {
00841     s = pico_tcp_open();
00842     s->proto = &pico_proto_tcp; 
00843   }
00844 #endif
00845 
00846   if (!s) {
00847     pico_err = PICO_ERR_EPROTONOSUPPORT;
00848     return NULL;
00849   }
00850   s->local_port = facsimile->local_port;
00851   s->remote_port = facsimile->remote_port;
00852   s->state = facsimile->state;
00853 
00854 #ifdef PICO_SUPPORT_IPV4
00855   if (facsimile->net == &pico_proto_ipv4) {
00856     s->net = &pico_proto_ipv4;
00857     memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip4));
00858     memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip4));
00859   }
00860 #endif
00861 
00862 #ifdef PICO_SUPPORT_IPV6
00863   if (net == &pico_proto_ipv6) {
00864     s->net = &pico_proto_ipv6;
00865     memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip6));
00866     memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip6));
00867   }
00868 #endif
00869   s->q_in.max_size = PICO_DEFAULT_SOCKETQ;
00870   s->q_out.max_size = PICO_DEFAULT_SOCKETQ;
00871   s->wakeup = NULL;
00872   if (!s->net) {
00873     pico_free(s);
00874     pico_err = PICO_ERR_ENETUNREACH;
00875     return NULL;
00876   }
00877   return s;
00878 }
00879 
00880 int pico_socket_read(struct pico_socket *s, void *buf, int len)
00881 {
00882   if (!s || buf == NULL) {
00883     pico_err = PICO_ERR_EINVAL;
00884     return -1;
00885   } else {
00886     /* check if exists in tree */
00887     /* See task #178 */
00888     if (pico_check_socket(s) != 0) {
00889       pico_err = PICO_ERR_EINVAL;
00890       return -1;
00891     }
00892   }
00893 
00894   if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
00895     pico_err = PICO_ERR_EIO;
00896     return -1;
00897   }
00898 #ifdef PICO_SUPPORT_UDP 
00899   if (PROTO(s) == PICO_PROTO_UDP)
00900     return pico_udp_recv(s, buf, len, NULL, NULL);
00901 #endif
00902 
00903 #ifdef PICO_SUPPORT_TCP
00904   if (PROTO(s) == PICO_PROTO_TCP){
00905     /* check if in shutdown state and if no more data in tcpq_in */
00906     if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s) ) {  
00907       pico_err = PICO_ERR_ESHUTDOWN;
00908       return -1;
00909     } else {
00910       return pico_tcp_read(s, buf, len);
00911     }
00912   }
00913 #endif
00914   return 0;
00915 }
00916 
00917 int pico_socket_write(struct pico_socket *s, void *buf, int len)
00918 {
00919   if (!s || buf == NULL) {
00920     pico_err = PICO_ERR_EINVAL;
00921     return -1;
00922   } else {
00923     /* check if exists in tree */
00924     /* See task #178 */
00925     if (pico_check_socket(s) != 0) {
00926       pico_err = PICO_ERR_EINVAL;
00927       return -1;
00928     }
00929   }
00930 
00931   if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
00932     pico_err = PICO_ERR_EIO;
00933     return -1;
00934   }
00935   if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
00936     pico_err = PICO_ERR_ENOTCONN;
00937     return -1;
00938   } else if (s->state & PICO_SOCKET_STATE_SHUT_LOCAL) {  /* check if in shutdown state */
00939     pico_err = PICO_ERR_ESHUTDOWN;
00940     return -1;
00941   } else {
00942     return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
00943   }
00944 }
00945 
00946 uint16_t pico_socket_high_port(uint16_t proto)
00947 {
00948   uint16_t port;
00949   if (0 || 
00950 #ifdef PICO_SUPPORT_TCP
00951   (proto == PICO_PROTO_TCP) ||
00952 #endif
00953 #ifdef PICO_SUPPORT_TCP
00954   (proto == PICO_PROTO_UDP) ||
00955 #endif
00956   0) {
00957     do {
00958       uint32_t rand = pico_rand();
00959       port = (uint16_t) (rand & 0xFFFFU);
00960       port = (uint16_t)(port % (65535 - 1024)) + 1024U; 
00961       if (pico_is_port_free(proto, port, NULL, NULL)) {
00962         return short_be(port);
00963       }
00964     } while(1);
00965   }
00966   else return 0U;
00967 }
00968 
00969 
00970 int pico_socket_sendto(struct pico_socket *s, void *buf, int len, void *dst, uint16_t remote_port)
00971 {
00972   struct pico_frame *f;
00973   struct pico_remote_duple *remote_duple = NULL;
00974   int header_offset = 0;
00975   int total_payload_written = 0;
00976 #ifdef PICO_SUPPORT_IPV4
00977   struct pico_ip4 *src4;
00978 #endif
00979 
00980 #ifdef PICO_SUPPORT_IPV6
00981   struct pico_ip6 *src6;
00982 #endif
00983   if (len == 0) {
00984     return 0;
00985   } else if (len < 0) {
00986     pico_err = PICO_ERR_EINVAL;
00987     return -1;
00988   }
00989 
00990   if (buf == NULL || s == NULL) {
00991     pico_err = PICO_ERR_EINVAL;
00992     return -1;
00993   }
00994 
00995   if (!dst || !remote_port) {
00996     pico_err = PICO_ERR_EADDRNOTAVAIL;
00997     return -1;
00998   }
00999 
01000   if ((s->state & PICO_SOCKET_STATE_CONNECTED) != 0) {
01001     if (remote_port != s->remote_port) {
01002       pico_err = PICO_ERR_EINVAL;
01003       return -1;
01004     }
01005   }
01006 
01007 #ifdef PICO_SUPPORT_IPV4
01008   if (IS_SOCK_IPV4(s)) {
01009     if ((s->state & PICO_SOCKET_STATE_CONNECTED)) {
01010       if  (s->remote_addr.ip4.addr != ((struct pico_ip4 *)dst)->addr ) {
01011         pico_err = PICO_ERR_EADDRNOTAVAIL;
01012         return -1;
01013       }
01014     } else {
01015       src4 = pico_ipv4_source_find(dst);
01016       if (!src4) {
01017         pico_err = PICO_ERR_EHOSTUNREACH;
01018         return -1;
01019       }
01020       if (src4->addr != PICO_IPV4_INADDR_ANY)
01021         s->local_addr.ip4.addr = src4->addr;
01022 #     ifdef PICO_SUPPORT_UDP
01023       /* socket remote info could change in a consecutive call, make persistent */
01024       if (PROTO(s) == PICO_PROTO_UDP) {
01025         remote_duple = pico_zalloc(sizeof(struct pico_remote_duple));
01026         remote_duple->remote_addr.ip4.addr = ((struct pico_ip4 *)dst)->addr;
01027         remote_duple->remote_port = remote_port;
01028       }
01029 #     endif
01030     }
01031   }
01032 #endif
01033 
01034 #ifdef PICO_SUPPORT_IPV6
01035   if (IS_SOCK_IPV6(s)) {
01036     if (s->state & PICO_SOCKET_STATE_CONNECTED) {
01037       if (memcmp(&s->remote_addr, dst, PICO_SIZE_IP6))
01038         return -1;
01039     } else {
01040       src6 = pico_ipv6_source_find(dst);
01041       if (!src6) {
01042         pico_err = PICO_ERR_EHOSTUNREACH;
01043         return -1;
01044       }
01045       memcpy(&s->local_addr, src6, PICO_SIZE_IP6);
01046       memcpy(&s->remote_addr, dst, PICO_SIZE_IP6);
01047 #     ifdef PICO_SUPPORT_UDP
01048       if (PROTO(s) == PICO_PROTO_UDP) {
01049         remote_duple = pico_zalloc(sizeof(struct pico_remote_duple));
01050         remote_duple->remote_addr.ip6.addr = ((struct pico_ip6 *)dst)->addr;
01051         remote_duple->remote_port = remote_port;
01052       }
01053 #     endif
01054     }
01055   }
01056 #endif
01057 
01058   if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
01059     s->local_port = pico_socket_high_port(s->proto->proto_number);
01060     if (s->local_port == 0) {
01061       pico_err = PICO_ERR_EINVAL;
01062       return -1;
01063     }
01064   }
01065   if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
01066     s->remote_port = remote_port;
01067   }
01068 
01069 #ifdef PICO_SUPPORT_TCP
01070   if (PROTO(s) == PICO_PROTO_TCP)
01071     header_offset = pico_tcp_overhead(s);
01072 #endif
01073 
01074 #ifdef PICO_SUPPORT_UDP
01075   if (PROTO(s) == PICO_PROTO_UDP)
01076     header_offset = sizeof(struct pico_udp_hdr);
01077 #endif
01078 
01079   while (total_payload_written < len) {
01080     int transport_len = (len - total_payload_written) + header_offset; 
01081     if (transport_len > PICO_SOCKET_MTU)
01082       transport_len = PICO_SOCKET_MTU;
01083 #ifdef PICO_SUPPORT_IPFRAG
01084     else {
01085       if (total_payload_written)
01086         transport_len -= header_offset; /* last fragment, do not allocate memory for transport header */
01087     }
01088 #endif /* PICO_SUPPORT_IPFRAG */
01089 
01090     f = pico_socket_frame_alloc(s, transport_len);
01091     if (!f) {
01092       pico_err = PICO_ERR_ENOMEM;
01093       return -1;
01094     }
01095     f->payload += header_offset;
01096     f->payload_len -= header_offset;
01097     f->sock = s;
01098     if (remote_duple) {
01099       f->info = pico_zalloc(sizeof(struct pico_remote_duple));
01100       memcpy(f->info, remote_duple, sizeof(struct pico_remote_duple));
01101     }
01102 
01103 #ifdef PICO_SUPPORT_IPFRAG
01104 #  ifdef PICO_SUPPORT_UDP
01105     if (PROTO(s) == PICO_PROTO_UDP && ((len + header_offset) > PICO_SOCKET_MTU)) {
01106       /* hacking way to identify fragmentation frames: payload != transport_hdr -> first frame */
01107       if (!total_payload_written) {
01108         frag_dbg("FRAG: first fragmented frame %p | len = %u offset = 0\n", f, f->payload_len);
01109         /* transport header length field contains total length + header length */
01110         f->transport_len = len + header_offset;
01111         f->frag = short_be(PICO_IPV4_MOREFRAG); 
01112       } else {
01113         /* no transport header in fragmented IP */
01114         f->payload = f->transport_hdr;
01115         f->payload_len += header_offset;
01116         /* set offset in octets */
01117         f->frag = short_be((total_payload_written + header_offset) / 8); 
01118         if (total_payload_written + f->payload_len < len) {
01119           frag_dbg("FRAG: intermediate fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
01120           f->frag |= short_be(PICO_IPV4_MOREFRAG);
01121         } else {
01122           frag_dbg("FRAG: last fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag));
01123           f->frag &= short_be(PICO_IPV4_FRAG_MASK);
01124         }
01125       }
01126     } else {
01127       f->frag = short_be(PICO_IPV4_DONTFRAG);
01128     }
01129 #  endif /* PICO_SUPPORT_UDP */
01130 #endif /* PICO_SUPPORT_IPFRAG */
01131 
01132     if (f->payload_len <= 0) {
01133       pico_frame_discard(f);
01134       if (remote_duple)
01135         pico_free(remote_duple);
01136       return total_payload_written;
01137     }
01138 
01139     memcpy(f->payload, buf + total_payload_written, f->payload_len);
01140     //dbg("Pushing segment, hdr len: %d, payload_len: %d\n", header_offset, f->payload_len);
01141 
01142     if (s->proto->push(s->proto, f) > 0) {
01143       total_payload_written += f->payload_len;
01144     } else {
01145       pico_frame_discard(f);
01146       pico_err = PICO_ERR_EAGAIN;
01147       break;
01148     }
01149   }
01150   if (remote_duple)
01151     pico_free(remote_duple);
01152   return total_payload_written;
01153 }
01154 
01155 int pico_socket_send(struct pico_socket *s, void *buf, int len)
01156 {
01157   if (!s || buf == NULL) {
01158     pico_err = PICO_ERR_EINVAL;
01159     return -1;
01160   } else {
01161     /* check if exists in tree */
01162     /* See task #178 */
01163     if (pico_check_socket(s) != 0) {
01164       pico_err = PICO_ERR_EINVAL;
01165       return -1;
01166     }
01167   }
01168 
01169   if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) {
01170     pico_err = PICO_ERR_ENOTCONN;
01171     return -1;
01172   }
01173   return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port);
01174 }
01175 
01176 int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port)
01177 {
01178   if (!s || buf == NULL) { /// || orig == NULL || remote_port == NULL) {
01179     pico_err = PICO_ERR_EINVAL;
01180     return -1;
01181   } else {
01182     /* check if exists in tree */
01183     if (pico_check_socket(s) != 0) {
01184       pico_err = PICO_ERR_EINVAL;
01185     /* See task #178 */
01186       return -1;
01187     }
01188   }
01189 
01190   if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
01191     pico_err = PICO_ERR_EADDRNOTAVAIL;
01192     return -1;
01193   }
01194 #ifdef PICO_SUPPORT_UDP 
01195   if (PROTO(s) == PICO_PROTO_UDP) {
01196     return pico_udp_recv(s, buf, len, orig, remote_port);
01197   }
01198 #endif
01199 #ifdef PICO_SUPPORT_TCP
01200   if (PROTO(s) == PICO_PROTO_TCP) {
01201     /* check if in shutdown state and if tcpq_in empty */
01202     if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) {
01203       pico_err = PICO_ERR_ESHUTDOWN;
01204       return -1;
01205     } else {
01206       //dbg("socket tcp recv\n");
01207       return pico_tcp_read(s, buf, len);
01208     }
01209   }
01210 #endif
01211   //dbg("socket return 0\n");
01212   return 0;
01213 }
01214 
01215 int pico_socket_recv(struct pico_socket *s, void *buf, int len)
01216 {
01217   return pico_socket_recvfrom(s, buf, len, NULL, NULL);
01218 }
01219 
01220 
01221 int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port)
01222 {
01223   if (!s || !local_addr || !port) {
01224     pico_err = PICO_ERR_EINVAL;
01225     return -1;
01226   }
01227 
01228   if (!is_sock_ipv6(s)) {
01229     struct pico_ip4 *ip = (struct pico_ip4 *)local_addr;
01230     if (ip->addr != PICO_IPV4_INADDR_ANY) {
01231       if (!pico_ipv4_link_find(local_addr)) {
01232         pico_err = PICO_ERR_EINVAL;
01233         return -1;
01234       }
01235     }
01236   } else {
01237     /*... IPv6 */
01238   }
01239 
01240 
01241   /* When given port = 0, get a random high port to bind to. */
01242   if (*port == 0) {
01243     *port = pico_socket_high_port(PROTO(s));
01244     if (*port == 0) {
01245       pico_err = PICO_ERR_EINVAL;
01246       return -1;
01247     }
01248   }
01249 
01250   if (pico_is_port_free(PROTO(s), *port, local_addr, s->net) == 0) {
01251     pico_err = PICO_ERR_EADDRINUSE;
01252     return -1;
01253   }
01254   s->local_port = *port;
01255 
01256   if (is_sock_ipv6(s)) {
01257     struct pico_ip6 *ip = (struct pico_ip6 *) local_addr;
01258     memcpy(s->local_addr.ip6.addr, ip, PICO_SIZE_IP6);
01259     /* XXX: port ipv4 functionality to ipv6 */
01260     /* Check for port already in use */
01261     if (pico_is_port_free(PROTO(s), *port, &local_addr, s->net)) {
01262       pico_err = PICO_ERR_EADDRINUSE;
01263       return -1;
01264     }
01265   } else if (is_sock_ipv4(s)) {
01266     struct pico_ip4 *ip = (struct pico_ip4 *) local_addr;
01267     s->local_addr.ip4.addr = ip->addr;
01268   }
01269   return pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
01270 }
01271 
01272 int pico_socket_connect(struct pico_socket *s, void *remote_addr, uint16_t remote_port)
01273 {
01274   int ret = -1;
01275   pico_err = PICO_ERR_EPROTONOSUPPORT;
01276   if (!s || remote_addr == NULL || remote_port == 0) {
01277     pico_err = PICO_ERR_EINVAL;
01278     return -1;
01279   }
01280 
01281   s->remote_port = remote_port;
01282 
01283   if (s->local_port == 0) {
01284     s->local_port = pico_socket_high_port(PROTO(s));
01285     if (!s->local_port) {
01286       pico_err = PICO_ERR_EINVAL;
01287       return -1;
01288     }
01289   }
01290 
01291   if (is_sock_ipv6(s)) {
01292     struct pico_ip6 *ip = (struct pico_ip6 *) remote_addr;
01293     memcpy(s->remote_addr.ip6.addr, ip, PICO_SIZE_IP6);
01294   } else if (is_sock_ipv4(s)) {
01295     struct pico_ip4 *local, *ip = (struct pico_ip4 *) remote_addr;
01296     s->remote_addr.ip4.addr = ip->addr;
01297     local = pico_ipv4_source_find(ip);
01298     if (local) {
01299       s->local_addr.ip4.addr = local->addr;
01300     } else {
01301       pico_err = PICO_ERR_EHOSTUNREACH;
01302       return -1;
01303     }
01304   }
01305 
01306   pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
01307 
01308 #ifdef PICO_SUPPORT_UDP
01309   if (PROTO(s) == PICO_PROTO_UDP) {
01310     pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED, 0, 0);
01311     pico_err = PICO_ERR_NOERR;
01312     ret = 0;
01313   }
01314 #endif
01315 
01316 #ifdef PICO_SUPPORT_TCP
01317   if (PROTO(s) == PICO_PROTO_TCP) {
01318     if (pico_tcp_initconn(s) == 0) {
01319       pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_SENT, 0, 0);
01320       pico_err = PICO_ERR_NOERR;
01321       ret = 0;
01322     } else {
01323       pico_err = PICO_ERR_EHOSTUNREACH;
01324     }
01325   }
01326 #endif
01327 
01328   return ret;
01329 }
01330 
01331 #ifdef PICO_SUPPORT_TCP
01332 
01333 int pico_socket_listen(struct pico_socket *s, int backlog)
01334 {
01335   if (!s || backlog < 1) {
01336     pico_err = PICO_ERR_EINVAL;
01337     return -1;
01338   } else {
01339     /* check if exists in tree */
01340     /* See task #178 */
01341     if (pico_check_socket(s) != 0) {
01342       pico_err = PICO_ERR_EINVAL;
01343       return -1;
01344     }
01345   }
01346 
01347   if (PROTO(s) == PICO_PROTO_UDP) {
01348     pico_err = PICO_ERR_EINVAL;
01349     return -1;
01350   }
01351 
01352   if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
01353     pico_err = PICO_ERR_EISCONN;
01354     return -1;
01355   }
01356 
01357   if (backlog < 1) {
01358     pico_err = PICO_ERR_EINVAL;
01359     return -1;
01360   }
01361 
01362   if (PROTO(s) == PICO_PROTO_TCP)
01363     pico_socket_alter_state(s, PICO_SOCKET_STATE_TCP_SYN_SENT, 0, PICO_SOCKET_STATE_TCP_LISTEN);
01364   s->max_backlog = backlog;
01365 
01366   return 0;
01367 }
01368 
01369 struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *port)
01370 {
01371   if (!s || !orig || !port) {
01372     pico_err = PICO_ERR_EINVAL;
01373     return NULL;
01374   }
01375 
01376   pico_err = PICO_ERR_EINVAL;
01377 
01378   if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) {
01379     return NULL;
01380   }
01381 
01382   if (PROTO(s) == PICO_PROTO_UDP) {
01383     return NULL;
01384   }
01385 
01386   if (TCPSTATE(s) == PICO_SOCKET_STATE_TCP_LISTEN) {
01387     struct pico_sockport *sp = pico_get_sockport(PICO_PROTO_TCP, s->local_port);
01388     struct pico_socket *found;
01389     /* If at this point no incoming connection socket is found,
01390      * the accept call is valid, but no connection is established yet.
01391      */
01392     pico_err = PICO_ERR_EAGAIN; 
01393     if (sp) {
01394       struct pico_tree_node * index;
01395       //RB_FOREACH(found, socket_tree, &sp->socks) {
01396       pico_tree_foreach(index,&sp->socks){
01397         found = index->keyValue;
01398         if (s == found->parent) {
01399           found->parent = NULL;
01400           pico_err = PICO_ERR_NOERR;
01401           memcpy(orig, &found->remote_addr, sizeof(struct pico_ip4));
01402           *port = found->remote_port;
01403           return found;
01404         }
01405       }
01406     }
01407   }
01408   return NULL;
01409 }
01410 
01411 #else
01412 
01413 int pico_socket_listen(struct pico_socket *s, int backlog)
01414 {
01415   pico_err = PICO_ERR_EINVAL;
01416   return -1;
01417 }
01418 
01419 struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *local_port)
01420 {
01421   pico_err = PICO_ERR_EINVAL;
01422   return NULL;
01423 }
01424 
01425 #endif
01426 
01427 #define PICO_SOCKET_SETOPT_EN(socket,index)  (socket->opt_flags |=  (1 << index))
01428 #define PICO_SOCKET_SETOPT_DIS(socket,index) (socket->opt_flags &= ~(1 << index))
01429 
01430 int pico_socket_setoption(struct pico_socket *s, int option, void *value) // XXX no check against proto (vs setsockopt) or implicit by socket?
01431 {
01432   if (s == NULL) {
01433     pico_err = PICO_ERR_EINVAL;
01434     return -1;
01435   }
01436 
01437   pico_err = PICO_ERR_NOERR;
01438 
01439   switch (option)
01440   {
01441 #ifdef PICO_SUPPORT_TCP
01442     case PICO_TCP_NODELAY:
01443           if (!value) {
01444             pico_err = PICO_ERR_EINVAL;
01445             return -1;
01446           }
01447           if (s->proto->proto_number == PICO_PROTO_TCP) {
01448             int *val = (int*)value;
01449             if (*val > 0) {
01450               dbg("setsockopt: Nagle algorithm disabled.\n");
01451               PICO_SOCKET_SETOPT_EN(s,PICO_SOCKET_OPT_TCPNODELAY);
01452             } else {
01453               dbg("setsockopt: Nagle algorithm enabled.\n");
01454               PICO_SOCKET_SETOPT_DIS(s,PICO_SOCKET_OPT_TCPNODELAY);
01455             }
01456           } else {
01457             pico_err = PICO_ERR_EINVAL;
01458           }
01459           break;
01460 #endif
01461 
01462 
01463 #ifdef PICO_SUPPORT_MCAST
01464     case PICO_IP_MULTICAST_IF:
01465           pico_err = PICO_ERR_EOPNOTSUPP;
01466           return -1;
01467           break;
01468 
01469     case PICO_IP_MULTICAST_TTL:
01470           if (s->proto->proto_number == PICO_PROTO_UDP) {
01471             return pico_udp_set_mc_ttl(s, *((uint8_t *) value));
01472           }
01473           break;
01474 
01475     case PICO_IP_MULTICAST_LOOP:
01476           if (s->proto->proto_number == PICO_PROTO_UDP) {
01477             switch (*(uint8_t *) value)
01478             {
01479               case 0:
01480                 /* do not loop back multicast datagram */
01481                 PICO_SOCKET_SETOPT_DIS(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
01482                 break;
01483 
01484               case 1:
01485                 /* do loop back multicast datagram */
01486                 PICO_SOCKET_SETOPT_EN(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
01487                 break;  
01488 
01489               default:
01490                 pico_err = PICO_ERR_EINVAL;
01491                 return -1;
01492              }
01493           }
01494           break;
01495 
01496     case PICO_IP_ADD_MEMBERSHIP:
01497       /* EXCLUDE mode */
01498       if (s->proto->proto_number == PICO_PROTO_UDP) {
01499         uint8_t filter_mode = 0;
01500         struct pico_ip_mreq *mreq = NULL;
01501         struct pico_mcast_listen *listen = NULL, ltest = {0};
01502         struct pico_ipv4_link *mcast_link = NULL;
01503 
01504         if (!value) {
01505           pico_err = PICO_ERR_EINVAL;
01506           return -1;
01507         }
01508         mreq = (struct pico_ip_mreq *) value;
01509         mcast_link = pico_socket_setoption_mcastargs_validation(mreq, NULL);
01510         if (!mcast_link) {
01511           pico_err = PICO_ERR_EINVAL;
01512           return -1;
01513         }
01514         if (!mreq->mcast_link_addr.addr)
01515           mreq->mcast_link_addr.addr = mcast_link->address.addr;
01516 
01517         if (!s->MCASTListen) { /* No RBTree allocated yet */
01518           s->MCASTListen = pico_zalloc(sizeof(struct pico_tree));
01519           if (!s->MCASTListen) {
01520             pico_err = PICO_ERR_ENOMEM;
01521             return -1;
01522           }
01523           s->MCASTListen->root = &LEAF;
01524           s->MCASTListen->compare = mcast_listen_cmp;
01525         }
01526         ltest.mcast_link = mreq->mcast_link_addr;
01527         ltest.mcast_group = mreq->mcast_group_addr;
01528         listen = pico_tree_findKey(s->MCASTListen, &ltest);
01529         if (listen) {
01530           if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
01531             so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
01532             pico_err = PICO_ERR_EINVAL;
01533             return -1;
01534           } else {
01535             so_mcast_dbg("pico_socket_setoption: ERROR duplicate PICO_IP_ADD_MEMBERSHIP\n");
01536             pico_err = PICO_ERR_EINVAL;
01537             return -1;
01538           }
01539         } else {
01540           listen = pico_zalloc(sizeof(struct pico_mcast_listen));
01541           if (!listen) {
01542             pico_err = PICO_ERR_ENOMEM;
01543             return -1;
01544           }
01545           listen->filter_mode = PICO_IP_MULTICAST_EXCLUDE;
01546           listen->mcast_link = mreq->mcast_link_addr;
01547           listen->mcast_group = mreq->mcast_group_addr;
01548           listen->MCASTSources.root = &LEAF;
01549           listen->MCASTSources.compare = mcast_sources_cmp;
01550           pico_tree_insert(s->MCASTListen, listen);
01551         }
01552 
01553         pico_tree_insert(&MCASTSockets, s);
01554         filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
01555         if (filter_mode < 0) 
01556           return -1;
01557 
01558         return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, filter_mode, &MCASTFilter);
01559       }          
01560       break;
01561 
01562     case PICO_IP_DROP_MEMBERSHIP:
01563       /* EXCLUDE mode */
01564       if (s->proto->proto_number == PICO_PROTO_UDP) {
01565         uint8_t filter_mode = 0;
01566         struct pico_ip_mreq *mreq = NULL;
01567         struct pico_mcast_listen *listen = NULL, ltest = {0};
01568         struct pico_ip4 *source = NULL;
01569         struct pico_ipv4_link *mcast_link = NULL;
01570         struct pico_tree_node *index, *_tmp;
01571 
01572         if (!value) {
01573           pico_err = PICO_ERR_EINVAL;
01574           return -1;
01575         }
01576         mreq = (struct pico_ip_mreq *) value;
01577         mcast_link = pico_socket_setoption_mcastargs_validation(mreq, NULL);
01578         if (!mcast_link) {
01579           pico_err = PICO_ERR_EINVAL;
01580           return -1;
01581         }
01582         if (!mreq->mcast_link_addr.addr)
01583           mreq->mcast_link_addr.addr = mcast_link->address.addr;
01584 
01585         if (!s->MCASTListen) { /* No RBTree allocated yet */
01586           so_mcast_dbg("socket_setoption: ERROR PICO_IP_DROP_MEMBERSHIP before any PICO_IP_ADD_MEMBERSHIP/SOURCE_MEMBERSHIP\n");
01587           pico_err = PICO_ERR_EINVAL;
01588           return -1;
01589         }
01590         ltest.mcast_link = mreq->mcast_link_addr;
01591         ltest.mcast_group = mreq->mcast_group_addr;
01592         listen = pico_tree_findKey(s->MCASTListen, &ltest);
01593         if (!listen) {
01594           so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_MEMBERSHIP before PICO_IP_ADD_MEMBERSHIP/SOURCE_MEMBERSHIP\n");
01595           pico_err = PICO_ERR_EADDRNOTAVAIL;
01596           return -1;
01597         } else {
01598           pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp)
01599           {
01600             source = index->keyValue;
01601             pico_tree_delete(&listen->MCASTSources, source);
01602             pico_free(source);
01603           }
01604           pico_tree_delete(s->MCASTListen, listen);
01605           pico_free(listen);
01606           if (pico_tree_empty(s->MCASTListen)) {
01607             pico_free(s->MCASTListen);
01608             s->MCASTListen = NULL;
01609             pico_tree_delete(&MCASTSockets, s);
01610           }
01611         }
01612 
01613         filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
01614         if (filter_mode < 0) 
01615           return -1;
01616 
01617         return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, filter_mode, &MCASTFilter);
01618       }          
01619       break;
01620 
01621     case PICO_IP_UNBLOCK_SOURCE:
01622       /* EXCLUDE mode */
01623       if (s->proto->proto_number == PICO_PROTO_UDP) {
01624         uint8_t filter_mode = 0;
01625         struct pico_ip_mreq_source *mreq = NULL;
01626         struct pico_mcast_listen *listen = NULL, ltest = {0};
01627         struct pico_ip4 *source = NULL, stest = {0};
01628         struct pico_ipv4_link *mcast_link = NULL;
01629 
01630         if (!value) {
01631           pico_err = PICO_ERR_EINVAL;
01632           return -1;
01633         }
01634         mreq = (struct pico_ip_mreq_source *) value;
01635         mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq);
01636         if (!mcast_link) {
01637           pico_err = PICO_ERR_EINVAL;
01638           return -1;
01639         }
01640         if (!mreq->mcast_link_addr.addr)
01641           mreq->mcast_link_addr.addr = mcast_link->address.addr;
01642 
01643         if (!s->MCASTListen) { /* No RBTree allocated yet */
01644           so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_UNBLOCK_SOURCE before any PICO_IP_ADD_MEMBERSHIP\n");
01645           pico_err = PICO_ERR_EINVAL;
01646           return -1;
01647         }
01648         ltest.mcast_link = mreq->mcast_link_addr;
01649         ltest.mcast_group = mreq->mcast_group_addr;
01650         listen = pico_tree_findKey(s->MCASTListen, &ltest);
01651         if (!listen) {
01652           so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_UNBLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
01653           pico_err = PICO_ERR_EINVAL;
01654           return -1;
01655         } else {
01656           if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
01657             so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
01658             pico_err = PICO_ERR_EINVAL;
01659             return -1;
01660           }
01661           stest.addr = mreq->mcast_source_addr.addr;
01662           source = pico_tree_findKey(&listen->MCASTSources, &stest);
01663           if (!source) {
01664             so_mcast_dbg("pico_socket_setoption: ERROR address to unblock not in source list\n");
01665             pico_err = PICO_ERR_EADDRNOTAVAIL;
01666             return -1;
01667           } else {
01668             pico_tree_delete(&listen->MCASTSources, source);
01669             pico_free(source);
01670           }
01671         }
01672 
01673         filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
01674         if (filter_mode < 0) 
01675           return -1;
01676 
01677         return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, filter_mode, &MCASTFilter);
01678       }          
01679       break;
01680 
01681     case PICO_IP_BLOCK_SOURCE:
01682       /* EXCLUDE mode */
01683       if (s->proto->proto_number == PICO_PROTO_UDP) {
01684         uint8_t filter_mode = 0;
01685         struct pico_ip_mreq_source *mreq = NULL;
01686         struct pico_mcast_listen *listen = NULL, ltest = {0};
01687         struct pico_ip4 *source = NULL, stest = {0};
01688         struct pico_ipv4_link *mcast_link = NULL;
01689 
01690         if (!value) {
01691           pico_err = PICO_ERR_EINVAL;
01692           return -1;
01693         }
01694         mreq = (struct pico_ip_mreq_source *) value;
01695         mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq);
01696         if (!mcast_link) {
01697           pico_err = PICO_ERR_EINVAL;
01698           return -1;
01699         }
01700         if (!mreq->mcast_link_addr.addr)
01701           mreq->mcast_link_addr.addr = mcast_link->address.addr;
01702 
01703         if (!s->MCASTListen) { /* No RBTree allocated yet */
01704           so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_BLOCK_SOURCE before any PICO_IP_ADD_MEMBERSHIP\n");
01705           pico_err = PICO_ERR_EINVAL;
01706           return -1;
01707         }
01708         ltest.mcast_link = mreq->mcast_link_addr;
01709         ltest.mcast_group = mreq->mcast_group_addr;
01710         listen = pico_tree_findKey(s->MCASTListen, &ltest);
01711         if (!listen) {
01712           so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_BLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n");
01713           pico_err = PICO_ERR_EINVAL;
01714           return -1;
01715         } else {
01716           if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) {
01717             so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n");
01718             pico_err = PICO_ERR_EINVAL;
01719             return -1;
01720           }
01721           stest.addr = mreq->mcast_source_addr.addr;
01722           source = pico_tree_findKey(&listen->MCASTSources, &stest);
01723           if (source) {
01724             so_mcast_dbg("pico_socket_setoption: ERROR address to block already in source list\n");
01725             pico_err = PICO_ERR_EADDRNOTAVAIL;
01726             return -1;
01727           } else {
01728             source = pico_zalloc(sizeof(struct pico_ip4));
01729             if (!source) {
01730               pico_err = PICO_ERR_ENOMEM;
01731               return -1;
01732             }
01733             source->addr = mreq->mcast_source_addr.addr;
01734             pico_tree_insert(&listen->MCASTSources, source);
01735           }
01736         }
01737 
01738         filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
01739         if (filter_mode < 0) 
01740           return -1;
01741 
01742         return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, filter_mode, &MCASTFilter);
01743       }          
01744       break;
01745 
01746     case PICO_IP_ADD_SOURCE_MEMBERSHIP:
01747       /* INCLUDE mode */
01748       if (s->proto->proto_number == PICO_PROTO_UDP) {
01749         uint8_t filter_mode = 0, reference_count = 0;
01750         struct pico_ip_mreq_source *mreq = NULL;
01751         struct pico_mcast_listen *listen = NULL, ltest = {0};
01752         struct pico_ip4 *source = NULL, stest = {0};
01753         struct pico_ipv4_link *mcast_link = NULL;
01754 
01755         if (!value) {
01756           pico_err = PICO_ERR_EINVAL;
01757           return -1;
01758         }
01759         mreq = (struct pico_ip_mreq_source *) value;
01760         mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq);
01761         if (!mcast_link) {
01762           pico_err = PICO_ERR_EINVAL;
01763           return -1;
01764         }
01765         if (!mreq->mcast_link_addr.addr)
01766           mreq->mcast_link_addr.addr = mcast_link->address.addr;
01767 
01768         if (!s->MCASTListen) { /* No RBTree allocated yet */
01769           s->MCASTListen = pico_zalloc(sizeof(struct pico_tree));
01770           if (!s->MCASTListen) {
01771             pico_err = PICO_ERR_ENOMEM;
01772             return -1;
01773           }
01774           s->MCASTListen->root = &LEAF;
01775           s->MCASTListen->compare = mcast_listen_cmp;
01776         }
01777         ltest.mcast_link = mreq->mcast_link_addr;
01778         ltest.mcast_group = mreq->mcast_group_addr;
01779         listen = pico_tree_findKey(s->MCASTListen, &ltest);
01780         if (listen) {
01781           if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
01782             so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
01783             pico_err = PICO_ERR_EINVAL;
01784             return -1;
01785           }
01786           stest.addr = mreq->mcast_source_addr.addr;
01787           source = pico_tree_findKey(&listen->MCASTSources, &stest);
01788           if (source) {
01789             so_mcast_dbg("pico_socket_setoption: ERROR source address to allow already in source list\n");
01790             pico_err = PICO_ERR_EADDRNOTAVAIL;
01791             return -1;
01792           } else {
01793             source = pico_zalloc(sizeof(struct pico_ip4));
01794             if (!source) {
01795               pico_err = PICO_ERR_ENOMEM;
01796               return -1;
01797             }
01798             source->addr = mreq->mcast_source_addr.addr;
01799             pico_tree_insert(&listen->MCASTSources, source);
01800           }
01801         } else {
01802           listen = pico_zalloc(sizeof(struct pico_mcast_listen));
01803           if (!listen) {
01804             pico_err = PICO_ERR_ENOMEM;
01805             return -1;
01806           }
01807           listen->filter_mode = PICO_IP_MULTICAST_INCLUDE;
01808           listen->mcast_link = mreq->mcast_link_addr;
01809           listen->mcast_group = mreq->mcast_group_addr;
01810           listen->MCASTSources.root = &LEAF;
01811           listen->MCASTSources.compare = mcast_sources_cmp;
01812           source = pico_zalloc(sizeof(struct pico_ip4));
01813           if (!source) {
01814             pico_free(listen);
01815             pico_err = PICO_ERR_ENOMEM;
01816             return -1;
01817           }
01818           source->addr = mreq->mcast_source_addr.addr;
01819           pico_tree_insert(&listen->MCASTSources, source);
01820           pico_tree_insert(s->MCASTListen, listen);
01821           reference_count = 1;
01822         }
01823 
01824         pico_tree_insert(&MCASTSockets, s);
01825         filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
01826         if (filter_mode < 0) 
01827           return -1;
01828 
01829         return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, reference_count, filter_mode, &MCASTFilter);
01830       }          
01831       break;
01832 
01833     case PICO_IP_DROP_SOURCE_MEMBERSHIP:
01834       /* INCLUDE mode */
01835       if (s->proto->proto_number == PICO_PROTO_UDP) {
01836         uint8_t filter_mode = 0, reference_count = 0;
01837         struct pico_ip_mreq_source *mreq = NULL;
01838         struct pico_mcast_listen *listen = NULL, ltest = {0};
01839         struct pico_ip4 *source = NULL, stest = {0};
01840         struct pico_ipv4_link *mcast_link = NULL;
01841 
01842         if (!value) {
01843           pico_err = PICO_ERR_EINVAL;
01844           return -1;
01845         }
01846         mreq = (struct pico_ip_mreq_source *) value;
01847         mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq);
01848         if (!mcast_link) {
01849           pico_err = PICO_ERR_EINVAL;
01850           return -1;
01851         }
01852         if (!mreq->mcast_link_addr.addr)
01853           mreq->mcast_link_addr.addr = mcast_link->address.addr;
01854 
01855         if (!s->MCASTListen) { /* No RBTree allocated yet */
01856           so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_SOURCE_MEMBERSHIP before any PICO_IP_ADD_SOURCE_MEMBERSHIP\n");
01857           pico_err = PICO_ERR_EINVAL;
01858           return -1;
01859         }
01860         ltest.mcast_link = mreq->mcast_link_addr;
01861         ltest.mcast_group = mreq->mcast_group_addr;
01862         listen = pico_tree_findKey(s->MCASTListen, &ltest);
01863         if (!listen) {
01864           so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_SOURCE_MEMBERSHIP before PICO_IP_ADD_SOURCE_MEMBERSHIP\n");
01865           pico_err = PICO_ERR_EADDRNOTAVAIL;
01866           return -1;
01867         } else {
01868           if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) {
01869             so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n");
01870             pico_err = PICO_ERR_EINVAL;
01871             return -1;
01872           }
01873           stest.addr = mreq->mcast_source_addr.addr;
01874           source = pico_tree_findKey(&listen->MCASTSources, &stest);
01875           if (!source) {
01876             so_mcast_dbg("pico_socket_setoption: ERROR address to drop not in source list\n");
01877             pico_err = PICO_ERR_EADDRNOTAVAIL;
01878             return -1;
01879           } else {
01880             pico_tree_delete(&listen->MCASTSources, source);
01881             pico_free(source);
01882             if (pico_tree_empty(&listen->MCASTSources)) { /* 1 if empty, 0 otherwise */
01883               reference_count = 1;
01884               pico_tree_delete(s->MCASTListen, listen);
01885               pico_free(listen);
01886               if (pico_tree_empty(s->MCASTListen)) {
01887                 pico_free(s->MCASTListen);
01888                 s->MCASTListen = NULL;
01889                 pico_tree_delete(&MCASTSockets, s);
01890               }
01891             }
01892           }
01893         }
01894 
01895         filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr);
01896         if (filter_mode < 0) 
01897           return -1;
01898 
01899         return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, reference_count, filter_mode, &MCASTFilter);
01900       }          
01901       break;
01902 #endif /* PICO_SUPPORT_MCAST */
01903 
01904     default:
01905           pico_err = PICO_ERR_EINVAL;
01906           return -1;
01907   }
01908 
01909   if (pico_err != PICO_ERR_NOERR)
01910     return -1;
01911   else
01912     return 0;
01913 }
01914 
01915 #define PICO_SOCKET_GETOPT(socket,index) ((socket->opt_flags & (1 << index)) != 0)
01916 
01917 int pico_socket_getoption(struct pico_socket *s, int option, void *value)
01918 {  
01919   if (!s || !value) {
01920     pico_err = PICO_ERR_EINVAL;
01921     return -1;
01922   }
01923 
01924   switch (option)
01925   {
01926 #ifdef PICO_SUPPORT_TCP
01927     case PICO_TCP_NODELAY:
01928           if (s->proto->proto_number == PICO_PROTO_TCP)
01929             /* state of the NODELAY option */
01930             *(int *)value = PICO_SOCKET_GETOPT(s,PICO_SOCKET_OPT_TCPNODELAY);
01931           else
01932             *(int *)value = 0;
01933           break;
01934 #endif
01935 
01936 #ifdef PICO_SUPPORT_MCAST
01937     case PICO_IP_MULTICAST_IF:
01938           pico_err = PICO_ERR_EOPNOTSUPP;
01939           return -1;
01940           break;
01941 
01942     case PICO_IP_MULTICAST_TTL:
01943           if (s->proto->proto_number == PICO_PROTO_UDP) {
01944             pico_udp_get_mc_ttl(s, (uint8_t *) value);
01945           } else {
01946             *(uint8_t *)value = 0;
01947             pico_err = PICO_ERR_EINVAL;
01948             return -1;
01949           }            
01950           break;
01951 
01952     case PICO_IP_MULTICAST_LOOP:
01953           if (s->proto->proto_number == PICO_PROTO_UDP) {
01954             *(uint8_t *)value = PICO_SOCKET_GETOPT(s,PICO_SOCKET_OPT_MULTICAST_LOOP);
01955           } else {
01956             *(uint8_t *)value = 0;
01957             pico_err = PICO_ERR_EINVAL;
01958             return -1;
01959           }
01960           break;
01961 #endif /* PICO_SUPPORT_MCAST */
01962 
01963     default:
01964           pico_err = PICO_ERR_EINVAL;
01965           return -1;
01966   }
01967 
01968   return 0;
01969 }
01970 
01971 
01972 int pico_socket_shutdown(struct pico_socket *s, int mode)
01973 {
01974   if (!s) {
01975     pico_err = PICO_ERR_EINVAL;
01976     return -1;
01977   } else {
01978     /* check if exists in tree */
01979     /* See task #178 */
01980     if (pico_check_socket(s) != 0) {
01981       pico_free(s); /* close socket after bind or connect failed */
01982       return 0;
01983     }
01984   }
01985 
01986 #ifdef PICO_SUPPORT_UDP
01987   if (PROTO(s) == PICO_PROTO_UDP) {
01988     if (mode & PICO_SHUT_RDWR)
01989       pico_socket_alter_state(s, PICO_SOCKET_STATE_CLOSED, PICO_SOCKET_STATE_CLOSING |PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED, 0);
01990     else if (mode & PICO_SHUT_RD)
01991       pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0);
01992   }
01993 #endif
01994 #ifdef PICO_SUPPORT_TCP
01995   if (PROTO(s) == PICO_PROTO_TCP) {
01996       if(mode & PICO_SHUT_RDWR)
01997           pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL | PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
01998       else if (mode & PICO_SHUT_WR)
01999       pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL, 0, 0);
02000     else if (mode & PICO_SHUT_RD)
02001       pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0);
02002 
02003   }
02004 #endif
02005   return 0;
02006 }
02007 
02008 int pico_socket_close(struct pico_socket *s)
02009 {
02010   return pico_socket_shutdown(s, PICO_SHUT_RDWR);
02011 }
02012 
02013 #ifdef PICO_SUPPORT_CRC
02014 static inline int pico_transport_crc_check(struct pico_frame *f)
02015 {
02016   struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr;
02017   struct pico_udp_hdr *udp_hdr = NULL;
02018   uint16_t checksum_invalid = 1;
02019 
02020   switch (net_hdr->proto)
02021   {
02022     case PICO_PROTO_TCP:
02023       checksum_invalid = short_be(pico_tcp_checksum_ipv4(f));
02024       //dbg("TCP CRC validation == %u\n", checksum_invalid);
02025       if (checksum_invalid) {
02026         //dbg("TCP CRC: validation failed!\n");
02027         pico_frame_discard(f);
02028         return 0;
02029       }
02030       break;
02031 
02032     case PICO_PROTO_UDP:
02033       udp_hdr = (struct pico_udp_hdr *) f->transport_hdr;
02034       if (short_be(udp_hdr->crc)) {
02035         checksum_invalid = short_be(pico_udp_checksum_ipv4(f));
02036         //dbg("UDP CRC validation == %u\n", checksum_invalid);
02037         if (checksum_invalid) {
02038           //dbg("UDP CRC: validation failed!\n");
02039           pico_frame_discard(f);
02040           return 0;
02041         }
02042       }
02043       break;
02044 
02045     default:
02046       // Do nothing
02047       break;
02048   }
02049   return 1;
02050 }
02051 #else
02052 static inline int pico_transport_crc_check(struct pico_frame *f)
02053 {
02054   return 1;
02055 }
02056 #endif /* PICO_SUPPORT_CRC */
02057 
02058 int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f)
02059 {
02060   struct pico_trans *hdr = (struct pico_trans *) f->transport_hdr;
02061   int ret = 0;
02062 
02063   if (!hdr) {
02064     pico_err = PICO_ERR_EFAULT;
02065     return -1;
02066   }
02067 
02068   ret = pico_transport_crc_check(f);
02069   if (ret < 1)
02070     return ret;
02071   else
02072     ret = 0;
02073 
02074   if ((hdr) && (pico_socket_deliver(self, f, hdr->dport) == 0))
02075     return ret;
02076 
02077   if (!IS_BCAST(f)) {
02078     dbg("Socket not found... \n");
02079     pico_notify_socket_unreachable(f);
02080 #ifdef PICO_SUPPORT_TCP
02081     /* if tcp protocol send RST segment */
02082     //if (self->proto_number == PICO_PROTO_TCP)
02083     //  pico_tcp_reply_rst(f);
02084 #endif
02085     ret = -1;
02086     pico_err = PICO_ERR_ENOENT;
02087   }
02088   pico_frame_discard(f);
02089   return ret;
02090 }
02091 
02092 #define SL_LOOP_MIN 1
02093 
02094 
02095 int pico_sockets_loop(int loop_score)
02096 {
02097   static struct pico_tree_node *index_udp, * index_tcp;
02098 
02099   struct pico_sockport *start;
02100   struct pico_socket *s;
02101 
02102 #ifdef PICO_SUPPORT_UDP
02103   struct pico_frame *f;
02104 
02105   if (sp_udp == NULL)
02106   {
02107     index_udp = pico_tree_firstNode(UDPTable.root);
02108     sp_udp = index_udp->keyValue;
02109   }
02110 
02111   /* init start node */
02112   start = sp_udp;
02113 
02114   /* round-robin all transport protocols, break if traversed all protocols */
02115   while (loop_score > SL_LOOP_MIN && sp_udp != NULL) {
02116     struct pico_tree_node * index;
02117 
02118     pico_tree_foreach(index,&sp_udp->socks){
02119       s = index->keyValue;
02120       f = pico_dequeue(&s->q_out);
02121       while (f && (loop_score > 0)) {
02122         pico_proto_udp.push(&pico_proto_udp, f);
02123         loop_score -= 1;
02124         f = pico_dequeue(&s->q_out);
02125       }
02126     }
02127 
02128     index_udp = pico_tree_next(index_udp);
02129     sp_udp = index_udp->keyValue;
02130 
02131     if (sp_udp == NULL)
02132     {
02133       index_udp = pico_tree_firstNode(UDPTable.root);
02134       sp_udp = index_udp->keyValue;
02135     }
02136     if (sp_udp == start)
02137       break;
02138   }
02139 #endif
02140 
02141 #ifdef PICO_SUPPORT_TCP
02142   if (sp_tcp == NULL)
02143   {
02144     index_tcp = pico_tree_firstNode(TCPTable.root);
02145     sp_tcp = index_tcp->keyValue;
02146   }
02147 
02148   /* init start node */
02149   start = sp_tcp;
02150 
02151   while (loop_score > SL_LOOP_MIN && sp_tcp != NULL) {
02152     struct pico_tree_node * index;
02153     pico_tree_foreach(index, &sp_tcp->socks){
02154       s = index->keyValue;
02155       loop_score = pico_tcp_output(s, loop_score);
02156       if ((s->ev_pending) && s->wakeup) {
02157         s->wakeup(s->ev_pending, s);
02158       }
02159       if (loop_score <= 0) {
02160         loop_score = 0;
02161         break;
02162       }
02163     }
02164 
02165     /* check if RB_FOREACH ended, if not, break to keep the cur sp_tcp */
02166     if (s != NULL)
02167       break;
02168 
02169     index_tcp = pico_tree_next(index_tcp);
02170     sp_tcp = index_tcp->keyValue;
02171 
02172     if (sp_tcp == NULL)
02173     {
02174       index_tcp = pico_tree_firstNode(TCPTable.root);
02175       sp_tcp = index_tcp->keyValue;
02176     }
02177     if (sp_tcp == start)
02178       break;
02179   }
02180 #endif
02181 
02182   return loop_score;
02183 }
02184 
02185 
02186 struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, int len)
02187 {
02188   struct pico_frame *f = NULL;
02189 
02190 #ifdef PICO_SUPPORT_IPV6
02191   if (IS_SOCK_IPV6(s))
02192     f = pico_proto_ipv6.alloc(&pico_proto_ipv6, len);
02193 #endif
02194 
02195 #ifdef PICO_SUPPORT_IPV4
02196   if (IS_SOCK_IPV4(s))
02197     f = pico_proto_ipv4.alloc(&pico_proto_ipv4, len);
02198 #endif
02199   if (!f) {
02200     pico_err = PICO_ERR_ENOMEM;
02201     return f;
02202   }
02203   f->payload = f->transport_hdr;
02204   f->payload_len = len;
02205   f->sock = s;
02206   return f;
02207 }
02208 
02209 int pico_transport_error(struct pico_frame *f, uint8_t proto, int code)
02210 {
02211   int ret = -1;
02212   struct pico_trans *trans = (struct pico_trans*) f->transport_hdr;
02213   struct pico_sockport *port = NULL;
02214   struct pico_socket *s = NULL;
02215   switch (proto) {
02216 
02217 
02218 #ifdef PICO_SUPPORT_UDP
02219   case PICO_PROTO_UDP:
02220     port = pico_get_sockport(proto, trans->sport);
02221     break;
02222 #endif
02223 
02224 #ifdef PICO_SUPPORT_TCP
02225   case PICO_PROTO_TCP:
02226     port = pico_get_sockport(proto, trans->sport);
02227     break;
02228 #endif
02229 
02230   default:
02231     /* Protocol not available */
02232     ret = -1;
02233   }
02234   if (port) {
02235     struct pico_tree_node * index;
02236     ret = 0;
02237 
02238     pico_tree_foreach(index,&port->socks) {
02239       s = index->keyValue;
02240       if (trans->dport == s->remote_port) {
02241         if (s->wakeup) {
02242           //dbg("SOCKET ERROR FROM ICMP NOTIFICATION. (icmp code= %d)\n\n", code);
02243           switch(code) {
02244             case PICO_ICMP_UNREACH_PROTOCOL:
02245               pico_err = PICO_ERR_EPROTO;
02246               break;
02247 
02248             case PICO_ICMP_UNREACH_PORT:
02249               pico_err = PICO_ERR_ECONNREFUSED;
02250               break;
02251 
02252             case PICO_ICMP_UNREACH_NET:
02253             case PICO_ICMP_UNREACH_NET_PROHIB:
02254             case PICO_ICMP_UNREACH_NET_UNKNOWN:
02255               pico_err = PICO_ERR_ENETUNREACH;
02256               break;
02257 
02258             default:
02259               pico_err = PICO_ERR_EHOSTUNREACH;
02260           }
02261           s->wakeup(PICO_SOCK_EV_ERR, s);
02262         }
02263         break;
02264       }
02265     }
02266   }
02267   pico_frame_discard(f);
02268   return ret;
02269 }
02270 #endif
02271 #endif