]> Zhao Yanbai Git Server - minix.git/commitdiff
Initial convertion to asynchronous sends for communicating with ethernet
authorPhilip Homburg <philip@cs.vu.nl>
Mon, 23 Apr 2007 14:49:20 +0000 (14:49 +0000)
committerPhilip Homburg <philip@cs.vu.nl>
Mon, 23 Apr 2007 14:49:20 +0000 (14:49 +0000)
drivers.

servers/inet/generic/eth.c
servers/inet/generic/eth_int.h
servers/inet/generic/ip_ioctl.c
servers/inet/inet.c
servers/inet/inet_config.c
servers/inet/mnx_eth.c
servers/inet/osdep_eth.h

index 59a17dc33791cfe415d9ce70de94255e8faa693c..75e3c3985f2f0c3e6014bae359d123b89b244bc6 100644 (file)
@@ -100,7 +100,8 @@ PUBLIC void eth_init()
                eth_fd_table[i].ef_flags= EFF_EMPTY;
        for (i=0; i<eth_conf_nr; i++)
        {
-               eth_port_table[i].etp_flags= EFF_EMPTY;
+               eth_port_table[i].etp_flags= EPF_EMPTY;
+               eth_port_table[i].etp_getstat= NULL;
                eth_port_table[i].etp_sendq_head= NULL;
                eth_port_table[i].etp_sendq_tail= NULL;
                eth_port_table[i].etp_type_any= NULL;
@@ -346,6 +347,15 @@ ioreq_t req;
                                return NW_SUSPEND;
                        }
 
+                       if (eth_port->etp_getstat)
+                       {
+                               printf(
+       "eth_ioctl: pending eth_get_stat request, suspending caller\n");
+                               assert(!(eth_fd->ef_flags & EFF_IOCTL_IP));
+                               eth_fd->ef_flags |= EFF_IOCTL_IP;
+                               return NW_SUSPEND;
+                       }
+
                        acc= bf_memreq(sizeof(nwio_ethstat_t));
                        compare (bf_bufsize(acc), ==, sizeof(*ethstat));
 
