Free (GPLv2) TCP/IP stack developed by TASS Belgium

Dependents:   lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pico_socket_udp.c Source File

pico_socket_udp.c

00001 #include "pico_config.h"
00002 #include "pico_socket.h"
00003 #include "pico_udp.h"
00004 #include "pico_socket_multicast.h"
00005 #include "pico_ipv4.h"
00006 #include "pico_ipv6.h"
00007 #include "pico_socket_udp.h"
00008 
00009 #define UDP_FRAME_OVERHEAD (sizeof(struct pico_frame))
00010 
00011 
00012 struct pico_socket *pico_socket_udp_open(void)
00013 {
00014     struct pico_socket *s = NULL;
00015 #ifdef PICO_SUPPORT_UDP
00016     s = pico_udp_open();
00017     if (!s) {
00018         pico_err = PICO_ERR_ENOMEM;
00019         return NULL;
00020     }
00021 
00022     s->proto = &pico_proto_udp;
00023     s->q_in.overhead = UDP_FRAME_OVERHEAD;
00024     s->q_out.overhead = UDP_FRAME_OVERHEAD;
00025 #endif
00026     return s;
00027 }
00028 
00029 
00030 #ifdef PICO_SUPPORT_IPV4
00031 static inline int pico_socket_udp_deliver_ipv4_mcast_initial_checks(struct pico_socket *s, struct pico_frame *f)
00032 {
00033     struct pico_ip4 p_dst;
00034     struct pico_ipv4_hdr *ip4hdr;
00035 
00036     ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
00037     p_dst.addr = ip4hdr->dst.addr;
00038     if (pico_ipv4_is_multicast(p_dst.addr) && (pico_socket_mcast_filter(s, (union pico_address *)&ip4hdr->dst, (union pico_address *)&ip4hdr->src) < 0))
00039         return -1;
00040 
00041 
00042     if ((pico_ipv4_link_get(&ip4hdr->src)) && (PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP) == 0u)) {
00043         /* Datagram from ourselves, Loop disabled, discarding. */
00044         return -1;
00045     }
00046 
00047     return 0;
00048 }
00049 
00050 
00051 static int pico_socket_udp_deliver_ipv4_mcast(struct pico_socket *s, struct pico_frame *f)
00052 {
00053     struct pico_ip4 s_local;
00054     struct pico_frame *cpy;
00055     struct pico_device *dev = pico_ipv4_link_find(&s->local_addr.ip4);
00056 
00057     s_local.addr = s->local_addr.ip4.addr;
00058 
00059     if (pico_socket_udp_deliver_ipv4_mcast_initial_checks(s, f) < 0)
00060         return 0;
00061 
00062     if ((s_local.addr == PICO_IPV4_INADDR_ANY) || /* If our local ip is ANY, or.. */
00063         (dev == f->dev)) {     /* the source of the bcast packet is a neighbor... */
00064         cpy = pico_frame_copy(f);
00065         if (!cpy)
00066             return -1;
00067 
00068         if (pico_enqueue(&s->q_in, cpy) > 0) {
00069             if (s->wakeup)
00070                 s->wakeup(PICO_SOCK_EV_RD, s);
00071         }
00072         else
00073             pico_frame_discard(cpy);
00074     }
00075 
00076     return 0;
00077 }
00078 
00079 static int pico_socket_udp_deliver_ipv4_unicast(struct pico_socket *s, struct pico_frame *f)
00080 {
00081     struct pico_frame *cpy;
00082     /* Either local socket is ANY, or matches dst */
00083     cpy = pico_frame_copy(f);
00084     if (!cpy)
00085         return -1;
00086 
00087     if (pico_enqueue(&s->q_in, cpy) > 0) {
00088         if (s->wakeup)
00089             s->wakeup(PICO_SOCK_EV_RD, s);
00090     } else {
00091         pico_frame_discard(cpy);
00092     }
00093 
00094     return 0;
00095 }
00096 
00097 
00098 static int pico_socket_udp_deliver_ipv4(struct pico_socket *s, struct pico_frame *f)
00099 {
00100     int ret = 0;
00101     struct pico_ip4 s_local, p_dst;
00102     struct pico_ipv4_hdr *ip4hdr;
00103     ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr);
00104     s_local.addr = s->local_addr.ip4.addr;
00105     p_dst.addr = ip4hdr->dst.addr;
00106     if ((pico_ipv4_is_broadcast(p_dst.addr)) || pico_ipv4_is_multicast(p_dst.addr)) {
00107         ret = pico_socket_udp_deliver_ipv4_mcast(s, f);
00108     } else if ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr)) {
00109         ret = pico_socket_udp_deliver_ipv4_unicast(s, f);
00110     }
00111 
00112     pico_frame_discard(f);
00113     return ret;
00114 }
00115 #endif
00116 
00117 #ifdef PICO_SUPPORT_IPV6
00118 static inline int pico_socket_udp_deliver_ipv6_mcast(struct pico_socket *s, struct pico_frame *f)
00119 {
00120     struct pico_ipv6_hdr *ip6hdr;
00121     struct pico_frame *cpy;
00122     struct pico_device *dev = pico_ipv6_link_find(&s->local_addr.ip6);
00123 
00124     ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr);
00125 
00126     if ((pico_ipv6_link_get(&ip6hdr->src)) && (PICO_SOCKET_GETOPT(s, PICO_SOCKET_OPT_MULTICAST_LOOP) == 0u)) {
00127         /* Datagram from ourselves, Loop disabled, discarding. */
00128         return 0;
00129     }
00130 
00131 
00132     if (pico_ipv6_is_unspecified(s->local_addr.ip6.addr) || /* If our local ip is ANY, or.. */
00133         (dev == f->dev)) {     /* the source of the bcast packet is a neighbor... */
00134         cpy = pico_frame_copy(f);
00135         if (!cpy)
00136         {
00137             return -1;
00138         }
00139 
00140         if (pico_enqueue(&s->q_in, cpy) > 0) {
00141             if (s->wakeup)
00142                 s->wakeup(PICO_SOCK_EV_RD, s);
00143         }
00144         else
00145             pico_frame_discard(cpy);
00146     }
00147 
00148     return 0;
00149 }
00150 
00151 static int pico_socket_udp_deliver_ipv6(struct pico_socket *s, struct pico_frame *f)
00152 {
00153     struct pico_ip6 s_local, p_dst;
00154     struct pico_ipv6_hdr *ip6hdr;
00155     struct pico_frame *cpy;
00156     ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr);
00157     s_local = s->local_addr.ip6;
00158     p_dst = ip6hdr->dst;
00159     if ((pico_ipv6_is_multicast(p_dst.addr))) {
00160         int retval = pico_socket_udp_deliver_ipv6_mcast(s, f);
00161         pico_frame_discard(f);
00162         return retval;
00163     } 
00164     else if (pico_ipv6_is_unspecified(s->local_addr.ip6.addr) || (pico_ipv6_compare(&s_local, &p_dst) == 0))
00165     { /* Either local socket is ANY, or matches dst */
00166         cpy = pico_frame_copy(f);
00167         if (!cpy)
00168         {
00169             pico_frame_discard(f);
00170             return -1;
00171         }
00172 
00173         if (pico_enqueue(&s->q_in, cpy) > 0) {
00174             if (s->wakeup)
00175                 s->wakeup(PICO_SOCK_EV_RD, s);
00176         }
00177     }
00178 
00179     pico_frame_discard(f);
00180     return 0;
00181 }
00182 #endif
00183 
00184 
00185 int pico_socket_udp_deliver(struct pico_sockport *sp, struct pico_frame *f)
00186 {
00187     struct pico_tree_node *index = NULL;
00188     struct pico_tree_node *_tmp;
00189     struct pico_socket *s = NULL;
00190     pico_err = PICO_ERR_EPROTONOSUPPORT;
00191     #ifdef PICO_SUPPORT_UDP
00192     pico_err = PICO_ERR_NOERR;
00193     pico_tree_foreach_safe(index, &sp->socks, _tmp){
00194         s = index->keyValue;
00195         if (IS_IPV4(f)) { /* IPV4 */
00196 #ifdef PICO_SUPPORT_IPV4
00197             return pico_socket_udp_deliver_ipv4(s, f);
00198 #endif
00199         } else if (IS_IPV6(f)) {
00200 #ifdef PICO_SUPPORT_IPV6
00201             return pico_socket_udp_deliver_ipv6(s, f);
00202 #endif
00203         } else {
00204             /* something wrong in the packet header*/
00205         }
00206     } /* FOREACH */
00207     pico_frame_discard(f);
00208     if (s)
00209         return 0;
00210 
00211     pico_err = PICO_ERR_ENXIO;
00212   #endif
00213     return -1;
00214 }
00215 
00216 int pico_setsockopt_udp(struct pico_socket *s, int option, void *value)
00217 {
00218     switch(option) {
00219     case PICO_SOCKET_OPT_RCVBUF:
00220         s->q_in.max_size = (*(uint32_t*)value);
00221         return 0;
00222     case PICO_SOCKET_OPT_SNDBUF:
00223         s->q_out.max_size = (*(uint32_t*)value);
00224         return 0;
00225     }
00226 
00227     /* switch's default */
00228 #ifdef PICO_SUPPORT_MCAST
00229     return pico_setsockopt_mcast(s, option, value);
00230 #else
00231     pico_err = PICO_ERR_EINVAL;
00232     return -1;
00233 #endif
00234 }
00235 
00236 int pico_getsockopt_udp(struct pico_socket *s, int option, void *value)
00237 {
00238     uint32_t *val = (uint32_t *)value;
00239     switch(option) {
00240     case PICO_SOCKET_OPT_RCVBUF:
00241         *val = s->q_in.max_size;
00242         return 0;
00243     case PICO_SOCKET_OPT_SNDBUF:
00244         *val = s->q_out.max_size;
00245         return 0;
00246     }
00247 
00248     /* switch's default */
00249 #ifdef PICO_SUPPORT_MCAST
00250     return pico_getsockopt_mcast(s, option, value);
00251 #else
00252     pico_err = PICO_ERR_EINVAL;
00253     return -1;
00254 #endif
00255 }
00256