1 #include <sys/cdefs.h> 2 #include "namespace.h" 3 #include <lib.h> 4 5 #include <assert.h> 6 #include <errno.h> 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 #include <unistd.h> 11 #include <sys/ioctl.h> 12 #include <sys/socket.h> 13 #include <netinet/in.h> 14 15 #include <net/gen/in.h> 16 #include <net/gen/ip_hdr.h> 17 #include <net/gen/ip_io.h> 18 #include <net/gen/tcp.h> 19 #include <net/gen/tcp_io.h> 20 #include <net/gen/udp.h> 21 #include <net/gen/udp_hdr.h> 22 #include <net/gen/udp_io.h> 23 24 #define DEBUG 0 25 26 static ssize_t _tcp_sendto(int sock, const void *message, size_t length, 27 int flags, const struct sockaddr *dest_addr, socklen_t dest_len); 28 static ssize_t _udp_sendto(int sock, const void *message, size_t length, 29 int flags, const struct sockaddr *dest_addr, socklen_t dest_len, 30 nwio_udpopt_t *udpoptp); 31 static ssize_t _uds_sendto_conn(int sock, const void *message, size_t length, 32 int flags, const struct sockaddr *dest_addr, socklen_t dest_len); 33 static ssize_t _uds_sendto_dgram(int sock, const void *message, size_t length, 34 int flags, const struct sockaddr *dest_addr, socklen_t dest_len); 35 36 /* 37 * Send a message on a socket. 38 */ 39 static ssize_t 40 __sendto(int fd, const void * buffer, size_t length, int flags, 41 const struct sockaddr * dest_addr, socklen_t dest_len) 42 { 43 message m; 44 45 memset(&m, 0, sizeof(m)); 46 m.m_lc_vfs_sendrecv.fd = fd; 47 m.m_lc_vfs_sendrecv.buf = (vir_bytes)buffer; 48 m.m_lc_vfs_sendrecv.len = length; 49 m.m_lc_vfs_sendrecv.flags = flags; 50 m.m_lc_vfs_sendrecv.addr = (vir_bytes)dest_addr; 51 m.m_lc_vfs_sendrecv.addr_len = dest_len; 52 53 return _syscall(VFS_PROC_NR, VFS_SENDTO, &m); 54 } 55 56 ssize_t sendto(int sock, const void *message, size_t length, int flags, 57 const struct sockaddr *dest_addr, socklen_t dest_len) 58 { 59 int r; 60 nwio_tcpopt_t tcpopt; 61 nwio_udpopt_t udpopt; 62 nwio_ipopt_t ipopt; 63 int uds_sotype = -1; 64 65 r = __sendto(sock, message, length, flags, dest_addr, dest_len); 66 if (r != -1 || (errno != ENOTSOCK && errno != ENOSYS)) 67 return r; 68 69 /* For old socket driver implementations, this flag is the default. */ 70 flags &= ~MSG_NOSIGNAL; 71 72 r= ioctl(sock, NWIOGTCPOPT, &tcpopt); 73 if (r != -1 || errno != ENOTTY) 74 { 75 if (r == -1) 76 return r; 77 return _tcp_sendto(sock, message, length, flags, 78 dest_addr, dest_len); 79 } 80 81 r= ioctl(sock, NWIOGUDPOPT, &udpopt); 82 if (r != -1 || errno != ENOTTY) 83 { 84 if (r == -1) 85 return r; 86 return _udp_sendto(sock, message, length, flags, 87 dest_addr, dest_len, &udpopt); 88 } 89 90 r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype); 91 if (r != -1 || errno != ENOTTY) 92 { 93 if (r == -1) { 94 return r; 95 } 96 97 if (uds_sotype == SOCK_DGRAM) { 98 99 return _uds_sendto_dgram(sock, message, 100 length, flags,dest_addr, dest_len); 101 } else { 102 103 return _uds_sendto_conn(sock, message, 104 length, flags, dest_addr, dest_len); 105 } 106 } 107 108 r= ioctl(sock, NWIOGIPOPT, &ipopt); 109 if (r != -1 || errno != ENOTTY) 110 { 111 ip_hdr_t *ip_hdr; 112 const struct sockaddr_in *sinp; 113 ssize_t retval; 114 int saved_errno; 115 116 if (r == -1) { 117 return r; 118 } 119 120 sinp = (const struct sockaddr_in *)dest_addr; 121 if (sinp->sin_family != AF_INET) 122 { 123 errno= EAFNOSUPPORT; 124 return -1; 125 } 126 127 /* raw */ 128 /* XXX this is horrible: we have to copy the entire buffer 129 * because we have to change one header field. Obviously we 130 * can't modify the user buffer directly.. 131 */ 132 if ((ip_hdr = malloc(length)) == NULL) 133 return -1; /* errno is ENOMEM */ 134 memcpy(ip_hdr, message, length); 135 ip_hdr->ih_dst= sinp->sin_addr.s_addr; 136 137 retval = write(sock, ip_hdr, length); 138 139 saved_errno = errno; 140 free(ip_hdr); 141 errno = saved_errno; 142 return retval; 143 } 144 145 errno = ENOTSOCK; 146 return -1; 147 } 148 149 static ssize_t _tcp_sendto(int sock, const void *message, size_t length, 150 int flags, const struct sockaddr *dest_addr, socklen_t dest_len) 151 { 152 153 if (flags != 0) { 154 #if DEBUG 155 fprintf(stderr, "sendto(tcp): flags not implemented\n"); 156 #endif 157 errno= ENOSYS; 158 return -1; 159 } 160 161 /* Silently ignore destination, if given. */ 162 163 return write(sock, message, length); 164 } 165 166 static ssize_t _udp_sendto(int sock, const void *message, size_t length, 167 int flags, const struct sockaddr *dest_addr, socklen_t dest_len, 168 nwio_udpopt_t *udpoptp) 169 { 170 int r, t_errno; 171 size_t buflen; 172 void *buf; 173 struct sockaddr_in *sinp; 174 udp_io_hdr_t *io_hdrp; 175 176 if (flags) 177 { 178 #if DEBUG 179 fprintf(stderr, "sendto(udp): flags not implemented\n"); 180 #endif 181 errno= ENOSYS; 182 return -1; 183 } 184 185 if (udpoptp->nwuo_flags & NWUO_RWDATONLY) 186 return write(sock, message, length); 187 188 if ((udpoptp->nwuo_flags & NWUO_RP_ANY) || 189 (udpoptp->nwuo_flags & NWUO_RA_ANY)) 190 { 191 if (!dest_addr) 192 { 193 errno= ENOTCONN; 194 return -1; 195 } 196 197 /* Check destination address */ 198 if (dest_len < sizeof(*sinp)) 199 { 200 errno= EINVAL; 201 return -1; 202 } 203 sinp= (struct sockaddr_in *) __UNCONST(dest_addr); 204 if (sinp->sin_family != AF_INET) 205 { 206 errno= EAFNOSUPPORT; 207 return -1; 208 } 209 } 210 211 buflen= sizeof(*io_hdrp) + length; 212 if (buflen < length) 213 { 214 /* Overflow */ 215 errno= EMSGSIZE; 216 return -1; 217 } 218 buf= malloc(buflen); 219 if (buf == NULL) 220 return -1; 221 222 io_hdrp= buf; 223 io_hdrp->uih_src_addr= 0; /* Unused */ 224 io_hdrp->uih_src_port= 0; /* Will cause error if NWUO_LP_ANY */ 225 if (udpoptp->nwuo_flags & NWUO_RA_ANY) 226 io_hdrp->uih_dst_addr= sinp->sin_addr.s_addr; 227 else 228 io_hdrp->uih_dst_addr= 0; 229 if (udpoptp->nwuo_flags & NWUO_RP_ANY) 230 io_hdrp->uih_dst_port= sinp->sin_port; 231 else 232 io_hdrp->uih_dst_port= 0; 233 io_hdrp->uih_ip_opt_len= 0; 234 io_hdrp->uih_data_len= 0; 235 236 memcpy(&io_hdrp[1], message, length); 237 r= write(sock, buf, buflen); 238 if (r == -1) 239 { 240 t_errno= errno; 241 free(buf); 242 errno= t_errno; 243 return -1; 244 } 245 assert((size_t)r == buflen); 246 free(buf); 247 return length; 248 } 249 250 static ssize_t _uds_sendto_conn(int sock, const void *message, size_t length, 251 int flags, const struct sockaddr *dest_addr, socklen_t dest_len) 252 { 253 254 /* for connection oriented unix domain sockets (SOCK_STREAM / 255 * SOCK_SEQPACKET) 256 */ 257 258 if (flags != 0) { 259 #if DEBUG 260 fprintf(stderr, "sendto(uds): flags not implemented\n"); 261 #endif 262 errno= ENOSYS; 263 return -1; 264 } 265 266 /* Silently ignore destination, if given. */ 267 268 return write(sock, message, length); 269 } 270 271 static ssize_t _uds_sendto_dgram(int sock, const void *message, size_t length, 272 int flags, const struct sockaddr *dest_addr, socklen_t dest_len) 273 { 274 int r; 275 276 /* for connectionless unix domain sockets (SOCK_DGRAM) */ 277 278 if (flags != 0) { 279 #if DEBUG 280 fprintf(stderr, "sendto(uds): flags not implemented\n"); 281 #endif 282 errno= ENOSYS; 283 return -1; 284 } 285 286 if (dest_addr == NULL) { 287 errno = EFAULT; 288 return -1; 289 } 290 291 /* set the target address */ 292 r= ioctl(sock, NWIOSUDSTADDR, (void *) __UNCONST(dest_addr)); 293 if (r == -1) { 294 return r; 295 } 296 297 /* do the send */ 298 return write(sock, message, length); 299 } 300