@@ -356,6 +366,20 @@ ioreq_t req;
                        {
                                result= eth_get_stat(eth_port,
                                        &ethstat->nwes_stat);
+                               if (result == SUSPEND)
+                               {
+                                       printf(
+                               "eth_ioctl: eth_get_stat returned SUSPEND\n");
+                                       eth_fd->ef_ioctl_req= req;
+                                       assert(!(eth_fd->ef_flags &
+                                               EFF_IOCTL_IP));
+                                       eth_fd->ef_flags |= EFF_IOCTL_IP;
+printf("eth_ioctl: setting etp_getstat in port %d to %p\n",
+       eth_port-eth_port_table, acc);
+                                       eth_port->etp_getstat= acc;
+                                       acc= NULL;
+                                       return NW_SUSPEND;
+                               }
                                if (result != NW_OK)
                                {
                                        bf_afree(acc);
@@ -993,8 +1017,18 @@ eth_port_t *vlan_port;
 PUBLIC void eth_restart_ioctl(eth_port)
 eth_port_t *eth_port;
 {
-       int i;
+       int i, r;
        eth_fd_t *eth_fd;
+       acc_t *acc;
+
+       printf("in eth_restart_ioctl\n");
+
+       /* eth_restart_ioctl is called on too occasions: when a device
+        * driver registers with inet and when a eth_get_stat call has
+        * completed. We assume the second option when etp_getstat is
+        * not equal to zero at the start of the call.
+        */
+       acc= eth_port->etp_getstat;
 
        for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
        {
@@ -1007,9 +1041,36 @@ eth_port_t *eth_port;
                if (eth_fd->ef_ioctl_req != NWIOGETHSTAT)
                        continue;
 
+printf("eth_restart_ioctl: etp_getstat in port %d is %p\n",
+       eth_port-eth_port_table, acc);
+
+               if (acc != NULL)
+               {
+                       printf("eth_restart_ioctl: completed getstat\n");
+                       acc->acc_linkC++;
+                       r= (*eth_fd->ef_put_userdata)(eth_fd->ef_srfd, 0,
+                               acc, TRUE);
+                       if (r >= 0)
+                               reply_thr_put(eth_fd, NW_OK, TRUE);
+                       eth_fd->ef_flags &= ~EFF_IOCTL_IP;
+                       continue;
+               }
+
+ { static int count; if (++count > 5) ip_panic(("too many restarts")); }
+
                eth_fd->ef_flags &= ~EFF_IOCTL_IP;
                eth_ioctl(i, eth_fd->ef_ioctl_req);
        }
+
+       if (acc != NULL)
+       {
+printf("eth_restart_ioctl: clearing etp_getstat in port %d\n",
+       eth_port-eth_port_table);
+               assert(acc == eth_port->etp_getstat);
+
+               bf_afree(acc);
+               eth_port->etp_getstat= NULL;
+       }
 }
 
 PRIVATE void packet2user (eth_fd, pack, exp_time)
index d5a4c28b3c8197b5fd6b1448dbcdb9b7a455afe7..b8354dbb7c4b6fd12f6829321022613e6db24a30 100644 (file)
@@ -21,6 +21,7 @@ typedef struct eth_port
        int etp_flags;
        ether_addr_t etp_ethaddr;
        acc_t *etp_wr_pack, *etp_rd_pack;
+       acc_t *etp_getstat;
        struct eth_fd *etp_sendq_head;
        struct eth_fd *etp_sendq_tail;
        struct eth_fd *etp_type_any;
index bbfaf247a217658deaa4a4d6247c2c4bf9dc7d93..d726d7738128aa1b4fc60c2286d3ce4e3b17f64e 100644 (file)
@@ -426,6 +426,15 @@ ioreq_t req;
                        return (*ip_fd->if_put_userdata)(ip_fd->if_srfd, 
                                EBADIOCTL, (acc_t *)0, TRUE);
                }
+
+               if (!(ip_port->ip_flags & IPF_IPADDRSET))
+               {
+                       ip_fd->if_ioctl= req;
+                       ip_fd->if_flags |= IFF_IOCTL_IP;
+                       printf("ip_ioctl: suspending ARP request\n");
+                       return NW_SUSPEND;
+               }
+
                result= arp_ioctl(ip_port->ip_dl.dl_eth.de_port,
                        ip_fd->if_srfd, req, ip_fd->if_get_userdata,
                        ip_fd->if_put_userdata);
index 9ce7db78c8e6e1b05411b839beb74f094bced015..d7fefa9e4695bb8ab8402c57036fc379eab30346 100644 (file)
@@ -35,7 +35,7 @@ from DL_ETH:
 | m_type       |  DL_PORT  | DL_PROC | DL_COUNT |  DL_STAT   | DL_TIME |
 |_______________|___________|_________|__________|____________|_________|
 |              |           |         |          |            |         |
-| DL_INIT_REPLY        | minor dev | proc nr | rd_count |  0  | stat |  time   |
+| DL_CONF_REPLY        | minor dev | proc nr | rd_count |  0  | stat |  time   |
 |_______________|___________|_________|__________|____________|_________|
 |              |           |         |          |            |         |
 | DL_TASK_REPLY        | minor dev | proc nr | rd_count | err | stat |  time   |
@@ -95,7 +95,7 @@ PUBLIC void main()
 {
        mq_t *mq;
        int r;
-       int source, timerand, fd;
+       int source, m_type, timerand, fd;
        struct fssignon device;
 #ifdef __minix_vmd
        struct systaskinfo info;
@@ -229,6 +229,7 @@ PUBLIC void main()
                }
                reset_time();
                source= mq->mq_mess.m_source;
+               m_type= mq->mq_mess.m_type;
                if (source == FS_PROC_NR)
                {
                        sr_rec(mq);
@@ -240,25 +241,26 @@ PUBLIC void main()
                        mq_free(mq);
                }
 #else /* Minix 3 */
-               else if (mq->mq_mess.m_type == SYN_ALARM)
+               else if (m_type == SYN_ALARM)
                {
                        clck_tick(&mq->mq_mess);
                        mq_free(mq);
                } 
-               else if (mq->mq_mess.m_type == PROC_EVENT)
+               else if (m_type == PROC_EVENT)
                {
                        /* signaled */ 
                        /* probably SIGTERM */
                        mq_free(mq);
                } 
-               else if (mq->mq_mess.m_type & NOTIFY_MESSAGE)
+               else if (m_type & NOTIFY_MESSAGE)
                {
                        /* A driver is (re)started. */
                        eth_check_drivers(&mq->mq_mess);
                        mq_free(mq);
                }
 #endif
-               else if (mq->mq_mess.m_type == DL_TASK_REPLY)
+               else if (m_type == DL_CONF_REPLY || m_type == DL_TASK_REPLY ||
+                       m_type == DL_NAME_REPLY || m_type == DL_STAT_REPLY)
                {
                        eth_rec(&mq->mq_mess);
                        mq_free(mq);
index 5c1b68caa82020c3a07550ffa6d4ac217f6f60bf..b8794c0f0713fafe0a62c7cdcedc7d92a2a48dd2 100644 (file)
@@ -23,6 +23,9 @@ Copyright 1995 Philip Homburg
 #include <minix/sysutil.h>
 #include <minix/syslib.h>
 #include "inet_config.h"
+#include "inet.h"
+
+THIS_FILE
 
 struct eth_conf eth_conf[IP_PORT_MAX];
 struct psip_conf psip_conf[IP_PORT_MAX];
@@ -213,6 +216,13 @@ void read_conf(void)
        struct ip_conf *icp;
        struct stat st;
 
+       { static int first= 1; 
+               if (!first) ip_panic(( "read_conf: called a second time" ));
+               first= 0;
+               *(u8_t *)0 = 0xcc;      /* INT 3 */
+       }
+
+
        /* Open the configuration file. */
        if ((cfg_fd= open(PATH_INET_CONF, O_RDONLY)) == -1)
                fatal(PATH_INET_CONF);
index 44bb82e3fca61d80cb2cc3e05fe1b1ab9ea33e01..859dc70991a3f92e4c188752ef1dcdbe8417d158 100644 (file)
@@ -25,11 +25,15 @@ static int recv_debug= 0;
 
 FORWARD _PROTOTYPE( void setup_read, (eth_port_t *eth_port) );
 FORWARD _PROTOTYPE( void read_int, (eth_port_t *eth_port, int count) );
+FORWARD _PROTOTYPE( void eth_issue_send, (eth_port_t *eth_port) );
 FORWARD _PROTOTYPE( void write_int, (eth_port_t *eth_port) );
 FORWARD _PROTOTYPE( void eth_recvev, (event_t *ev, ev_arg_t ev_arg) );
 FORWARD _PROTOTYPE( void eth_sendev, (event_t *ev, ev_arg_t ev_arg) );
 FORWARD _PROTOTYPE( eth_port_t *find_port, (message *m) );
 FORWARD _PROTOTYPE( void eth_restart, (eth_port_t *eth_port, int tasknr) );
+FORWARD _PROTOTYPE( void send_getstat, (eth_port_t *eth_port) );
+
+FORWARD _PROTOTYPE( int asynsend, (endpoint_t dst, message *mp) );
 
 PUBLIC void osdep_eth_init()
 {
@@ -51,6 +55,11 @@ PUBLIC void osdep_eth_init()
                        eth_port->etp_osdep.etp_rd_iovec[j].iov_grant= -1;
                eth_port->etp_osdep.etp_rd_vec_grant= -1;
 
+               eth_port->etp_osdep.etp_state= OEPS_INIT;
+               eth_port->etp_osdep.etp_flags= OEPF_EMPTY;
+               eth_port->etp_osdep.etp_stat_gid= -1;
+               eth_port->etp_osdep.etp_stat_buf= NULL;
+
                if (eth_is_vlan(ecp))
                        continue;
 
@@ -120,8 +129,11 @@ PUBLIC void osdep_eth_init()
                        r= ENXIO;
                else
                {
-                       r= send(eth_port->etp_osdep.etp_task, &mess);
-                       if (r<0)
+                       assert(eth_port->etp_osdep.etp_state == OEPS_INIT);
+                       r= asynsend(eth_port->etp_osdep.etp_task, &mess);
+                       if (r == OK)
+                               eth_port->etp_osdep.etp_state= OEPS_CONF_SENT;
+                       else
                        {
                                printf(
                "osdep_eth_init: unable to send to ethernet task, error= %d\n",
@@ -129,41 +141,7 @@ PUBLIC void osdep_eth_init()
                        }
                }
 
-               if (r == OK)
-               {
-                       r= receive(eth_port->etp_osdep.etp_task, &mess);
-                       if (r<0)
-                       {
-                               printf(
-       "osdep_eth_init: unable to receive from ethernet task, error= %d\n",
-                                       r);
-                       }
-               }
-
-               if (r == OK)
-               {
-                       r= mess.m3_i1;
-                       if (r == ENXIO)
-                       {
-                               printf(
-               "osdep_eth_init: no ethernet device at task=%d,port=%d\n",
-                                       eth_port->etp_osdep.etp_task, 
-                                       eth_port->etp_osdep.etp_port);
-                       }
-                       else if (r < 0)
-                       {
-                               ip_panic((
-                               "osdep_eth_init: DL_INIT returned error %d\n",
-                                       r));
-                       }
-                       else if (mess.m3_i1 != eth_port->etp_osdep.etp_port)
-                       {
-                               ip_panic((
-       "osdep_eth_init: got reply for wrong port (got %d, expected %d)\n",
-                                       mess.m3_i1,
-                                       eth_port->etp_osdep.etp_port));
-                       }
-               }
+               r= ENXIO;
                        
                sr_add_minor(if2minor(ecp->ec_ifno, ETH_DEV_OFF),
                        i, eth_open, eth_close, eth_read, 
@@ -177,6 +155,7 @@ PUBLIC void osdep_eth_init()
                if (r == OK)
                {
                        eth_port->etp_ethaddr= *(ether_addr_t *)mess.m3_ca1;
+                       printf("osdep_eth_init: setting EPF_GOT_ADDR\n");
                        eth_port->etp_flags |= EPF_GOT_ADDR;
                        setup_read (eth_port);
                }
@@ -214,6 +193,7 @@ PUBLIC void osdep_eth_init()
                if (rep->etp_flags & EPF_GOT_ADDR)
                {
                        eth_port->etp_ethaddr= rep->etp_ethaddr;
+                       printf("osdep_eth_init: setting EPF_GOT_ADDR\n");
                        eth_port->etp_flags |= EPF_GOT_ADDR;
                }
 
@@ -237,9 +217,6 @@ acc_t *pack;
 {
        eth_port_t *loc_port;
        message mess1, block_msg;
-       int i, pack_size;
-       acc_t *pack_ptr;
-       iovec_s_t *iovec;
        u8_t *eth_dst_ptr;
        int multicast, r;
        ev_arg_t ev_arg;
@@ -250,202 +227,214 @@ acc_t *pack;
        assert(eth_port->etp_wr_pack == NULL);
        eth_port->etp_wr_pack= pack;
 
-       iovec= eth_port->etp_osdep.etp_wr_iovec;
-       pack_size= 0;
-       for (i=0, pack_ptr= pack; i<IOVEC_NR && pack_ptr; i++,
-               pack_ptr= pack_ptr->acc_next)
+       if (eth_port->etp_osdep.etp_state != OEPS_IDLE)
        {
-               r= cpf_setgrant_direct(iovec[i].iov_grant,
-                       eth_port->etp_osdep.etp_task,
-                       (vir_bytes)ptr2acc_data(pack_ptr),
-                       (vir_bytes)pack_ptr->acc_length,
-                       CPF_READ);
-               if (r != 0)
-               {
-                       ip_panic((
-               "eth_write_port: cpf_setgrant_direct failed: %d\n",
-                               errno));
-               }
-               pack_size += iovec[i].iov_size= pack_ptr->acc_length;
+               eth_port->etp_osdep.etp_flags |= OEPF_NEED_SEND;
+               return;
        }
-       if (i>= IOVEC_NR)
+
+
+       eth_issue_send(eth_port);
+}
+
+PRIVATE int notification_count;
+
+PUBLIC void eth_rec(m)
+message *m;
+{
+       int i, r, m_type, stat;
+       eth_port_t *loc_port, *vlan_port;
+       char *drivername;
+       struct eth_conf *ecp;
+
+       m_type= m->m_type;
+       if (m_type == DL_NAME_REPLY)
        {
-               pack= bf_pack(pack);            /* packet is too fragmented */
-               eth_port->etp_wr_pack= pack;
-               pack_size= 0;
-               for (i=0, pack_ptr= pack; i<IOVEC_NR && pack_ptr;
-                       i++, pack_ptr= pack_ptr->acc_next)
+               drivername= m->m3_ca1;
+               printf("eth_rec: got name: %s\n", drivername);
+
+               notification_count= 0;
+
+               /* Re-init ethernet interfaces */
+               for (i= 0, ecp= eth_conf, loc_port= eth_port_table;
+                       i<eth_conf_nr; i++, ecp++, loc_port++)
                {
-                       r= cpf_setgrant_direct(iovec[i].iov_grant,
-                               eth_port->etp_osdep.etp_task,
-                               (vir_bytes)ptr2acc_data(pack_ptr),
-                               (vir_bytes)pack_ptr->acc_length,
-                               CPF_READ);
-                       if (r != 0)
+                       if (eth_is_vlan(ecp))
+                               continue;
+
+                       if (strcmp(ecp->ec_task, drivername) != 0)
                        {
-                               ip_panic((
-                       "eth_write_port: cpf_setgrant_direct failed: %d\n",
-                                       errno));
+                               /* Wrong driver */
+                               continue;
                        }
-                       pack_size += iovec[i].iov_size= pack_ptr->acc_length;
+                       eth_restart(loc_port, m->m_source);
                }
+               return;
        }
-       assert (i< IOVEC_NR);
-       assert (pack_size >= ETH_MIN_PACK_SIZE);
 
+       assert(m_type == DL_CONF_REPLY || m_type == DL_TASK_REPLY ||
+               m_type == DL_STAT_REPLY);
 
-       r= cpf_setgrant_direct(eth_port->etp_osdep.etp_wr_vec_grant,
-               eth_port->etp_osdep.etp_task,
-               (vir_bytes)iovec,
-               (vir_bytes)(i * sizeof(iovec[0])),
-               CPF_READ);
-       if (r != 0)
+       for (i=0, loc_port= eth_port_table; i<eth_conf_nr; i++, loc_port++)
        {
-               ip_panic((
-       "eth_write_port: cpf_setgrant_direct failed: %d\n",
-                       errno));
+               if (loc_port->etp_osdep.etp_port == m->DL_PORT &&
+                       loc_port->etp_osdep.etp_task == m->m_source)
+                       break;
+       }
+       if (i >= eth_conf_nr)
+       {
+               printf("eth_rec: bad port %d in message type 0x%x from %d\n",
+                       m->DL_PORT, m_type, m->m_source);
+               return;
        }
-       mess1.DL_COUNT= i;
-       mess1.DL_GRANT= eth_port->etp_osdep.etp_wr_vec_grant;
-       mess1.m_type= DL_WRITEV_S;
-
-       mess1.DL_PORT= eth_port->etp_osdep.etp_port;
-       mess1.DL_PROC= this_proc;
-       mess1.DL_MODE= DL_NOMODE;
 
-       for (;;)
+       if (loc_port->etp_osdep.etp_state == OEPS_CONF_SENT)
        {
-               r= sendrec(eth_port->etp_osdep.etp_task, &mess1);
-               if (r != ELOCKED)
-                       break;
+               if (m_type == DL_TASK_REPLY)
+               {
+                       stat= m->DL_STAT & 0xffff;
 
-               /* ethernet task is sending to this task, I hope */
-               r= receive(eth_port->etp_osdep.etp_task, &block_msg);
-               if (r < 0)
-                       ip_panic(("unable to receive"));
+                       if (stat & DL_PACK_SEND)
+                               write_int(loc_port);
+                       if (stat & DL_PACK_RECV)
+                               read_int(loc_port, m->DL_COUNT);
+                       return;
+               }
 
-               loc_port= eth_port;
-               if (loc_port->etp_osdep.etp_port != block_msg.DL_PORT ||
-                       loc_port->etp_osdep.etp_task != block_msg.m_source)
+               if (m_type != DL_CONF_REPLY)
                {
-                       loc_port= find_port(&block_msg);
+                       printf(
+       "eth_rec: got bad message type 0x%x from %d in CONF state\n",
+                               m_type, m->m_source);
+                       return;
                }
-               assert(block_msg.DL_STAT & (DL_PACK_SEND|DL_PACK_RECV));
-               if (block_msg.DL_STAT & DL_PACK_SEND)
+
+               r= m->m3_i1;
+               if (r == ENXIO)
+               {
+                       printf(
+       "eth_rec(conf_reply): no ethernet device at task=%d,port=%d\n",
+                               loc_port->etp_osdep.etp_task, 
+                               loc_port->etp_osdep.etp_port);
+                       return;
+               }
+               if (r < 0)
                {
-                       assert(loc_port != eth_port);
-                       loc_port->etp_osdep.etp_sendrepl= block_msg;
-                       ev_arg.ev_ptr= loc_port;
-                       assert(!loc_port->etp_osdep.etp_send_ev);
-                       loc_port->etp_osdep.etp_send_ev= 1;
-                       ev_enqueue(&loc_port->etp_sendev, eth_sendev, ev_arg);
+                       ip_panic(("eth_rec: DL_INIT returned error %d\n", r));
+                       return;
                }
-               if (block_msg.DL_STAT & DL_PACK_RECV)
+       
+               loc_port->etp_osdep.etp_flags &= ~OEPF_NEED_CONF;
+               loc_port->etp_osdep.etp_state= OEPS_IDLE;
+               loc_port->etp_flags |= EPF_ENABLED;
+
+               loc_port->etp_ethaddr= *(ether_addr_t *)m->m3_ca1;
+               if (!(loc_port->etp_flags & EPF_GOT_ADDR))
                {
-                       if (recv_debug)
+                       loc_port->etp_flags |= EPF_GOT_ADDR;
+                       printf("eth_rec: calling eth_restart_ioctl\n");
+                       eth_restart_ioctl(loc_port);
+
+                       /* Also update any VLANs on this device */
+                       for (i=0, vlan_port= eth_port_table; i<eth_conf_nr;
+                               i++, vlan_port++)
                        {
-                               printf(
-                       "eth_write_port(block_msg): eth%d got DL_PACK_RECV\n",
-                                       loc_port-eth_port_table);
+                               if (!(vlan_port->etp_flags & EPF_ENABLED))
+                                       continue;
+                               if (vlan_port->etp_vlan_port != loc_port)
+                                       continue;
+                                
+                               vlan_port->etp_ethaddr= loc_port->etp_ethaddr;
+                               vlan_port->etp_flags |= EPF_GOT_ADDR;
+                               eth_restart_ioctl(vlan_port);
                        }
-                       loc_port->etp_osdep.etp_recvrepl= block_msg;
-                       ev_arg.ev_ptr= loc_port;
-                       ev_enqueue(&loc_port->etp_osdep.etp_recvev,
-                               eth_recvev, ev_arg);
                }
-       }
+               if (!(loc_port->etp_flags & EPF_READ_IP))
+                       setup_read (loc_port);
 
-       if (r < 0)
-       {
-               printf("eth_write_port: sendrec to %d failed: %d\n",
-                       eth_port->etp_osdep.etp_task, r);
-               return;
-       }
+               if (loc_port->etp_osdep.etp_flags & OEPF_NEED_SEND)
+               {
+                       printf("eth_rec(conf): OEPF_NEED_SEND is set\n");
+               }
+               if (loc_port->etp_osdep.etp_flags & OEPF_NEED_RECV)
+               {
+                       printf("eth_rec(conf): OEPF_NEED_RECV is set\n");
+               }
+               if (loc_port->etp_osdep.etp_flags & OEPF_NEED_STAT)
+               {
+                       printf("eth_rec(conf): OEPF_NEED_STAT is set\n");
+               }
 
-       if (mess1.m_type != DL_TASK_REPLY ||
-               mess1.DL_PORT != eth_port->etp_osdep.etp_port ||
-               mess1.DL_PROC != this_proc)
-       {
-               printf(
-"eth_write_port: ignoring bad message (type = 0x%x, port = %d, proc = %d) from %d\n",
-                       mess1.m_type, mess1.DL_PORT, mess1.DL_PROC,
-                       mess1.m_source);
                return;
        }
-
-       assert(mess1.m_type == DL_TASK_REPLY &&
-               mess1.DL_PORT == eth_port->etp_osdep.etp_port &&
-               mess1.DL_PROC == this_proc);
-       assert((mess1.DL_STAT >> 16) == OK);
-
-       if (mess1.DL_STAT & DL_PACK_RECV)
+       if (loc_port->etp_osdep.etp_state == OEPS_GETSTAT_SENT)
        {
-               if (recv_debug)
+               if (m_type != DL_STAT_REPLY)
                {
                        printf(
-                       "eth_write_port(mess1): eth%d got DL_PACK_RECV\n",
-                               mess1.DL_PORT);
+       "eth_rec: got bad message type 0x%x from %d in GETSTAT state\n",
+                               m_type, m->m_source);
+                       return;
                }
-               eth_port->etp_osdep.etp_recvrepl= mess1;
-               ev_arg.ev_ptr= eth_port;
-               ev_enqueue(&eth_port->etp_osdep.etp_recvev, eth_recvev,
-                       ev_arg);
-       }
-       if (!(mess1.DL_STAT & DL_PACK_SEND))
-       {
-               /* Packet is not yet sent. */
-               return;
-       }
 
-       /* If the port is in promiscuous mode or the packet is
-        * broad- or multicast, enqueue the reply packet.
-        */
-       eth_dst_ptr= (u8_t *)ptr2acc_data(pack);
-       multicast= (*eth_dst_ptr & 1);  /* low order bit indicates multicast */
-       if (multicast || (eth_port->etp_osdep.etp_recvconf & NWEO_EN_PROMISC))
-       {
-               eth_port->etp_osdep.etp_sendrepl= mess1;
-               ev_arg.ev_ptr= eth_port;
-               assert(!eth_port->etp_osdep.etp_send_ev);
-               eth_port->etp_osdep.etp_send_ev= 1;
-               ev_enqueue(&eth_port->etp_sendev, eth_sendev, ev_arg);
+               r= m->DL_STAT;
+               if (r != OK)
+               {
+                       ip_warning(("eth_rec: DL_STAT returned error %d\n",
+                               r));
+                       return;
+               }
+       
+               loc_port->etp_osdep.etp_state= OEPS_IDLE;
+               loc_port->etp_osdep.etp_flags &= ~OEPF_NEED_STAT;
 
-               /* Pretend that we didn't get a reply. */
+               assert(loc_port->etp_osdep.etp_stat_gid != -1);
+               cpf_revoke(loc_port->etp_osdep.etp_stat_gid);
+               loc_port->etp_osdep.etp_stat_gid= -1;
+               loc_port->etp_osdep.etp_stat_buf= NULL;
+               
+               /* Finish ioctl */
+               assert(loc_port->etp_flags & EPF_GOT_ADDR);
+               eth_restart_ioctl(loc_port);
+
+               if (loc_port->etp_osdep.etp_flags & OEPF_NEED_SEND)
+               {
+                       printf("eth_rec(stat): OEPF_NEED_SEND is set\n");
+               }
+               if (loc_port->etp_osdep.etp_flags & OEPF_NEED_RECV)
+               {
+                       printf("eth_rec(stat): OEPF_NEED_RECV is set\n");
+               }
+               if (loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF)
+               {
+                       printf("eth_rec(stat): OEPF_NEED_CONF is set\n");
+               }
+#if 0
+               if (loc_port->etp_osdep.etp_state == OEPS_IDLE &&
+                       (loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF))
+               {
+                       eth_set_rec_conf(loc_port,
+                               loc_port->etp_osdep.etp_recvconf);
+               }
+#endif
                return;
        }
+       assert(loc_port->etp_osdep.etp_state == OEPS_IDLE  ||
+               loc_port->etp_osdep.etp_state == OEPS_RECV_SENT ||
+               loc_port->etp_osdep.etp_state == OEPS_SEND_SENT ||
+               (printf("etp_state = %d\n", loc_port->etp_osdep.etp_state), 0));
+       loc_port->etp_osdep.etp_state= OEPS_IDLE;
 
-       /* packet is sent */
-       bf_afree(eth_port->etp_wr_pack);
-       eth_port->etp_wr_pack= NULL;
-}
-
-PUBLIC void eth_rec(m)
-message *m;
-{
-       int i;
-       eth_port_t *loc_port;
-       int stat;
-
-       assert(m->m_type == DL_TASK_REPLY);
-
+#if 0 /* Ethernet driver is not trusted */
        set_time (m->DL_CLCK);
-
-       for (i=0, loc_port= eth_port_table; i<eth_conf_nr; i++, loc_port++)
-       {
-               if (loc_port->etp_osdep.etp_port == m->DL_PORT &&
-                       loc_port->etp_osdep.etp_task == m->m_source)
-                       break;
-       }
-       if (i == eth_conf_nr)
-       {
-               ip_panic(("message from unknown source: %d:%d",
-                       m->m_source, m->DL_PORT));
-       }
+#endif
 
        stat= m->DL_STAT & 0xffff;
 
+#if 0
        if (!(stat & (DL_PACK_SEND|DL_PACK_RECV)))
                printf("eth_rec: neither DL_PACK_SEND nor DL_PACK_RECV\n");
+#endif
        if (stat & DL_PACK_SEND)
                write_int(loc_port);
        if (stat & DL_PACK_RECV)
@@ -457,53 +446,54 @@ message *m;
                }
                read_int(loc_port, m->DL_COUNT);
        }
+
+       if (loc_port->etp_osdep.etp_state == OEPS_IDLE &&
+               loc_port->etp_osdep.etp_flags & OEPF_NEED_SEND)
+       {
+               loc_port->etp_osdep.etp_flags &= ~OEPF_NEED_SEND;
+               if (loc_port->etp_wr_pack)
+                       eth_issue_send(loc_port);
+       }
+       if (loc_port->etp_osdep.etp_state == OEPS_IDLE &&
+               (loc_port->etp_osdep.etp_flags & OEPF_NEED_RECV))
+       {
+               printf("eth_rec: OEPF_NEED_RECV is set\n");
+               loc_port->etp_osdep.etp_flags &= ~OEPF_NEED_RECV;
+               if (!(loc_port->etp_flags & EPF_READ_IP))
+                       setup_read (loc_port);
+       }
+       if (loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF)
+       {
+               printf("eth_rec: OEPF_NEED_CONF is set\n");
+       }
+       if (loc_port->etp_osdep.etp_state == OEPS_IDLE &&
+               (loc_port->etp_osdep.etp_flags & OEPF_NEED_STAT))
+       {
+               send_getstat(loc_port);
+       }
 }
 
 PUBLIC void eth_check_drivers(m)
 message *m;
 {
        int i, r, tasknr;
-       struct eth_conf *ecp;
-       eth_port_t *eth_port;
-       char *drivername;
 
        tasknr= m->m_source;
-       printf("eth_check_drivers: got a notification from %d\n", tasknr);
-
+       if (notification_count < 100)
+       {
+               notification_count++;
+               printf("eth_check_drivers: got a notification #%d from %d\n",
+                       notification_count, tasknr);
+       }
+               
        m->m_type= DL_GETNAME;
-       r= sendrec(tasknr, m);
+       r= asynsend(tasknr, m);
        if (r != OK)
        {
-               printf("eth_check_drivers: sendrec to %d failed: %d\n",
+               printf("eth_check_drivers: asynsend to %d failed: %d\n",
                        tasknr, r);
                return;
        }
-       if (m->m_type != DL_NAME_REPLY)
-       {
-               printf(
-               "eth_check_drivers: got bad getname reply (%d) from %d\n",
-                       m->m_type, tasknr);
-               return;
-       }
-
-       drivername= m->m3_ca1;
-       printf("eth_check_drivers: got name: %s\n", drivername);
-
-       /* Re-init ethernet interfaces */
-       for (i= 0, ecp= eth_conf, eth_port= eth_port_table;
-               i<eth_conf_nr; i++, ecp++, eth_port++)
-       {
-               if (eth_is_vlan(ecp))
-                       continue;
-
-               if (strcmp(ecp->ec_task, drivername) != 0)
-               {
-                       /* Wrong driver */
-                       continue;
-               }
-
-               eth_restart(eth_port, tasknr);
-       }
 }
 
 PUBLIC int eth_get_stat(eth_port, eth_stat)
@@ -512,10 +502,12 @@ eth_stat_t *eth_stat;
 {
        int r;
        cp_grant_id_t gid;
-       message mess, mlocked;
 
        assert(!eth_port->etp_vlan);
 
+       if (eth_port->etp_osdep.etp_flags & OEPF_NEED_STAT)
+               ip_panic(( "eth_get_stat: getstat already in progress" ));
+
        gid= cpf_grant_direct(eth_port->etp_osdep.etp_task,
                (vir_bytes)eth_stat, sizeof(*eth_stat), CPF_WRITE);
        if (gid == -1)
@@ -523,43 +515,19 @@ eth_stat_t *eth_stat;
                ip_panic(( "eth_get_stat: cpf_grant_direct failed: %d\n",
                        errno));
        }
+       assert(eth_port->etp_osdep.etp_stat_gid == -1);
+       eth_port->etp_osdep.etp_stat_gid= gid;
+       eth_port->etp_osdep.etp_stat_buf= eth_stat;
 
-       mess.m_type= DL_GETSTAT_S;
-       mess.DL_PORT= eth_port->etp_osdep.etp_port;
-       mess.DL_PROC= this_proc;
-       mess.DL_GRANT= gid;
-
-       for (;;)
-       {
-               r= sendrec(eth_port->etp_osdep.etp_task, &mess);
-               if (r != ELOCKED)
-                       break;
-
-               r= receive(eth_port->etp_osdep.etp_task, &mlocked);
-               assert(r == OK);
-
-               compare(mlocked.m_type, ==, DL_TASK_REPLY);
-               eth_rec(&mlocked);
-       }
-       cpf_revoke(gid);
-
-       if (r != OK)
+       if (eth_port->etp_osdep.etp_state != OEPS_IDLE)
        {
-               printf("eth_get_stat: sendrec to %d failed: %d\n",
-                       eth_port->etp_osdep.etp_task, r);
-               return EIO;
+               eth_port->etp_osdep.etp_flags |= OEPF_NEED_STAT;
+               return SUSPEND;
        }
 
-       assert(mess.m_type == DL_TASK_REPLY);
-
-       r= mess.DL_STAT >> 16;
-       assert (r == 0);
+       send_getstat(eth_port);
 
-       if (mess.DL_STAT)
-       {
-               eth_rec(&mess);
-       }
-       return OK;
+       return SUSPEND;
 }
 
 PUBLIC void eth_set_rec_conf (eth_port, flags)
@@ -579,6 +547,15 @@ u32_t flags;
                return;
        }
 
+       if (eth_port->etp_osdep.etp_state != OEPS_IDLE)
+       {
+               printf(
+               "eth_set_rec_conf: setting OEPF_NEED_CONF, state = %d\n",
+                       eth_port->etp_osdep.etp_state);
+               eth_port->etp_osdep.etp_flags |= OEPF_NEED_CONF;
+               return;
+       }
+
        eth_port->etp_osdep.etp_recvconf= flags;
        dl_flags= DL_NOMODE;
        if (flags & NWEO_EN_BROAD)
@@ -593,35 +570,99 @@ u32_t flags;
        mess.DL_PROC= this_proc;
        mess.DL_MODE= dl_flags;
 
-       do
+       assert(eth_port->etp_osdep.etp_state == OEPS_IDLE);
+       r= asynsend(eth_port->etp_osdep.etp_task, &mess);
+       eth_port->etp_osdep.etp_state= OEPS_CONF_SENT;
+
+       if (r < 0)
        {
-               r= sendrec(eth_port->etp_osdep.etp_task, &mess);
-               if (r == ELOCKED)       /* etp_task is sending to this task,
-                                          I hope */
+               printf("eth_set_rec_conf: asynsend to %d failed: %d\n",
+                       eth_port->etp_osdep.etp_task, r);
+               return;
+       }
+}
+
+PRIVATE void eth_issue_send(eth_port)
+eth_port_t *eth_port;
+{
+       int i, r, pack_size;
+       acc_t *pack, *pack_ptr;
+       iovec_s_t *iovec;
+       message m;
+
+       iovec= eth_port->etp_osdep.etp_wr_iovec;
+       pack= eth_port->etp_wr_pack;
+       pack_size= 0;
+       for (i=0, pack_ptr= pack; i<IOVEC_NR && pack_ptr; i++,
+               pack_ptr= pack_ptr->acc_next)
+       {
+               r= cpf_setgrant_direct(iovec[i].iov_grant,
+                       eth_port->etp_osdep.etp_task,
+                       (vir_bytes)ptr2acc_data(pack_ptr),
+                       (vir_bytes)pack_ptr->acc_length,
+                       CPF_READ);
+               if (r != 0)
                {
-                       if (receive (eth_port->etp_osdep.etp_task, 
-                               &repl_mess)< 0)
+                       ip_panic((
+               "eth_write_port: cpf_setgrant_direct failed: %d\n",
+                               errno));
+               }
+               pack_size += iovec[i].iov_size= pack_ptr->acc_length;
+       }
+       if (i>= IOVEC_NR)
+       {
+               pack= bf_pack(pack);            /* packet is too fragmented */
+               eth_port->etp_wr_pack= pack;
+               pack_size= 0;
+               for (i=0, pack_ptr= pack; i<IOVEC_NR && pack_ptr;
+                       i++, pack_ptr= pack_ptr->acc_next)
+               {
+                       r= cpf_setgrant_direct(iovec[i].iov_grant,
+                               eth_port->etp_osdep.etp_task,
+                               (vir_bytes)ptr2acc_data(pack_ptr),
+                               (vir_bytes)pack_ptr->acc_length,
+                               CPF_READ);
+                       if (r != 0)
                        {
-                               ip_panic(("unable to receive"));
+                               ip_panic((
+                       "eth_write_port: cpf_setgrant_direct failed: %d\n",
+                                       errno));
                        }
-
-                       compare(repl_mess.m_type, ==, DL_TASK_REPLY);
-                       eth_rec(&repl_mess);
+                       pack_size += iovec[i].iov_size= pack_ptr->acc_length;
                }
-       } while (r == ELOCKED);
-       
-       if (r < 0)
+       }
+       assert (i< IOVEC_NR);
+       assert (pack_size >= ETH_MIN_PACK_SIZE);
+
+       r= cpf_setgrant_direct(eth_port->etp_osdep.etp_wr_vec_grant,
+               eth_port->etp_osdep.etp_task,
+               (vir_bytes)iovec,
+               (vir_bytes)(i * sizeof(iovec[0])),
+               CPF_READ);
+       if (r != 0)
        {
-               printf("eth_set_rec_conf: sendrec to %d failed: %d\n",
-                       eth_port->etp_osdep.etp_task, r);
-               return;
+               ip_panic((
+       "eth_write_port: cpf_setgrant_direct failed: %d\n",
+                       errno));
        }
