From: <ljs...@us...> - 2012-05-24 00:59:46
|
Revision: 769 http://cadcdev.svn.sourceforge.net/cadcdev/?rev=769&view=rev Author: ljsebald Date: 2012-05-24 00:59:36 +0000 (Thu, 24 May 2012) Log Message: ----------- A few changes to how the internal networking stack works (some are quite major): 1. Add a input function to the fs_socket interface, which is used to input a packet into the protocol. This way, new protocols can be added without actually changing anything internally (if someone really wants to). 2. Change fs_socket_setflags() to take a uint32, and define some flags for it. If you were using this before with O_NONBLOCK, you should change that to FS_SOCKET_NONBLOCK now. 3. Change net_ipv4_input_proto() to use the new fs_socket_input() function for any protocols it doesn't handle internally. 4. Fix DHCP so that it doesn't crash if the DHCP thread is running when you shutdown. 5. Change UDP to use IPv6 for everything internally. The IPv6 code will automatically call down to the IPv4 stuff if appropriate, so this makes things a lot easier internally. 6. Make it so that you can create IPv6 UDP sockets. Note that you can't actually receive IPv6 UDP packets yet, but you should be able to send them just fine. Modified Paths: -------------- kos/include/kos/fs_socket.h kos/kernel/fs/fs_socket.c kos/kernel/net/net_dhcp.c kos/kernel/net/net_ipv4.c kos/kernel/net/net_udp.c Removed Paths: ------------- kos/kernel/net/net_udp.h Modified: kos/include/kos/fs_socket.h =================================================================== --- kos/include/kos/fs_socket.h 2012-05-24 00:50:27 UTC (rev 768) +++ kos/include/kos/fs_socket.h 2012-05-24 00:59:36 UTC (rev 769) @@ -1,7 +1,7 @@ /* KallistiOS ##version## kos/fs_socket.h - Copyright (C) 2006, 2009, 2010 Lawrence Sebald + Copyright (C) 2006, 2009, 2010, 2012 Lawrence Sebald */ @@ -13,16 +13,11 @@ doesn't export any files there, so that point is largely irrelevant. The filesystem is designed to be extensible, making it possible to add additional socket family handlers at runtime. Currently, the kernel only - implements UDP sockets over IPv4, but as mentioned, this can be extended in - a fairly straightforward manner. In general, as a user of KallistiOS - (someone not interested in adding additional socket family drivers), there's - very little in this file that will be of interest. + implements UDP sockets over IPv4 and IPv6, but as mentioned, this can be + extended in a fairly straightforward manner. In general, as a user of + KallistiOS (someone not interested in adding additional socket family + drivers), there's very little in this file that will be of interest. - Also, note, that currently there is no way to get input into a network - protocol added with this functionality only. At some point, I will add - protocol registration with net_ipv4 for that, however, I haven't had the - time to do so just yet. - \author Lawrence Sebald */ @@ -36,8 +31,10 @@ #include <arch/types.h> #include <kos/limits.h> #include <kos/fs.h> +#include <kos/net.h> #include <sys/queue.h> #include <sys/socket.h> +#include <stdint.h> struct fs_socket_proto; @@ -154,7 +151,7 @@ \retval 0 On success \see fs_socket_setflags */ - int (*setflags)(net_socket_t *s, int flags); + int (*setflags)(net_socket_t *s, uint32_t flags); /** \brief Accept a connection on a socket created with the protocol. @@ -265,6 +262,26 @@ \retval 0 On success */ int (*shutdownsock)(net_socket_t *s, int how); + + /** \brief Input a packet into a protocol. + + This function should read in the packet specified by the arguments and + sort out what exactly to do with it. This usually involves checking if + there is an open socket with the source address and adding it to a + packet queue if there is. + + \param src The interface the packet was input on + \param domain The low-level protocol used (AF_INET or AF_INET6) + \param hdr The low-level protocol header + \param data The packet itself, including any protcol headers, + but not any from lower-level protocols + \param size The size of the packet, not including any lower- + level protocol headers + \retval -1 On error (the packet is discarded) + \retval 0 On success + */ + int (*input)(netif_t *src, int domain, const void *hdr, const uint8 *data, + int size); } fs_socket_proto_t; /** \brief Initializer for the entry field in the fs_socket_proto_t struct. */ @@ -276,26 +293,61 @@ int fs_socket_shutdown(); /* \endcond */ +/** \defgroup sock_flags Socket flags + + These are the available flags to set with the fs_socket_setflags() function. + + Every flag after FS_SOCKET_FAM_MAX is for internal-use only, and should + never be passed into any functions. + @{ +*/ +#define FS_SOCKET_NONBLOCK 0x00000001 /** \brief Non-blocking operations */ +#define FS_SOCKET_V6ONLY 0x00000002 /** \brief IPv6 Only */ + +#define FS_SOCKET_GEN_MAX 0x00008000 /** \brief Maximum generic flag */ +#define FS_SOCKET_FAM_MAX 0x00800000 /** \brief Maximum family flag */ +/** @} */ + +/** \brief Input a packet into some socket family handler. + + This function is used by the lower-level network protocol handlers to input + packets for further processing by upper-level protocols. This will call the + input function on the family handler, if one is found. + + \param src The network interface the packet came in on + \param domain The low-level protocol used (AF_INET or AF_INET6) + \param protocol The upper-level protocol that we're looking for + \param hdr The low-level protocol header + \param data The upper-level packet, without any lower-level protocol + headers, but with the upper-level ones intact + \param size The size of the packet (the data parameter) + \retval -2 The protocol is not known + \retval -1 Protocol-level error processing packet + \retval 0 On success +*/ +int fs_socket_input(netif_t *src, int domain, int protocol, const void *hdr, + const uint8 *data, int size); + /** \brief Set flags on a socket file descriptor. This function can be used to set various flags on a socket file descriptor, similar to what one would use fcntl or ioctl on a normal system for. The - flags available for use here are largely protocol dependent, and for UDP - the only flag available is O_NONBLOCK. + flags available for use here are largely protocol dependent. \param sock The socket to operate on (returned from a call to the function socket()) \param flags The flags to set on the socket. \retval -1 On error, and sets errno as appropriate \retval 0 On success + \see sock_flags \par Error Conditions: \em EWOULDBLOCK - if the function would block while inappropriate to \n \em EBADF - if passed an invalid file descriptor \n \em ENOTSOCK - if passed a file descriptor other than a socket \n - \em EINVAL - if an invalid flag was passed in + \em EINVAL - if an invalid flag (or combination) was passed in */ -int fs_socket_setflags(int sock, int flags); +int fs_socket_setflags(int sock, uint32_t flags); /** \brief Add a new protocol for use with fs_socket. Modified: kos/kernel/fs/fs_socket.c =================================================================== --- kos/kernel/fs/fs_socket.c 2012-05-24 00:50:27 UTC (rev 768) +++ kos/kernel/fs/fs_socket.c 2012-05-24 00:59:36 UTC (rev 769) @@ -1,7 +1,7 @@ /* KallistiOS ##version## fs_socket.c - Copyright (C) 2006, 2009 Lawrence Sebald + Copyright (C) 2006, 2009, 2012 Lawrence Sebald */ @@ -18,9 +18,6 @@ #include <netinet/in.h> #include <arpa/inet.h> -#include "../net/net_ipv4.h" -#include "../net/net_udp.h" - /* Define the protocol list type */ TAILQ_HEAD(proto_list, fs_socket_proto); @@ -33,7 +30,7 @@ static recursive_lock_t *list_rlock = NULL; static void fs_socket_close(void *hnd) { - net_socket_t *sock = (net_socket_t *) hnd; + net_socket_t *sock = (net_socket_t *)hnd; rlock_lock(list_rlock); LIST_REMOVE(sock, sock_list); @@ -168,10 +165,28 @@ return 0; } -int fs_socket_setflags(int sock, int flags) { +int fs_socket_input(netif_t *src, int domain, int protocol, const void *hdr, + const uint8 *data, int size) { + fs_socket_proto_t *i; + int rv = -2; + + /* Find the protocol handler and call its input function... */ + rlock_lock(proto_rlock); + TAILQ_FOREACH(i, &protocols, entry) { + if(i->protocol == protocol) { + rv = i->input(src, domain, hdr, data, size); + break; + } + } + rlock_unlock(proto_rlock); + + return rv; +} + +int fs_socket_setflags(int sock, uint32_t flags) { net_socket_t *hnd; - hnd = (net_socket_t *) fs_get_handle(sock); + hnd = (net_socket_t *)fs_get_handle(sock); if(hnd == NULL) { errno = EBADF; return -1; @@ -217,8 +232,8 @@ net_socket_t *sock; fs_socket_proto_t *i; - /* We only support IPv4 sockets for now. */ - if(domain != PF_INET) { + /* We only support IPv4 and IPv6 sockets for now. */ + if(domain != PF_INET && domain != PF_INET6) { errno = EAFNOSUPPORT; return -1; } @@ -241,8 +256,8 @@ } /* Allocate the socket structure, if we have the space */ - sock = (net_socket_t *) malloc(sizeof(net_socket_t)); - if(!sock) { + sock = (net_socket_t *)malloc(sizeof(net_socket_t)); + if(!sock) { errno = ENOMEM; return -1; } @@ -274,7 +289,7 @@ int accept(int sock, struct sockaddr *address, socklen_t *address_len) { net_socket_t *hnd; - hnd = (net_socket_t *) fs_get_handle(sock); + hnd = (net_socket_t *)fs_get_handle(sock); if(hnd == NULL) { errno = EBADF; return -1; @@ -292,7 +307,7 @@ int bind(int sock, const struct sockaddr *address, socklen_t address_len) { net_socket_t *hnd; - hnd = (net_socket_t *) fs_get_handle(sock); + hnd = (net_socket_t *)fs_get_handle(sock); if(hnd == NULL) { errno = EBADF; return -1; @@ -310,7 +325,7 @@ int connect(int sock, const struct sockaddr *address, socklen_t address_len) { net_socket_t *hnd; - hnd = (net_socket_t *) fs_get_handle(sock); + hnd = (net_socket_t *)fs_get_handle(sock); if(hnd == NULL) { errno = EBADF; return -1; @@ -328,7 +343,7 @@ int listen(int sock, int backlog) { net_socket_t *hnd; - hnd = (net_socket_t *) fs_get_handle(sock); + hnd = (net_socket_t *)fs_get_handle(sock); if(hnd == NULL) { errno = EBADF; return -1; @@ -346,7 +361,7 @@ ssize_t recv(int sock, void *buffer, size_t length, int flags) { net_socket_t *hnd; - hnd = (net_socket_t *) fs_get_handle(sock); + hnd = (net_socket_t *)fs_get_handle(sock); if(hnd == NULL) { errno = EBADF; return -1; @@ -365,7 +380,7 @@ struct sockaddr *address, socklen_t *address_len) { net_socket_t *hnd; - hnd = (net_socket_t *) fs_get_handle(sock); + hnd = (net_socket_t *)fs_get_handle(sock); if(hnd == NULL) { errno = EBADF; return -1; @@ -384,7 +399,7 @@ ssize_t send(int sock, const void *message, size_t length, int flags) { net_socket_t *hnd; - hnd = (net_socket_t *) fs_get_handle(sock); + hnd = (net_socket_t *)fs_get_handle(sock); if(hnd == NULL) { errno = EBADF; return -1; @@ -403,7 +418,7 @@ const struct sockaddr *dest_addr, socklen_t dest_len) { net_socket_t *hnd; - hnd = (net_socket_t *) fs_get_handle(sock); + hnd = (net_socket_t *)fs_get_handle(sock); if(hnd == NULL) { errno = EBADF; return -1; @@ -422,7 +437,7 @@ int shutdown(int sock, int how) { net_socket_t *hnd; - hnd = (net_socket_t *) fs_get_handle(sock); + hnd = (net_socket_t *)fs_get_handle(sock); if(hnd == NULL) { errno = EBADF; return -1; Modified: kos/kernel/net/net_dhcp.c =================================================================== --- kos/kernel/net/net_dhcp.c 2012-05-24 00:50:27 UTC (rev 768) +++ kos/kernel/net/net_dhcp.c 2012-05-24 00:59:36 UTC (rev 769) @@ -643,7 +643,7 @@ memset(srv_addr.sin_zero, 0, sizeof(addr.sin_zero)); /* Make the socket non-blocking */ - fs_socket_setflags(dhcp_sock, O_NONBLOCK); + fs_socket_setflags(dhcp_sock, FS_SOCKET_NONBLOCK); /* Create the callback for processing DHCP packets */ dhcp_cbid = net_thd_add_callback(&net_dhcp_thd, NULL, 50); @@ -652,20 +652,27 @@ } void net_dhcp_shutdown() { - int old = irq_disable(); + int old; + /* Remove the callback first, otherwise it'll probably end up grabbing the + lock, which we don't want it to do! */ + if(dhcp_cbid != -1) { + net_thd_del_callback(dhcp_cbid); + } + + /* This song and dance is to make sure nobody else is holding the lock, + otherwise, we can't destroy it! Granted, nobody should be able to be + holding the lock if we've deleted the dhcp callback already... */ if(dhcp_lock) { + rlock_lock(dhcp_lock); + old = irq_disable(); + rlock_unlock(dhcp_lock); rlock_destroy(dhcp_lock); dhcp_lock = NULL; + irq_restore(old); } - irq_restore(old); - if(dhcp_sock != -1) { close(dhcp_sock); } - - if(dhcp_cbid != -1) { - net_thd_del_callback(dhcp_cbid); - } } Modified: kos/kernel/net/net_ipv4.c =================================================================== --- kos/kernel/net/net_ipv4.c 2012-05-24 00:50:27 UTC (rev 768) +++ kos/kernel/net/net_ipv4.c 2012-05-24 00:59:36 UTC (rev 769) @@ -2,7 +2,7 @@ kernel/net/net_ipv4.c - Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Lawrence Sebald + Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2012 Lawrence Sebald Portions adapted from KOS' old net_icmp.c file: Copyright (c) 2002 Dan Potter @@ -15,9 +15,10 @@ #include <errno.h> #include <arpa/inet.h> #include <kos/net.h> +#include <kos/fs_socket.h> + #include "net_ipv4.h" #include "net_icmp.h" -#include "net_udp.h" static net_ipv4_stats_t ipv4_stats = { 0 }; @@ -232,16 +233,20 @@ int net_ipv4_input_proto(netif_t *src, ip_hdr_t *ip, const uint8 *data) { int hdrlen = (ip->version_ihl & 0x0F) << 2; + int datalen = ntohs(ip->length) - hdrlen; + int rv; /* Send the packet along to the appropriate protocol. */ switch(ip->protocol) { case IPPROTO_ICMP: ++ipv4_stats.pkt_recv; - return net_icmp_input(src, ip, data, ntohs(ip->length) - hdrlen); + return net_icmp_input(src, ip, data, datalen); - case IPPROTO_UDP: - ++ipv4_stats.pkt_recv; - return net_udp_input(src, ip, data, ntohs(ip->length) - hdrlen); + default: + rv = fs_socket_input(src, AF_INET, ip->protocol, ip, data, datalen); + + if(rv > -2) + ++ipv4_stats.pkt_recv; } /* There's no handler for this packet type, send an ICMP Destination Modified: kos/kernel/net/net_udp.c =================================================================== --- kos/kernel/net/net_udp.c 2012-05-24 00:50:27 UTC (rev 768) +++ kos/kernel/net/net_udp.c 2012-05-24 00:59:36 UTC (rev 769) @@ -1,7 +1,7 @@ /* KallistiOS ##version## kernel/net/net_udp.c - Copyright (C) 2005, 2006, 2007, 2008, 2009 Lawrence Sebald + Copyright (C) 2005, 2006, 2007, 2008, 2009, 2012 Lawrence Sebald */ @@ -20,7 +20,6 @@ #include "net_ipv4.h" #include "net_ipv6.h" -#include "net_udp.h" #define packed __attribute__((packed)) typedef struct { @@ -33,7 +32,7 @@ struct udp_pkt { TAILQ_ENTRY(udp_pkt) pkt_queue; - struct sockaddr_in from; + struct sockaddr_in6 from; uint8 *data; uint16 datasize; }; @@ -42,10 +41,11 @@ struct udp_sock { LIST_ENTRY(udp_sock) sock_list; - struct sockaddr_in local_addr; - struct sockaddr_in remote_addr; + struct sockaddr_in6 local_addr; + struct sockaddr_in6 remote_addr; - int flags; + uint32 flags; + int domain; struct udp_pkt_queue packets; }; @@ -56,8 +56,8 @@ static mutex_t *udp_mutex = NULL; static net_udp_stats_t udp_stats = { 0 }; -static int net_udp_send_raw(netif_t *net, uint32 src_ip, uint16 src_port, - uint32 dst_ip, uint16 dst_port, const uint8 *data, +static int net_udp_send_raw(netif_t *net, const struct sockaddr_in6 *src, + const struct sockaddr_in6 *dst, const uint8 *data, int size, int flags); static int net_udp_accept(net_socket_t *hnd, struct sockaddr *addr, @@ -69,22 +69,52 @@ static int net_udp_bind(net_socket_t *hnd, const struct sockaddr *addr, socklen_t addr_len) { struct udp_sock *udpsock, *iter; - struct sockaddr_in *realaddr; + struct sockaddr_in *realaddr4; + struct sockaddr_in6 realaddr6; /* Verify the parameters sent in first */ if(addr == NULL) { - errno = EFAULT; + errno = EDESTADDRREQ; return -1; } - if(addr->sa_family != AF_INET) { - errno = EAFNOSUPPORT; - return -1; + switch(addr->sa_family) { + case AF_INET: + if(addr_len != sizeof(struct sockaddr_in)) { + errno = EINVAL; + return -1; + } + + /* Grab the IPv4 address struct and convert it to IPv6 */ + realaddr4 = (struct sockaddr_in *)addr; + memset(&realaddr6, 0, sizeof(struct sockaddr_in6)); + realaddr6.sin6_family = AF_INET6; + realaddr6.sin6_port = realaddr4->sin_port; + + if(realaddr4->sin_addr.s_addr != INADDR_ANY) { + realaddr6.sin6_addr.__s6_addr.__s6_addr16[5] = 0xFFFF; + realaddr6.sin6_addr.__s6_addr.__s6_addr32[3] = + realaddr4->sin_addr.s_addr; + } + else { + realaddr6.sin6_addr = in6addr_any; + } + break; + + case AF_INET6: + if(addr_len != sizeof(struct sockaddr_in6)) { + errno = EINVAL; + return -1; + } + + realaddr6 = *((struct sockaddr_in6 *)addr); + break; + + default: + errno = EAFNOSUPPORT; + return -1; } - /* Get the sockaddr_in structure, rather than the sockaddr one */ - realaddr = (struct sockaddr_in *) addr; - if(irq_inside_int()) { if(mutex_trylock(udp_mutex) == -1) { errno = EWOULDBLOCK; @@ -102,20 +132,27 @@ return -1; } + /* Make sure the address family we're binding to matches that which is set + on the socket itself */ + if(addr->sa_family != udpsock->domain) { + mutex_unlock(udp_mutex); + errno = EINVAL; + return -1; + } + /* See if we requested a specific port or not */ - if(realaddr->sin_port != 0) { + if(realaddr6.sin6_port != 0) { /* Make sure we don't already have a socket bound to the port specified */ - LIST_FOREACH(iter, &net_udp_sockets, sock_list) { - if(iter->local_addr.sin_port == realaddr->sin_port) { + if(iter->local_addr.sin6_port == realaddr6.sin6_port) { mutex_unlock(udp_mutex); errno = EADDRINUSE; return -1; } } - udpsock->local_addr = *realaddr; + udpsock->local_addr = realaddr6; } else { uint16 port = 1024, tmp = 0; @@ -125,15 +162,15 @@ tmp = port; LIST_FOREACH(iter, &net_udp_sockets, sock_list) { - if(iter->local_addr.sin_port == port) { + if(iter->local_addr.sin6_port == port) { ++port; break; } } } - udpsock->local_addr = *realaddr; - udpsock->local_addr.sin_port = htons(port); + udpsock->local_addr = realaddr6; + udpsock->local_addr.sin6_port = htons(port); } mutex_unlock(udp_mutex); @@ -144,16 +181,49 @@ static int net_udp_connect(net_socket_t *hnd, const struct sockaddr *addr, socklen_t addr_len) { struct udp_sock *udpsock; - struct sockaddr_in *realaddr; + struct sockaddr_in *realaddr4; + struct sockaddr_in6 realaddr6; if(addr == NULL) { - errno = EFAULT; + errno = EDESTADDRREQ; return -1; } - if(addr->sa_family != AF_INET) { - errno = EAFNOSUPPORT; - return -1; + switch(addr->sa_family) { + case AF_INET: + if(addr_len != sizeof(struct sockaddr_in)) { + errno = EINVAL; + return -1; + } + + /* Grab the IPv4 address struct and convert it to IPv6 */ + realaddr4 = (struct sockaddr_in *)addr; + + if(realaddr4->sin_addr.s_addr == INADDR_ANY) { + errno = EADDRNOTAVAIL; + return -1; + } + + memset(&realaddr6, 0, sizeof(struct sockaddr_in6)); + realaddr6.sin6_family = AF_INET6; + realaddr6.sin6_port = realaddr4->sin_port; + realaddr6.sin6_addr.__s6_addr.__s6_addr16[5] = 0xFFFF; + realaddr6.sin6_addr.__s6_addr.__s6_addr32[3] = + realaddr4->sin_addr.s_addr; + break; + + case AF_INET6: + if(addr_len != sizeof(struct sockaddr_in6)) { + errno = EINVAL; + return -1; + } + + realaddr6 = *((struct sockaddr_in6 *)addr); + break; + + default: + errno = EAFNOSUPPORT; + return -1; } if(irq_inside_int()) { @@ -173,21 +243,31 @@ return -1; } - if(udpsock->remote_addr.sin_addr.s_addr != INADDR_ANY) { + /* Make sure the address family we're binding to matches that which is set + on the socket itself */ + if(addr->sa_family != udpsock->domain) { mutex_unlock(udp_mutex); + errno = EINVAL; + return -1; + } + + /* Make sure the socket isn't already connected */ + if(!IN6_IS_ADDR_UNSPECIFIED(&udpsock->remote_addr.sin6_addr)) { + mutex_unlock(udp_mutex); errno = EISCONN; return -1; } - realaddr = (struct sockaddr_in *) addr; - if(realaddr->sin_port == 0 || realaddr->sin_addr.s_addr == INADDR_ANY) { + /* Make sure we have a valid address to connect to */ + if(IN6_IS_ADDR_UNSPECIFIED(&realaddr6.sin6_addr) || + realaddr6.sin6_port == 0) { mutex_unlock(udp_mutex); errno = EADDRNOTAVAIL; return -1; } - udpsock->remote_addr.sin_addr.s_addr = realaddr->sin_addr.s_addr; - udpsock->remote_addr.sin_port = realaddr->sin_port; + /* "Connect" to the specified address */ + udpsock->remote_addr = realaddr6; mutex_unlock(udp_mutex); @@ -222,7 +302,7 @@ return -1; } - if(udpsock->flags & SHUT_RD) { + if(udpsock->flags & (SHUT_RD << 24)) { mutex_unlock(udp_mutex); return 0; } @@ -233,8 +313,8 @@ return -1; } - if(TAILQ_EMPTY(&udpsock->packets) && ((udpsock->flags & O_NONBLOCK) || - irq_inside_int())) { + if(TAILQ_EMPTY(&udpsock->packets) && + ((udpsock->flags & FS_SOCKET_NONBLOCK) || irq_inside_int())) { mutex_unlock(udp_mutex); errno = EWOULDBLOCK; return -1; @@ -257,19 +337,38 @@ } if(addr != NULL) { - struct sockaddr_in realaddr; + if(udpsock->domain == AF_INET) { + struct sockaddr_in realaddr; - realaddr.sin_family = AF_INET; - realaddr.sin_addr.s_addr = pkt->from.sin_addr.s_addr; - realaddr.sin_port = pkt->from.sin_port; - memset(realaddr.sin_zero, 0, 8); + memset(&realaddr, 0, sizeof(struct sockaddr_in)); + realaddr.sin_family = AF_INET; + realaddr.sin_addr.s_addr = + pkt->from.sin6_addr.__s6_addr.__s6_addr32[3]; + realaddr.sin_port = pkt->from.sin6_port; - if(*addr_len < sizeof(struct sockaddr_in)) { - memcpy(addr, &realaddr, *addr_len); + if(*addr_len < sizeof(struct sockaddr_in)) { + memcpy(addr, &realaddr, *addr_len); + } + else { + memcpy(addr, &realaddr, sizeof(struct sockaddr_in)); + *addr_len = sizeof(struct sockaddr_in); + } } - else { - memcpy(addr, &realaddr, sizeof(struct sockaddr_in)); - *addr_len = sizeof(struct sockaddr_in); + else if(udpsock->domain == AF_INET6) { + struct sockaddr_in6 realaddr6; + + memset(&realaddr6, 0, sizeof(struct sockaddr_in6)); + realaddr6.sin6_family = AF_INET6; + realaddr6.sin6_addr = pkt->from.sin6_addr; + realaddr6.sin6_port = pkt->from.sin6_port; + + if(*addr_len < sizeof(struct sockaddr_in6)) { + memcpy(addr, &realaddr6, *addr_len); + } + else { + memcpy(addr, &realaddr6, sizeof(struct sockaddr_in6)); + *addr_len = sizeof(struct sockaddr_in6); + } } } @@ -287,6 +386,9 @@ const struct sockaddr *addr, socklen_t addr_len) { struct udp_sock *udpsock; struct sockaddr_in *realaddr; + struct sockaddr_in6 realaddr6; + uint32_t sflags; + struct sockaddr_in6 local_addr; if(irq_inside_int()) { if(mutex_trylock(udp_mutex) == -1) { @@ -304,34 +406,62 @@ goto err; } - if(udpsock->flags & SHUT_WR) { + if(udpsock->flags & (SHUT_WR << 24)) { errno = EPIPE; goto err; } - if(udpsock->remote_addr.sin_addr.s_addr != INADDR_ANY && - udpsock->remote_addr.sin_port != 0) { + if(!IN6_IS_ADDR_UNSPECIFIED(&udpsock->remote_addr.sin6_addr) && + udpsock->remote_addr.sin6_port != 0) { if(addr) { errno = EISCONN; goto err; } - realaddr = &udpsock->remote_addr; + realaddr6 = udpsock->remote_addr; } else if(addr == NULL) { errno = EDESTADDRREQ; goto err; } - else { + else if(addr->sa_family != udpsock->domain) { + errno = EAFNOSUPPORT; + goto err; + } + else if(udpsock->domain == AF_INET6) { + if(addr_len != sizeof(struct sockaddr_in6)) { + errno = EINVAL; + goto err; + } + + realaddr6 = *((struct sockaddr_in6 *)addr); + } + else if(udpsock->domain == AF_INET) { + if(addr_len != sizeof(struct sockaddr_in)) { + errno = EINVAL; + goto err; + } + realaddr = (struct sockaddr_in *)addr; + memset(&realaddr6, 0, sizeof(struct sockaddr_in6)); + realaddr6.sin6_family = AF_INET6; + realaddr6.sin6_addr.__s6_addr.__s6_addr16[5] = 0xFFFF; + realaddr6.sin6_addr.__s6_addr.__s6_addr32[3] = + realaddr->sin_addr.s_addr; + realaddr6.sin6_port = realaddr->sin_port; } + else { + /* Shouldn't be able to get here... */ + errno = EBADF; + goto err; + } if(message == NULL) { errno = EFAULT; goto err; } - if(udpsock->local_addr.sin_port == 0) { + if(udpsock->local_addr.sin6_port == 0) { uint16 port = 1024, tmp = 0; struct udp_sock *iter; @@ -340,22 +470,22 @@ tmp = port; LIST_FOREACH(iter, &net_udp_sockets, sock_list) { - if(iter->local_addr.sin_port == port) { + if(iter->local_addr.sin6_port == port) { ++port; break; } } } - udpsock->local_addr.sin_port = htons(port); + udpsock->local_addr.sin6_port = htons(port); } + local_addr = udpsock->local_addr; + sflags = udpsock->flags; mutex_unlock(udp_mutex); - return net_udp_send_raw(NULL, udpsock->local_addr.sin_addr.s_addr, - udpsock->local_addr.sin_port, - realaddr->sin_addr.s_addr, realaddr->sin_port, - (uint8 *) message, length, udpsock->flags); + return net_udp_send_raw(NULL, &local_addr, &realaddr6, + (const uint8 *)message, length, sflags); err: mutex_unlock(udp_mutex); return -1; @@ -387,7 +517,7 @@ return -1; } - udpsock->flags |= how; + udpsock->flags |= (how << 24); mutex_unlock(udp_mutex); @@ -397,23 +527,15 @@ static int net_udp_socket(net_socket_t *hnd, int domain, int type, int proto) { struct udp_sock *udpsock; - udpsock = (struct udp_sock *) malloc(sizeof(struct udp_sock)); + udpsock = (struct udp_sock *)malloc(sizeof(struct udp_sock)); if(udpsock == NULL) { errno = ENOMEM; return -1; } - udpsock->remote_addr.sin_family = AF_INET; - udpsock->remote_addr.sin_addr.s_addr = INADDR_ANY; - udpsock->remote_addr.sin_port = 0; - - udpsock->local_addr.sin_family = AF_INET; - udpsock->local_addr.sin_addr.s_addr = INADDR_ANY; - udpsock->local_addr.sin_port = 0; - - udpsock->flags = 0; - + memset(udpsock, 0, sizeof(struct udp_sock)); TAILQ_INIT(&udpsock->packets); + udpsock->domain = domain; if(irq_inside_int()) { if(mutex_trylock(udp_mutex) == -1) { @@ -427,10 +549,9 @@ } LIST_INSERT_HEAD(&net_udp_sockets, udpsock, sock_list); + hnd->data = udpsock; mutex_unlock(udp_mutex); - hnd->data = udpsock; - return 0; } @@ -467,7 +588,7 @@ mutex_unlock(udp_mutex); } -static int net_udp_setflags(net_socket_t *hnd, int flags) { +static int net_udp_setflags(net_socket_t *hnd, uint32_t flags) { struct udp_sock *udpsock; if(irq_inside_int()) { @@ -487,7 +608,7 @@ return -1; } - if(flags & (~O_NONBLOCK)) { + if(flags & (~FS_SOCKET_NONBLOCK)) { mutex_unlock(udp_mutex); errno = EINVAL; return -1; @@ -499,21 +620,25 @@ return 0; } -int net_udp_input(netif_t *src, ip_hdr_t *ip, const uint8 *data, int size) { +static int net_udp_input4(netif_t *src, const ip_hdr_t *ip, const uint8 *data, + int size) { udp_hdr_t *hdr = (udp_hdr_t *)data; uint16 cs; struct udp_sock *sock; struct udp_pkt *pkt; - if(size <= sizeof(udp_hdr_t)) { + if(!udp_mutex) + return -1; + + if(size <= sizeof(udp_hdr_t)) { /* Discard the packet, since it is too short to be of any interest. */ ++udp_stats.pkt_recv_bad_size; return -1; } - cs = net_ipv4_checksum_pseudo(ip->src, ip->dest, ip->protocol, size); + if(hdr->checksum != 0) { + cs = net_ipv4_checksum_pseudo(ip->src, ip->dest, ip->protocol, size); - if(hdr->checksum != 0) { /* If the checksum is right, we'll get zero back from the checksum function */ if(net_ipv4_checksum(data, size, cs)) { @@ -523,56 +648,90 @@ } } - if(mutex_trylock(udp_mutex)) { + if(mutex_trylock(udp_mutex)) /* Considering this function is usually called in an IRQ, if the mutex is locked, there isn't much that can be done. */ return -1; - } LIST_FOREACH(sock, &net_udp_sockets, sock_list) { - /* See if we have a socket matching the description provided */ - if(sock->local_addr.sin_port == hdr->dst_port && - ((sock->remote_addr.sin_port == hdr->src_port && - sock->remote_addr.sin_addr.s_addr == ip->src) || - (sock->remote_addr.sin_port == 0 && - sock->remote_addr.sin_addr.s_addr == INADDR_ANY))) { - pkt = (struct udp_pkt *) malloc(sizeof(struct udp_pkt)); + /* Don't even bother looking at IPv6-only sockets */ + if(sock->domain == AF_INET6 && (sock->flags & FS_SOCKET_V6ONLY)) + continue; - pkt->datasize = size - sizeof(udp_hdr_t); - pkt->data = (uint8 *) malloc(pkt->datasize); + /* If the ports don't match, don't look any further */ + if(sock->local_addr.sin6_port != hdr->dst_port) + continue; - pkt->from.sin_family = AF_INET; - pkt->from.sin_addr.s_addr = ip->src; - pkt->from.sin_port = hdr->src_port; + /* If the socket has a remote port set and it isn't the one that this + packet came from, bail */ + if(sock->remote_addr.sin6_port != 0 && + sock->remote_addr.sin6_port != hdr->src_port) + continue; - memcpy(pkt->data, data + sizeof(udp_hdr_t), pkt->datasize); + /* If we have a address specified, and its not v4-mapped or its not the + address this packet came from, bail out */ + if(!IN6_IS_ADDR_UNSPECIFIED(&sock->remote_addr.sin6_addr) && + (!IN6_IS_ADDR_V4MAPPED(&sock->remote_addr.sin6_addr) || + sock->remote_addr.sin6_addr.__s6_addr.__s6_addr32[3] != ip->src)) + continue; - TAILQ_INSERT_TAIL(&sock->packets, pkt, pkt_queue); + if(!(pkt = (struct udp_pkt *)malloc(sizeof(struct udp_pkt)))) { + mutex_unlock(udp_mutex); + return -1; + } - genwait_wake_one(sock); + memset(pkt, 0, sizeof(struct udp_pkt)); + pkt->datasize = size - sizeof(udp_hdr_t); + if(!(pkt->data = (uint8 *)malloc(pkt->datasize))) { + free(pkt); mutex_unlock(udp_mutex); + return -1; + } - ++udp_stats.pkt_recv; + pkt->from.sin6_family = AF_INET6; + pkt->from.sin6_addr.__s6_addr.__s6_addr16[5] = 0xFFFF; + pkt->from.sin6_addr.__s6_addr.__s6_addr32[3] = ip->src; + pkt->from.sin6_port = hdr->src_port; - return 0; - } + memcpy(pkt->data, data + sizeof(udp_hdr_t), pkt->datasize); + + TAILQ_INSERT_TAIL(&sock->packets, pkt, pkt_queue); + + ++udp_stats.pkt_recv; + genwait_wake_one(sock); + mutex_unlock(udp_mutex); + + return 0; } + ++udp_stats.pkt_recv_no_sock; mutex_unlock(udp_mutex); - ++udp_stats.pkt_recv_no_sock; + return -1; +} +static int net_udp_real_input(netif_t *src, int domain, const void *hdr, + const uint8 *data, int size) { + if(!udp_mutex) + return -1; + + switch(domain) { + case AF_INET: + return net_udp_input4(src, (const ip_hdr_t *)hdr, data, size); + } + return -1; } -static int net_udp_send_raw(netif_t *net, uint32 src_ip, uint16 src_port, - uint32 dst_ip, uint16 dst_port, const uint8 *data, +static int net_udp_send_raw(netif_t *net, const struct sockaddr_in6 *src, + const struct sockaddr_in6 *dst, const uint8 *data, int size, int flags) { uint8 buf[size + sizeof(udp_hdr_t)]; udp_hdr_t *hdr = (udp_hdr_t *)buf; uint16 cs; int err; + struct in6_addr srcaddr = src->sin6_addr; if(!net) { net = net_default_dev; @@ -584,28 +743,51 @@ } } - if(src_ip == INADDR_ANY) { - src_ip = htonl(net_ipv4_address(net->ip_addr)); + if(IN6_IS_ADDR_UNSPECIFIED(&src->sin6_addr)) { + if(IN6_IS_ADDR_V4MAPPED(&dst->sin6_addr)) { + srcaddr.__s6_addr.__s6_addr16[5] = 0xFFFF; + srcaddr.__s6_addr.__s6_addr32[3] = + htonl(net_ipv4_address(net->ip_addr)); - if(src_ip == INADDR_ANY) { - errno = ENETDOWN; - ++udp_stats.pkt_send_failed; - return -1; + if(srcaddr.__s6_addr.__s6_addr32[3] == INADDR_ANY) { + errno = ENETDOWN; + ++udp_stats.pkt_send_failed; + return -1; + } } + else { + if(IN6_IS_ADDR_LOOPBACK(&dst->sin6_addr)) { + srcaddr = in6addr_loopback; + } + else if(IN6_IS_ADDR_LINKLOCAL(&dst->sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&dst->sin6_addr)) { + srcaddr = net->ip6_lladdr; + } + else if(net->ip6_addr_count) { + /* Punt and pick the first non-link-local address */ + srcaddr = net->ip6_addrs[0]; + } + else { + errno = ENETDOWN; + ++udp_stats.pkt_send_failed; + return -1; + } + } } memcpy(buf + sizeof(udp_hdr_t), data, size); size += sizeof(udp_hdr_t); - cs = net_ipv4_checksum_pseudo(src_ip, dst_ip, IPPROTO_UDP, size); + cs = net_ipv6_checksum_pseudo(&srcaddr, &dst->sin6_addr, IPPROTO_UDP, size); - hdr->src_port = src_port; - hdr->dst_port = dst_port; - hdr->length = size; + hdr->src_port = src->sin6_port; + hdr->dst_port = dst->sin6_port; + hdr->length = htons(size); hdr->checksum = 0; hdr->checksum = net_ipv4_checksum(buf, size, cs); /* Pass everything off to the network layer to do the rest. */ - err = net_ipv4_send(net, buf, size, -1, 64, IPPROTO_UDP, src_ip, dst_ip); + err = net_ipv6_send(net, buf, size, 0, IPPROTO_UDP, &srcaddr, + &dst->sin6_addr); if(err < 0) { ++udp_stats.pkt_send_failed; return -1; @@ -623,7 +805,7 @@ /* Protocol handler for fs_socket. */ static fs_socket_proto_t proto = { FS_SOCKET_PROTO_ENTRY, - PF_INET, /* domain */ + PF_INET6, /* domain */ SOCK_DGRAM, /* type */ IPPROTO_UDP, /* protocol */ net_udp_socket, @@ -635,7 +817,8 @@ net_udp_listen, net_udp_recvfrom, net_udp_sendto, - net_udp_shutdownsock + net_udp_shutdownsock, + net_udp_real_input }; int net_udp_init() { Deleted: kos/kernel/net/net_udp.h =================================================================== --- kos/kernel/net/net_udp.h 2012-05-24 00:50:27 UTC (rev 768) +++ kos/kernel/net/net_udp.h 2012-05-24 00:59:36 UTC (rev 769) @@ -1,16 +0,0 @@ -/* KallistiOS ##version## - - kernel/net/net_udp.h - Copyright (C) 2005, 2006, 2007, 2008 Lawrence Sebald - -*/ - -#ifndef __LOCAL_NET_UDP_H -#define __LOCAL_NET_UDP_H - -#include <sys/socket.h> -#include <kos/fs_socket.h> - -int net_udp_input(netif_t *src, ip_hdr_t *ih, const uint8 *data, int size); - -#endif /* __LOCAL_NET_UDP_H */ This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |