2 * This Cplant(TM) source code is the property of Sandia National
5 * This Cplant(TM) source code is copyrighted by Sandia National
8 * The redistribution of this Cplant(TM) source code is subject to the
9 * terms of the GNU Lesser General Public License
10 * (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
12 * Cplant(TM) Copyright 1998-2003 Sandia Corporation.
13 * Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
14 * license for use of this work by or on behalf of the US Government.
15 * Export of this program may require a license from the United States
20 * This library is free software; you can redistribute it and/or
21 * modify it under the terms of the GNU Lesser General Public
22 * License as published by the Free Software Foundation; either
23 * version 2.1 of the License, or (at your option) any later version.
25 * This library is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28 * Lesser General Public License for more details.
30 * You should have received a copy of the GNU Lesser General Public
31 * License along with this library; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
34 * Questions or comments about this library should be sent to:
37 * Sandia National Laboratories, New Mexico
39 * Albuquerque, NM 87185-1110
48 #include <stdio.h> /* for NULL */
57 #include <sys/types.h>
59 #include <sys/fcntl.h>
60 #include <sys/queue.h>
61 #include <sys/syscall.h>
62 #include <sys/socket.h>
63 #include <linux/net.h>
69 #include "dev.h" /* _sysio_nodev_ops */
72 * Sockets interface driver
76 * Sockets file identifiers format.
78 struct sockets_ino_identifier {
79 ino_t inum; /* i-number */
83 * Driver-private i-node information we keep about in-use sockets.
86 struct sockets_ino_identifier ski_ident; /* unique identifier */
87 struct file_identifier ski_fileid; /* ditto */
88 int ski_fd; /* host fildes */
91 static int sockets_inop_close(struct inode *ino);
92 static int sockets_inop_read(struct inode *ino,
94 static int sockets_inop_write(struct inode *ino,
95 struct ioctx *ioctxp);
96 static _SYSIO_OFF_T sockets_inop_pos(struct inode *ino,
98 static int sockets_inop_iodone(struct ioctx *ioctx);
99 static int sockets_inop_sync(struct inode *ino);
100 static int sockets_inop_datasync(struct inode *ino);
101 static int sockets_inop_fcntl(struct inode *ino, int cmd, va_list ap);
102 static int sockets_inop_ioctl(struct inode *ino,
103 unsigned long int request,
105 static void sockets_inop_gone(struct inode *ino);
106 static void sockets_illop(void);
109 * Given i-node, return driver private part.
111 #define I2SKI(ino) ((struct socket_info *)((ino)->i_private))
113 struct filesys_ops sockets_filesys_ops = {
114 (void (*)(struct filesys *))sockets_illop
117 static struct filesys *sockets_fs;
119 static struct inode_ops sockets_i_ops;
122 * Initialize this driver.
125 _sysio_sockets_init()
128 sockets_i_ops = _sysio_nodev_ops;
129 sockets_i_ops.inop_close = sockets_inop_close;
130 sockets_i_ops.inop_read = sockets_inop_read;
131 sockets_i_ops.inop_write = sockets_inop_write;
132 sockets_i_ops.inop_pos = sockets_inop_pos;
133 sockets_i_ops.inop_iodone = sockets_inop_iodone;
134 sockets_i_ops.inop_fcntl = sockets_inop_fcntl;
135 sockets_i_ops.inop_sync = sockets_inop_sync;
136 sockets_i_ops.inop_datasync = sockets_inop_datasync;
137 sockets_i_ops.inop_ioctl = sockets_inop_ioctl;
138 sockets_i_ops.inop_gone = sockets_inop_gone;
140 sockets_fs = _sysio_fs_new(&sockets_filesys_ops, 0, NULL);
148 sockets_inop_close(struct inode *ino)
150 struct socket_info *ski = I2SKI(ino);
156 err = syscall(SYS_close, ski->ski_fd);
164 * A helper function performing the real IO operation work.
166 * We don't really have async IO. We'll just perform the function
170 doio(ssize_t (*f)(int, const struct iovec *, int),
174 struct socket_info *ski = I2SKI(ino);
176 assert(ski->ski_fd >= 0);
178 /* XXX there's no way to check the position
179 * here we only could ingore the extends
181 if (ioctx->ioctx_xtvlen != 1)
184 if (ioctx->ioctx_iovlen && (int) ioctx->ioctx_iovlen < 0)
188 * Call the appropriate (read/write) IO function to
189 * transfer the data now.
192 (*f)(ski->ski_fd, ioctx->ioctx_iov, ioctx->ioctx_iovlen);
193 if (ioctx->ioctx_cc < 0)
194 ioctx->ioctx_errno = errno;
196 ioctx->ioctx_done = 1;
201 * Helper function passed to doio(), above, to accomplish a real readv.
204 _readv(int fd, const struct iovec *vector, int count)
207 return syscall(SYS_readv, fd, vector, count);
211 sockets_inop_read(struct inode *ino,
215 return doio(_readv, ino, ioctx);
219 * Helper function passed to doio(), above, to accomplish a real writev.
222 _writev(int fd, const struct iovec *vector, int count)
225 return syscall(SYS_writev, fd, vector, count);
229 sockets_inop_write(struct inode *ino,
233 return doio(_writev, ino, ioctx);
237 sockets_inop_pos(struct inode *ino, _SYSIO_OFF_T off)
243 sockets_inop_iodone(struct ioctx *ioctxp __IS_UNUSED)
247 * It's always done in this driver. It completed when posted.
253 sockets_inop_fcntl(struct inode *ino __IS_UNUSED,
255 va_list ap __IS_UNUSED)
259 assert(I2SKI(ino)->ski_fd >= 0);
265 return syscall(SYS_fcntl, I2SKI(ino)->ski_fd, cmd);
273 arg = va_arg(ap, long);
274 return syscall(SYS_fcntl, I2SKI(ino)->ski_fd, cmd, arg);
276 printf("uncatched cmd %d\n", cmd);
283 sockets_inop_sync(struct inode *ino)
286 assert(I2SKI(ino)->ski_fd >= 0);
288 return syscall(SYS_fsync, I2SKI(ino)->ski_fd);
292 sockets_inop_datasync(struct inode *ino)
295 assert(I2SKI(ino)->ski_fd >= 0);
297 return syscall(SYS_fdatasync, I2SKI(ino)->ski_fd);
301 sockets_inop_ioctl(struct inode *ino __IS_UNUSED,
302 unsigned long int request __IS_UNUSED,
303 va_list ap __IS_UNUSED)
306 * I'm lazy. Maybe implemented later.
312 sockets_inop_gone(struct inode *ino)
315 (void )sockets_inop_close(ino);
316 free(ino->i_private);
326 static struct inode *
327 _sysio_sockets_inew()
329 static ino_t inum = 1;
330 struct socket_info *ski;
333 ski = malloc(sizeof(struct socket_info));
336 ski->ski_ident.inum = inum++;
337 ski->ski_fileid.fid_data = &ski->ski_ident;
338 ski->ski_fileid.fid_len = sizeof(ski->ski_ident);
342 _sysio_i_new(sockets_fs,
356 socket(int domain, int type, int protocol)
360 struct socket_info *ski;
366 ino = _sysio_sockets_inew();
373 #ifndef SYS_socketcall
374 ski->ski_fd = syscall(SYS_socket, domain, type, protocol);
377 unsigned long avec[3] = {domain, type, protocol};
378 ski->ski_fd = syscall(SYS_socketcall, SYS_SOCKET, avec);
381 if (ski->ski_fd < 0) {
386 fil = _sysio_fnew(ino, O_RDWR);
392 err = _sysio_fd_set(fil, ski->ski_fd);
409 accept(int s, struct sockaddr *addr, socklen_t *addrlen)
413 struct socket_info *ski;
414 struct file *ofil, *nfil;
420 ofil = _sysio_fd_find(s);
426 ino = _sysio_sockets_inew();
432 nfil = _sysio_fnew(ino, O_RDWR);
439 #ifndef SYS_socketcall
440 ski->ski_fd = syscall(SYS_accept, I2SKI(ofil->f_ino)->ski_fd,
444 unsigned long avec[3] = {
445 (unsigned long) I2SKI(ofil->f_ino)->ski_fd,
446 (unsigned long) addr,
447 (unsigned long) addrlen};
448 ski->ski_fd = syscall(SYS_socketcall, SYS_ACCEPT, avec);
451 if (ski->ski_fd < 0) {
456 err = _sysio_fd_set(nfil, ski->ski_fd);
473 bind(int sockfd, const struct sockaddr *my_addr, socklen_t addrlen)
477 unsigned long avec[3];
481 fil = _sysio_fd_find(sockfd);
487 #ifndef SYS_socketcall
488 if (syscall(SYS_bind, I2SKI(fil->f_ino)->ski_fd, my_addr, addrlen)) {
490 avec[0] = I2SKI(fil->f_ino)->ski_fd;
491 avec[1] = (unsigned long )my_addr;
493 if (syscall(SYS_socketcall, SYS_BIND, avec) != 0) {
506 listen(int s, int backlog)
510 unsigned long avec[2];
514 fil = _sysio_fd_find(s);
520 #ifndef SYS_socketcall
521 if (syscall(SYS_listen, I2SKI(fil->f_ino)->ski_fd, backlog) != 0) {
523 avec[0] = I2SKI(fil->f_ino)->ski_fd;
525 if (syscall(SYS_socketcall, SYS_LISTEN, avec) != 0) {
538 connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen)
542 unsigned long avec[3];
546 fil = _sysio_fd_find(sockfd);
552 #ifndef SYS_socketcall
553 if (syscall(SYS_connect, I2SKI(fil->f_ino)->ski_fd,
554 serv_addr, addrlen) != 0) {
556 avec[0] = I2SKI(fil->f_ino)->ski_fd;
557 avec[1] = (unsigned long )serv_addr;
559 if (syscall(SYS_socketcall, SYS_CONNECT, avec) != 0) {