+       m.DL_COUNT= i;
+       m.DL_GRANT= eth_port->etp_osdep.etp_wr_vec_grant;
+       m.m_type= DL_WRITEV_S;
+
+       m.DL_PORT= eth_port->etp_osdep.etp_port;
+       m.DL_PROC= this_proc;
+       m.DL_MODE= DL_NOMODE;
+
+       assert(eth_port->etp_osdep.etp_state == OEPS_IDLE);
+       r= asynsend(eth_port->etp_osdep.etp_task, &m);
 
-       assert (mess.m_type == DL_CONF_REPLY);
-       if (mess.m3_i1 != eth_port->etp_osdep.etp_port)
+       if (r < 0)
        {
-               ip_panic(("got reply for wrong port"));
+               printf("eth_issue_send: send to %d failed: %d\n",
+                       eth_port->etp_osdep.etp_task, r);
+               return;
        }
+       eth_port->etp_osdep.etp_state= OEPS_SEND_SENT;
 }
 
 PRIVATE void write_int(eth_port)
@@ -708,181 +749,68 @@ eth_port_t *eth_port;
        assert(!eth_port->etp_vlan);
        assert(!(eth_port->etp_flags & (EPF_READ_IP|EPF_READ_SP)));
 
-       do
+       if (eth_port->etp_osdep.etp_state != OEPS_IDLE)
        {
-               assert (!eth_port->etp_rd_pack);
+               printf("setup_read: setting OEPF_NEED_RECV\n");
+               eth_port->etp_osdep.etp_flags |= OEPF_NEED_RECV;
 
-               iovec= eth_port->etp_osdep.etp_rd_iovec;
-               pack= bf_memreq (ETH_MAX_PACK_SIZE_TAGGED);
+               return;
+       }
 
