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