Dear all,

In Minix the "select" call does not work on ethernet devices,
such as /dev/eth. When used for this device it prints a message
"eth_select: not implemented".

I needed to have "select" work on ethernet devices, so I took the
relevant code from udp.c to eth.c and tested it. It seems to work
well.

If anyone needs this as well, the diff with Minix 3.1.2a is
included below. Only the file src/servers/inet/generic/eth.c needs
changing.

As far as I can see, the changes should not conflict with changes
made in the current SVN version of Minix, so this will probably
work with all newer Minixes as well.

With kind regards,
Erik van der Kouwe



*** src.release/servers/inet/generic/eth.c Sun Feb 3 19:04:59 2008
--- src/servers/inet/generic/eth.c Sun Feb 3 19:10:08 2008
***************
*** 36,41 ****
--- 36,42 ----
get_userdata_t ef_get_userdata;
put_userdata_t ef_put_userdata;
put_pkt_t ef_put_pkt;
+ select_res_t ef_select_res;
time_t ef_exp_time;
size_t ef_write_count;
ioreq_t ef_ioctl_req;
***************
*** 49,54 ****
--- 50,56 ----
# define EFF_WRITE_IP 0x4
# define EFF_IOCTL_IP 0x8
# define EFF_OPTSET 0x10
+ # define EFF_SEL_READ 0x20

/* Note that the vh_type field is normally considered part of the ethernet
* header.
***************
*** 66,71 ****
--- 68,74 ----
#ifdef BUF_CONSISTENCY_CHECK
FORWARD void eth_bufcheck ARGS(( void ));
#endif
+ FORWARD int eth_sel_read ARGS(( eth_fd_t * ));
FORWARD void packet2user ARGS(( eth_fd_t *fd, acc_t *pack, time_t exp_time ));
FORWARD void reply_thr_get ARGS(( eth_fd_t *eth_fd,
size_t result, int for_ioctl ));
***************
*** 157,162 ****
--- 160,166 ----
eth_fd->ef_get_userdata= get_userdata;
eth_fd->ef_put_userdata= put_userdata;
eth_fd->ef_put_pkt= put_pkt;
+ eth_fd->ef_select_res= select_res;

return i;
}
***************
*** 625,632 ****
int fd;
unsigned operations;
{
! printf("eth_select: not implemented\n");
! return 0;
}

PUBLIC void eth_close(fd)
--- 629,660 ----
int fd;
unsigned operations;
{
! int i;
! unsigned resops;
! eth_fd_t *eth_fd;
!
! eth_fd= &eth_fd_table[fd];
! assert (eth_fd->ef_flags & EFF_INUSE);
!
! resops= 0;
!
! if (operations & SR_SELECT_READ)
! {
! if (eth_sel_read(eth_fd))
! resops |= SR_SELECT_READ;
! else if (!(operations & SR_SELECT_POLL))
! eth_fd->ef_flags |= EFF_SEL_READ;
! }
! if (operations & SR_SELECT_WRITE)
! {
! /* Should handle special case when the interface is down */
! resops |= SR_SELECT_WRITE;
! }
! if (operations & SR_SELECT_EXCEPTION)
! {
! printf("eth_select: not implemented for exceptions\n");
! }
! return resops;
}

PUBLIC void eth_close(fd)
***************
*** 1012,1017 ****
--- 1040,1071 ----
}
}

+ PRIVATE int eth_sel_read (eth_fd)
+ eth_fd_t *eth_fd;
+ {
+ acc_t *pack, *tmp_acc, *next_acc;
+ int result;
+
+ if (!(eth_fd->ef_flags & EFF_OPTSET))
+ return 1; /* Read will not block */
+
+ if (eth_fd->ef_rdbuf_head)
+ {
+ if (get_time() <= eth_fd->ef_exp_time)
+ return 1;
+
+ tmp_acc= eth_fd->ef_rdbuf_head;
+ while (tmp_acc)
+ {
+ next_acc= tmp_acc->acc_ext_link;
+ bf_afree(tmp_acc);
+ tmp_acc= next_acc;
+ }
+ eth_fd->ef_rdbuf_head= NULL;
+ }
+ return 0;
+ }
+
PRIVATE void packet2user (eth_fd, pack, exp_time)
eth_fd_t *eth_fd;
acc_t *pack;
***************
*** 1040,1045 ****
--- 1094,1108 ----
else
eth_fd->ef_rdbuf_tail->acc_ext_link= pack;
eth_fd->ef_rdbuf_tail= pack;
+
+ if (eth_fd->ef_flags & EFF_SEL_READ)
+ {
+ eth_fd->ef_flags &= ~EFF_SEL_READ;
+ if (eth_fd->ef_select_res)
+ eth_fd->ef_select_res(eth_fd->ef_srfd, SR_SELECT_READ);
+ else
+ printf("packet2user: no select_res\n");
+ }
return;
}