-               for (i=0, pack_ptr= pack; i<RD_IOVEC && pack_ptr;
-                       i++, pack_ptr= pack_ptr->acc_next)
-               {
-                       r= cpf_setgrant_direct(iovec[i].iov_grant,
-                               eth_port->etp_osdep.etp_task,
-                               (vir_bytes)ptr2acc_data(pack_ptr),
-                               (vir_bytes)pack_ptr->acc_length,
-                               CPF_WRITE);
-                       if (r != 0)
-                       {
-                               ip_panic((
-                       "mnx_eth`setup_read: cpf_setgrant_direct failed: %d\n",
-                                       errno));
-                       }
-                       iovec[i].iov_size= (vir_bytes)pack_ptr->acc_length;
-               }
-               assert (!pack_ptr);
+       assert (!eth_port->etp_rd_pack);
 
-               r= cpf_setgrant_direct(eth_port->etp_osdep.etp_rd_vec_grant,
+       iovec= eth_port->etp_osdep.etp_rd_iovec;
+       pack= bf_memreq (ETH_MAX_PACK_SIZE_TAGGED);
+
+       for (i=0, pack_ptr= pack; i<RD_IOVEC && pack_ptr;
+               i++, pack_ptr= pack_ptr->acc_next)
+       {
+               r= cpf_setgrant_direct(iovec[i].iov_grant,
                        eth_port->etp_osdep.etp_task,
-                       (vir_bytes)iovec,
-                       (vir_bytes)(i * sizeof(iovec[0])),
-                       CPF_READ);
+                       (vir_bytes)ptr2acc_data(pack_ptr),
+                       (vir_bytes)pack_ptr->acc_length,
+                       CPF_WRITE);
                if (r != 0)
                {
                        ip_panic((
                "mnx_eth`setup_read: cpf_setgrant_direct failed: %d\n",
                                errno));
                }
+               iovec[i].iov_size= (vir_bytes)pack_ptr->acc_length;
+       }
+       assert (!pack_ptr);
 
