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 r= ioctl(sock, NWIOGTCPOPT, &tcpopt); 70 if (r != -1 || errno != ENOTTY) 71 { 72 if (r == -1) 73 return r; 74 return _tcp_sendto(sock, message, length, flags, 75 dest_addr, dest_len); 76 } 77 78 r= ioctl(sock, NWIOGUDPOPT, &udpopt); 79 if (r != -1 || errno != ENOTTY) 80 { 81 if (r == -1) 82 return r; 83 return _udp_sendto(sock, message, length, flags, 84 dest_addr, dest_len, &udpopt); 85 } 86 87 r= ioctl(sock, NWIOGUDSSOTYPE, &uds_sotype); 88 if (r != -1 || errno != ENOTTY) 89 { 90 if (r == -1) { 91 return r; 92 } 93 94 if (uds_sotype == SOCK_DGRAM) { 95 96 return _uds_sendto_dgram(sock, message, 97 length, flags,dest_addr, dest_len); 98 } else { 99 100 return _uds_sendto_conn(sock, message, 101 length, flags, dest_addr, dest_len); 102 } 103 } 104 105 r= ioctl(sock, NWIOGIPOPT, &ipopt); 106 if (r != -1 || errno != ENOTTY) 107 { 108 ip_hdr_t *ip_hdr; 109 const struct sockaddr_in *sinp; 110 ssize_t retval; 111 int saved_errno; 112 113 if (r == -1) { 114 return r; 115 } 116 117 sinp = (const struct sockaddr_in *)dest_addr; 118 if (sinp->sin_family != AF_INET) 119 { 120 errno= EAFNOSUPPORT; 121 return -1; 122 } 123 124 /* raw */ 125 /* XXX this is horrible: we have to copy the entire buffer 126 * because we have to change one header field. Obviously we 127 * can't modify the user buffer directly.. 128 */ 129 if ((ip_hdr = malloc(length)) == NULL) 130 return -1; /* errno is ENOMEM */ 131 memcpy(ip_hdr, message, length); 132 ip_hdr->ih_dst= sinp->sin_addr.s_addr; 133 134 retval = write(sock, ip_hdr, length); 135 136 saved_errno = errno; 137 free(ip_hdr); 138 errno = saved_errno; 139 return retval; 140 } 141 142 errno = ENOTSOCK; 143 return -1; 144 } 145 146 static ssize_t _tcp_sendto(int sock, const void *message, size_t length, 147 int flags, const struct sockaddr *dest_addr, socklen_t dest_len) 148 { 149 150 if (flags != 0) { 151 #if DEBUG 152 fprintf(stderr, "sendto(tcp): flags not implemented\n"); 153 #endif 154 errno= ENOSYS; 155 return -1; 156 } 157 158 /* Silently ignore destination, if given. */ 159 160 return write(sock, message, length); 161 } 162 163 static ssize_t _udp_sendto(int sock, const void *message, size_t length, 164 int flags, const struct sockaddr *dest_addr, socklen_t dest_len, 165 nwio_udpopt_t *udpoptp) 166 { 167 int r, t_errno; 168 size_t buflen; 169 void *buf; 170 struct sockaddr_in *sinp; 171 udp_io_hdr_t *io_hdrp; 172 173 if (flags) 174 { 175 #if DEBUG 176 fprintf(stderr, "sendto(udp): flags not implemented\n"); 177 #endif 178 errno= ENOSYS; 179 return -1; 180 } 181 182 if (udpoptp->nwuo_flags & NWUO_RWDATONLY) 183 return write(sock, message, length); 184 185 if ((udpoptp->nwuo_flags & NWUO_RP_ANY) || 186 (udpoptp->nwuo_flags & NWUO_RA_ANY)) 187 { 188 if (!dest_addr) 189 { 190 errno= ENOTCONN; 191 return -1; 192 } 193 194 /* Check destination address */ 195 if (dest_len < sizeof(*sinp)) 196 { 197 errno= EINVAL; 198 return -1; 199 } 200 sinp= (struct sockaddr_in *) __UNCONST(dest_addr); 201 if (sinp->sin_family != AF_INET) 202 { 203 errno= EAFNOSUPPORT; 204 return -1; 205 } 206 } 207 208 buflen= sizeof(*io_hdrp) + length; 209 if (buflen < length) 210 { 211 /* Overflow */ 212 errno= EMSGSIZE; 213 return -1; 214 } 215 buf= malloc(buflen); 216 if (buf == NULL) 217 return -1; 218 219 io_hdrp= buf; 220 io_hdrp->uih_src_addr= 0; /* Unused */ 221 io_hdrp->uih_src_port= 0; /* Will cause error if NWUO_LP_ANY */ 222 if (udpoptp->nwuo_flags & NWUO_RA_ANY) 223 io_hdrp->uih_dst_addr= sinp->sin_addr.s_addr; 224 else 225 io_hdrp->uih_dst_addr= 0; 226 if (udpoptp->nwuo_flags & NWUO_RP_ANY) 227 io_hdrp->uih_dst_port= sinp->sin_port; 228 else 229 io_hdrp->uih_dst_port= 0; 230 io_hdrp->uih_ip_opt_len= 0; 231 io_hdrp->uih_data_len= 0; 232 233 memcpy(&io_hdrp[1], message, length); 234 r= write(sock, buf, buflen); 235 if (r == -1) 236 { 237 t_errno= errno; 238 free(buf); 239 errno= t_errno; 240 return -1; 241 } 242 assert((size_t)r == buflen); 243 free(buf); 244 return length; 245 } 246 247 static ssize_t _uds_sendto_conn(int sock, const void *message, size_t length, 248 int flags, const struct sockaddr *dest_addr, socklen_t dest_len) 249 { 250 251 /* for connection oriented unix domain sockets (SOCK_STREAM / 252 * SOCK_SEQPACKET) 253 */ 254 255 if (flags != 0) { 256 #if DEBUG 257 fprintf(stderr, "sendto(uds): flags not implemented\n"); 258 #endif 259 errno= ENOSYS; 260 return -1; 261 } 262 263 /* Silently ignore destination, if given. */ 264 265 return write(sock, message, length); 266 } 267 268 static ssize_t _uds_sendto_dgram(int sock, const void *message, size_t length, 269 int flags, const struct sockaddr *dest_addr, socklen_t dest_len) 270 { 271 int r; 272 273 /* for connectionless unix domain sockets (SOCK_DGRAM) */ 274 275 if (flags != 0) { 276 #if DEBUG 277 fprintf(stderr, "sendto(uds): flags not implemented\n"); 278 #endif 279 errno= ENOSYS; 280 return -1; 281 } 282 283 if (dest_addr == NULL) { 284 errno = EFAULT; 285 return -1; 286 } 287 288 /* set the target address */ 289 r= ioctl(sock, NWIOSUDSTADDR, (void *) __UNCONST(dest_addr)); 290 if (r == -1) { 291 return r; 292 } 293 294 /* do the send */ 295 return write(sock, message, length); 296 } 297