summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pfinet/io-ops.c101
1 files changed, 100 insertions, 1 deletions
diff --git a/pfinet/io-ops.c b/pfinet/io-ops.c
index 0e7e9d0a..ded67992 100644
--- a/pfinet/io-ops.c
+++ b/pfinet/io-ops.c
@@ -31,6 +31,7 @@ S_io_write (struct sock_user *user,
return EOPNOTSUPP;
mutex_lock (&global_lock);
+ become_task (user);
/* O_NONBLOCK for fourth arg? XXX */
err = - (*user->sock->ops->write) (user->sock, data, datalen, 0);
mutex_unlock (&global_lock);
@@ -45,5 +46,103 @@ S_io_read (struct sock_user *user,
off_t offset,
mach_msg_type_number_t amount)
{
+ error_t err;
+ int alloced = 0;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ /* Instead of this, we should peek and the socket and only
+ allocate as much as necessary. */
+ if (amount > *datalen)
+ {
+ vm_allocate (mach_task_self (), (vm_address_t *)data, amount, 1);
+ alloced = 1;
+ }
+
+ mutex_lock (&global_lock);
+ become_task (user);
+ /* O_NONBLOCK for fourth arg? XXX */
+ err = (*user->sock->ops->read) (user->sock, *data, amount, 0);
+ mutex_unlock (&global_lock);
-
+ if (err < 0)
+ err = -err;
+ else
+ {
+ *datalen = err;
+ if (alloced && page_round (*datalen) < page_round (amount))
+ vm_deallocate (mach_task_self (), *data + page_round (*datalen),
+ page_round (amount) - page_round (*datalen));
+ err = 0;
+ }
+ return err;
+}
+
+error_t
+S_io_seek (struct sock_user *user,
+ off_t offset,
+ int whence,
+ off_t *newp)
+{
+ return user ? ESPIPE : EOPNOTSUPP;
+}
+
+error_t
+S_io_readable (struct sock_user *user,
+ mach_msg_type_number_t *amount)
+{
+ struct sock *sk;
+ error_t err;
+
+ if (!user)
+ return EOPNOTSUPP;
+
+ mutex_lock (&global_lock);
+ become_task (user);
+
+ /* We need to avoid calling the Linux ioctl routines,
+ so here is a rather ugly break of modularity. */
+
+ sk = (struct sock *) user->sock->data;
+ err = 0;
+
+ /* Linux's af_inet.c ioctl routine just calls the protocol-specific
+ ioctl routine; it's those routines that we need to simulate. So
+ this switch corresponds to the initialization of SK->prot in
+ af_inet.c:inet_create. */
+ switch (sock->type)
+ {
+ case SOCK_STREAM:
+ case SOCK_SEQPACKET:
+ /* These guts are copied from tcp.c:tcp_ioctl. */
+ if (sk->state == TCP_LISTEN)
+ err = EINVAL;
+ else
+ {
+ sk->inuse = 1;
+ *amount = tcp_readable (sk);
+ release_sock (sk);
+ }
+ break;
+
+ case SOCK_DGRAM:
+ /* These guts are copied from udp.c:udp_ioctl (TIOCINQ). */
+ if (sk->state == TCP_LISTEN)
+ err = EINVAL;
+ else
+ /* Boy, I really love the C language. */
+ *amount = (skb_peek (&sk->receive_queue)
+ ? : &((struct sk_buff){}))->len;
+ break;
+
+ case SOCK_RAW:
+ default:
+ err = EOPNOTSUPP;
+ break;
+ }
+
+ mutex_unlock (&global_lock);
+ return err;
+}
+