-               mess1.m_type= DL_READV_S;
-               mess1.DL_PORT= eth_port->etp_osdep.etp_port;
-               mess1.DL_PROC= this_proc;
-               mess1.DL_COUNT= i;
-               mess1.DL_GRANT= eth_port->etp_osdep.etp_rd_vec_grant;
-
-               for (;;)
-               {
-                       if (recv_debug)
-                       {
-                               printf("eth%d: sending DL_READV_S\n",
-                                       mess1.DL_PORT);
-                       }
-                       r= sendrec(eth_port->etp_osdep.etp_task, &mess1);
-                       if (r != ELOCKED)
-                               break;
-
-                       /* ethernet task is sending to this task, I hope */
-                       r= receive(eth_port->etp_osdep.etp_task, &block_msg);
-                       if (r < 0)
-                               ip_panic(("unable to receive"));
-
-                       loc_port= eth_port;
-                       if (loc_port->etp_osdep.etp_port != block_msg.DL_PORT ||
-                               loc_port->etp_osdep.etp_task !=
-                               block_msg.m_source)
-                       {
-                               loc_port= find_port(&block_msg);
-                       }
-                       assert(block_msg.DL_STAT &
-                               (DL_PACK_SEND|DL_PACK_RECV));
-                       if (block_msg.DL_STAT & DL_PACK_SEND)
-                       {
-                               loc_port->etp_osdep.etp_sendrepl=
-                                       block_msg;
-                               ev_arg.ev_ptr= loc_port;
-                               assert(!loc_port->etp_osdep.etp_send_ev);
-                               loc_port->etp_osdep.etp_send_ev= 1;
-                               ev_enqueue(&loc_port->etp_sendev,
-                                       eth_sendev, ev_arg);
-                       }
-                       if (block_msg.DL_STAT & DL_PACK_RECV)
-                       {
-                               if (recv_debug)
-                               {
-                                       printf(
-                       "setup_read(block_msg): eth%d got DL_PACK_RECV\n",
-                                               block_msg.DL_PORT);
-                               }
-                               assert(loc_port != eth_port);
-                               loc_port->etp_osdep.etp_recvrepl= block_msg;
-                               ev_arg.ev_ptr= loc_port;
-                               ev_enqueue(&loc_port->etp_osdep.etp_recvev,
-                                       eth_recvev, ev_arg);
-                       }
-               }
-
-               if (r < 0)
-               {
-                       printf("mnx_eth`setup_read: sendrec to %d failed: %d\n",
-                               eth_port->etp_osdep.etp_task, r);
-                       eth_port->etp_rd_pack= pack;
-                       eth_port->etp_flags |= EPF_READ_IP;
-                       continue;
-               }
-
-               if (mess1.m_type != DL_TASK_REPLY ||
-                       mess1.DL_PORT !=  eth_port->etp_osdep.etp_port ||
-                       mess1.DL_PROC != this_proc)
-               {
-                       printf("mnx_eth`setup_read: bad type, port or proc\n");
-                       printf("got type %d, port %d, proc %d\n",
-                               mess1.m_type, mess1.DL_PORT, mess1.DL_PROC);
-                       continue;
-               }
+       r= cpf_setgrant_direct(eth_port->etp_osdep.etp_rd_vec_grant,
+               eth_port->etp_osdep.etp_task,
+               (vir_bytes)iovec,
+               (vir_bytes)(i * sizeof(iovec[0])),
+               CPF_READ);
+       if (r != 0)
+       {
+               ip_panic((
+       "mnx_eth`setup_read: cpf_setgrant_direct failed: %d\n",
+                       errno));
+       }
 
-               if ((mess1.DL_STAT >> 16) != OK)
-               {
-                       printf(
-                       "mnx_eth`setup_read: bad value in DL_STAT: 0x%x\n",
-                               mess1.DL_STAT);
-                       mess1.DL_STAT= 0;
-               }
+       mess1.m_type= DL_READV_S;
+       mess1.DL_PORT= eth_port->etp_osdep.etp_port;
+       mess1.DL_PROC= this_proc;
+       mess1.DL_COUNT= i;
+       mess1.DL_GRANT= eth_port->etp_osdep.etp_rd_vec_grant;
 
-               if (mess1.DL_STAT & DL_PACK_RECV)
-               {
-                       if (recv_debug)
-                       {
-                               printf(
-                       "setup_read(mess1): eth%d: got DL_PACK_RECV\n",
-                                       mess1.DL_PORT);
-                       }
+       assert(eth_port->etp_osdep.etp_state == OEPS_IDLE);
 
-                       if (mess1.DL_COUNT < ETH_MIN_PACK_SIZE)
-                       {
-                               printf(
-                       "mnx_eth`setup_read: packet size too small (%d)\n",
-                                       mess1.DL_COUNT);
-                               bf_afree(pack);
-                       }
-                       else
-                       {
-                               /* packet received */
-                               pack_ptr= bf_cut(pack, 0, mess1.DL_COUNT);
-                               bf_afree(pack);
-
-                               assert(!no_ethWritePort);
-                               no_ethWritePort= 1;
-                               eth_arrive(eth_port, pack_ptr, mess1.DL_COUNT);
-                               assert(no_ethWritePort);
-                               no_ethWritePort= 0;
-                       }
-               }
-               else
-               {
-                       /* no packet received */
-                       eth_port->etp_rd_pack= pack;
-                       eth_port->etp_flags |= EPF_READ_IP;
-               }
+       r= asynsend(eth_port->etp_osdep.etp_task, &mess1);
+       eth_port->etp_osdep.etp_state= OEPS_RECV_SENT;
 
-               if (mess1.DL_STAT & DL_PACK_SEND)
-               {
-                       if (eth_port->etp_osdep.etp_send_ev)
-                       {
-                               printf(
-       "mnx_eth`setup_read: etp_send_ev is set, ignoring DL_PACK_SEND\n");
-                       }
-                       else
-                       {
-                               eth_port->etp_osdep.etp_sendrepl= mess1;
-                               ev_arg.ev_ptr= eth_port;
-                               assert(!eth_port->etp_osdep.etp_send_ev);
-                               eth_port->etp_osdep.etp_send_ev= 1;
-                               ev_enqueue(&eth_port->etp_sendev, eth_sendev,
-                                       ev_arg);
-                       }
-               }
-       } while (!(eth_port->etp_flags & EPF_READ_IP));
+       if (r < 0)
+       {
+               printf(
+               "mnx_eth`setup_read: asynsend to %d failed: %d\n",
+                       eth_port->etp_osdep.etp_task, r);
+       }
+       eth_port->etp_rd_pack= pack;
+       eth_port->etp_flags |= EPF_READ_IP;
        eth_port->etp_flags |= EPF_READ_SP;
 }
 
@@ -958,15 +886,58 @@ int tasknr;
 {
        int i, r;
        unsigned flags, dl_flags;
+       cp_grant_id_t gid;
        message mess;
-       eth_port_t *loc_port;
 
        printf("eth_restart: restarting eth%d, task %d, port %d\n",
                eth_port-eth_port_table, tasknr,
                eth_port->etp_osdep.etp_port);
 
+       if (eth_port->etp_osdep.etp_task == tasknr)
+       {
+               printf(
+               "eth_restart: task number did not change. Aborting restart\n");
+               return;
+       }
        eth_port->etp_osdep.etp_task= tasknr;
 
+       switch(eth_port->etp_osdep.etp_state)
+       {
+       case OEPS_CONF_SENT:
+       case OEPS_RECV_SENT:
+       case OEPS_SEND_SENT:
+               /* We can safely ignore the pending CONF, RECV, and SEND
+                * requests.
+                */
+               eth_port->etp_osdep.etp_state= OEPS_IDLE;
+               break;
+       case OEPS_GETSTAT_SENT:
+               /* Set the OEPF_NEED_STAT to trigger a new request */
+               eth_port->etp_osdep.etp_flags |= OEPF_NEED_STAT;
+               eth_port->etp_osdep.etp_state= OEPS_IDLE;
+               break;
+       }
+
+       /* If there is a pending GETSTAT request then we have to create a
+        * new grant.
+        */
+       if (eth_port->etp_osdep.etp_flags & OEPF_NEED_STAT)
+       {
+               assert(eth_port->etp_osdep.etp_stat_gid != -1);
+               cpf_revoke(eth_port->etp_osdep.etp_stat_gid);
+
+               gid= cpf_grant_direct(eth_port->etp_osdep.etp_task,
+               (vir_bytes)eth_port->etp_osdep.etp_stat_buf,
+               sizeof(*eth_port->etp_osdep.etp_stat_buf), CPF_WRITE);
+               if (gid == -1)
+               {
+                       ip_panic((
+                               "eth_restart: cpf_grant_direct failed: %d\n",
+                               errno));
+               }
+               eth_port->etp_osdep.etp_stat_gid= gid;
+       }
+
        flags= eth_port->etp_osdep.etp_recvconf;
        dl_flags= DL_NOMODE;
        if (flags & NWEO_EN_BROAD)
@@ -980,57 +951,16 @@ int tasknr;
        mess.DL_PROC= this_proc;
        mess.DL_MODE= dl_flags;
 
-       r= sendrec(eth_port->etp_osdep.etp_task, &mess);
-       /* YYY */
+       compare(eth_port->etp_osdep.etp_state, ==, OEPS_IDLE);
+       r= asynsend(eth_port->etp_osdep.etp_task, &mess);
        if (r<0)
        {
                printf(
-       "eth_restart: sendrec to ethernet task %d failed: %d\n",
+       "eth_restart: send to ethernet task %d failed: %d\n",
                        eth_port->etp_osdep.etp_task, r);
                return;
        }
-
-       if (mess.m3_i1 == ENXIO)
-       {
-               printf(
-       "osdep_eth_init: no ethernet device at task=%d,port=%d\n",
-                       eth_port->etp_osdep.etp_task, 
-                       eth_port->etp_osdep.etp_port);
-               return;
-       }
-       if (mess.m3_i1 < 0)
-               ip_panic(("osdep_eth_init: DL_INIT returned error %d\n",
-                       mess.m3_i1));
-               
-       if (mess.m3_i1 != eth_port->etp_osdep.etp_port)
-       {
-               ip_panic((
-"osdep_eth_init: got reply for wrong port (got %d, expected %d)\n",
-                       mess.m3_i1, eth_port->etp_osdep.etp_port));
-       }
-
-       eth_port->etp_flags |= EPF_ENABLED;
-
-       eth_port->etp_ethaddr= *(ether_addr_t *)mess.m3_ca1;
-       if (!(eth_port->etp_flags & EPF_GOT_ADDR))
-       {
-               eth_port->etp_flags |= EPF_GOT_ADDR;
-               eth_restart_ioctl(eth_port);
-
-               /* Also update any VLANs on this device */
-               for (i=0, loc_port= eth_port_table; i<eth_conf_nr;
-                       i++, loc_port++)
-               {
-                       if (!(loc_port->etp_flags & EPF_ENABLED))
-                               continue;
-                       if (loc_port->etp_vlan_port != eth_port)
-                               continue;
-                        
-                       loc_port->etp_ethaddr= eth_port->etp_ethaddr;
-                       loc_port->etp_flags |= EPF_GOT_ADDR;
-                       eth_restart_ioctl(loc_port);
-               }
-       }
+       eth_port->etp_osdep.etp_state= OEPS_CONF_SENT;
 
        if (eth_port->etp_wr_pack)
        {
@@ -1044,7 +974,76 @@ int tasknr;
                eth_port->etp_rd_pack= NULL;
                eth_port->etp_flags &= ~(EPF_READ_IP|EPF_READ_SP);
        }
-       setup_read (eth_port);
+
+}
+
+PRIVATE void send_getstat(eth_port)
+eth_port_t *eth_port;
+{
+       int r;
+       message mess;
+
+       mess.m_type= DL_GETSTAT_S;
+       mess.DL_PORT= eth_port->etp_osdep.etp_port;
+       mess.DL_PROC= this_proc;
+       mess.DL_GRANT= eth_port->etp_osdep.etp_stat_gid;
+
+       assert(eth_port->etp_osdep.etp_state == OEPS_IDLE);
+
+       r= asynsend(eth_port->etp_osdep.etp_task, &mess);
+       eth_port->etp_osdep.etp_state= OEPS_GETSTAT_SENT;
+
+       if (r != OK)
+               ip_panic(( "eth_get_stat: asynsend failed: %d", r));
+}
+
+PRIVATE asynmsg_t *msgtable= NULL;
+PRIVATE size_t msgtable_n= 0;
+
+PRIVATE int asynsend(dst, mp)
+endpoint_t dst;
+message *mp;
+{
+       int i;
+       unsigned flags;
+
+       if (msgtable == NULL)
+       {
+               printf("asynsend: allocating msg table\n");
+               msgtable_n= 5;
+               msgtable= malloc(msgtable_n * sizeof(msgtable[0]));
+               for (i= 0; i<msgtable_n; i++)
+                       msgtable[i].flags= AMF_EMPTY;
+       }
+
+       /* Find slot in table */
+       for (i= 0; i<msgtable_n; i++)
+       {
+               flags= msgtable[i].flags;
+               if ((flags & (AMF_VALID|AMF_DONE)) == (AMF_VALID|AMF_DONE))
+               {
+                       if (msgtable[i].result != OK)
+                       {
+                               printf(
+                       "asynsend: found completed entry %d with error %d\n",
+                                       i, msgtable[i].result);
+                       }
+                       break;
+               }
+               if (flags == AMF_EMPTY)
+                       break;
+       }
+       if (i >= msgtable_n)
+               ip_panic(( "asynsend: should resize table" ));
+       msgtable[i].dst= dst;
+       msgtable[i].msg= *mp;
+       msgtable[i].flags= AMF_VALID;   /* Has to be last. The kernel 
+                                        * scans this table while we are
+                                        * sleeping.
+                                        */
+
+       /* Tell the kernel to rescan the table */
+       return senda(msgtable, msgtable_n);
 }
 
 /*
index 0bfec142fb1f2f36b9710ca4b4691d0166295852..c19c3171f69d6f00d04443ad785d9a7be9406b8f 100644 (file)
@@ -16,6 +16,8 @@ Copyright 1995 Philip Homburg
 
 typedef struct osdep_eth_port
 {
+       int etp_state;
+       int etp_flags;
        int etp_task;
        int etp_port;
        int etp_recvconf;
@@ -27,8 +29,31 @@ typedef struct osdep_eth_port
        event_t etp_recvev;
        message etp_sendrepl;
        message etp_recvrepl;
+       cp_grant_id_t etp_stat_gid;
+       eth_stat_t *etp_stat_buf;
 } osdep_eth_port_t;
 
+#define OEPS_INIT              0       /* Not initialized */
+#define OEPS_CONF_SENT         1       /* Conf. request has been sent */
+#define OEPS_IDLE              2       /* Device is ready to accept requests */
+#define OEPS_RECV_SENT         3       /* Recv. request has been sent */
+#define OEPS_SEND_SENT         4       /* Send request has been sent */
+#define OEPS_GETSTAT_SENT      5       /* GETSTAT request has been sent */
+
+#define OEPF_EMPTY     0
+#define OEPF_NEED_RECV 1       /* Issue recv. request when the state becomes
+                                * idle
+                                */
+#define OEPF_NEED_SEND 2       /* Issue send request when the state becomes
+                                * idle
+                                */
+#define OEPF_NEED_CONF 4       /* Issue conf request when the state becomes
+                                * idle
+                                */
+#define OEPF_NEED_STAT 8       /* Issue getstat request when the state becomes
+                                * idle
+                                */
+
 #endif /* INET__OSDEP_ETH_H */
 
 /*