]> Zhao Yanbai Git Server - minix.git/commitdiff
Support for starting ethernet driver after inet has been started
authorPhilip Homburg <philip@cs.vu.nl>
Fri, 9 Dec 2005 13:25:30 +0000 (13:25 +0000)
committerPhilip Homburg <philip@cs.vu.nl>
Fri, 9 Dec 2005 13:25:30 +0000 (13:25 +0000)
servers/inet/generic/eth.c
servers/inet/generic/eth_int.h
servers/inet/mnx_eth.c

index a4f6773942ec785d41c66451e174da17c6cf74cc..e1aa97801a51e3a62ad8168706d1ae40dc673646 100644 (file)
@@ -38,15 +38,17 @@ typedef struct eth_fd
        put_pkt_t ef_put_pkt;
        time_t ef_exp_time;
        size_t ef_write_count;
+       ioreq_t ef_ioctl_req;
 } eth_fd_t;
 
 #define EFF_FLAGS      0xf
 #      define EFF_EMPTY        0x0
 #      define EFF_INUSE        0x1
-#      define EFF_BUSY         0x6
+#      define EFF_BUSY         0xE
 #              define  EFF_READ_IP     0x2
 #              define  EFF_WRITE_IP    0x4
-#      define EFF_OPTSET       0x8
+#              define  EFF_IOCTL_IP    0x8
+#      define EFF_OPTSET       0x10
 
 /* Note that the vh_type field is normally considered part of the ethernet
  * header.
@@ -335,6 +337,17 @@ ioreq_t req;
                        acc= bf_memreq(sizeof(nwio_ethstat_t));
                        compare (bf_bufsize(acc), ==, sizeof(*ethstat));
 
+                       if (!(eth_port->etp_flags & EPF_GOT_ADDR))
+                       {
+                               printf(
+                               "eth_ioctl: suspending NWIOGETHSTAT ioctl\n");
+
+                               eth_fd->ef_ioctl_req= req;
+                               assert(!(eth_fd->ef_flags & EFF_IOCTL_IP));
+                               eth_fd->ef_flags |= EFF_IOCTL_IP;
+                               return NW_SUSPEND;
+                       }
+
                        ethstat= (nwio_ethstat_t *)ptr2acc_data(acc);
                        ethstat->nwes_addr= eth_port->etp_ethaddr;
 
@@ -481,6 +494,13 @@ size_t data_len;
        if (nweo_flags & NWEO_REMSPEC)
                eth_hdr->eh_dst= eth_fd->ef_ethopt.nweo_rem;
 
+       if (!(eth_port->etp_flags & EPF_GOT_ADDR))
+       {
+               /* No device, discard packet */
+               bf_afree(eth_pack);
+               return NW_OK;
+       }
+
        if (!(nweo_flags & NWEO_EN_PROMISC))
                eth_hdr->eh_src= eth_port->etp_ethaddr;
 
@@ -569,6 +589,11 @@ int which_operation;
                eth_fd->ef_flags &= ~EFF_WRITE_IP;
                reply_thr_get(eth_fd, EINTR, FALSE);
                break;
+       case SR_CANCEL_IOCTL:
+               assert (eth_fd->ef_flags & EFF_IOCTL_IP);
+               eth_fd->ef_flags &= ~EFF_IOCTL_IP;
+               reply_thr_get(eth_fd, EINTR, TRUE);
+               break;
        default:
                ip_panic(( "got unknown cancel request" ));
        }
@@ -784,6 +809,7 @@ size_t pack_size;
        }
        else
        {
+               assert(eth_port->etp_flags & EPF_GOT_ADDR);
                if (eth_addrcmp (*dst_addr, eth_port->etp_ethaddr) == 0)
                        pack_stat= NWEO_EN_LOC;
                else
@@ -942,6 +968,28 @@ eth_port_t *vlan_port;
        eth_port->etp_vlan_tab[h]= vlan_port;
 }
 
+PUBLIC void eth_restart_ioctl(eth_port)
+eth_port_t *eth_port;
+{
+       int i;
+       eth_fd_t *eth_fd;
+
+       for (i= 0, eth_fd= eth_fd_table; i<ETH_FD_NR; i++, eth_fd++)
+       {
+               if (!(eth_fd->ef_flags & EFF_INUSE))
+                       continue;
+               if (eth_fd->ef_port != eth_port)
+                       continue;
+               if (!(eth_fd->ef_flags & EFF_IOCTL_IP))
+                       continue;
+               if (eth_fd->ef_ioctl_req != NWIOGETHSTAT)
+                       continue;
+
+               eth_fd->ef_flags &= ~EFF_IOCTL_IP;
+               eth_ioctl(i, eth_fd->ef_ioctl_req);
+       }
+}
+
 PRIVATE void packet2user (eth_fd, pack, exp_time)
 eth_fd_t *eth_fd;
 acc_t *pack;
index d9fc74d90eeef032f1371de9acd49b21efd26d6a..d5a4c28b3c8197b5fd6b1448dbcdb9b7a455afe7 100644 (file)
@@ -38,6 +38,7 @@ typedef struct eth_port
 
 #define EPF_EMPTY       0x0
 #define EPF_ENABLED     0x1
+#define EPF_GOT_ADDR    0x2    /* Got ethernet address from device */
 #define EPF_READ_IP    0x20
 #define EPF_READ_SP    0x40
 
@@ -53,6 +54,7 @@ void eth_set_rec_conf ARGS(( eth_port_t *eth_port, u32_t flags ));
 void eth_restart_write ARGS(( eth_port_t *eth_port ));
 void eth_loop_ev ARGS(( event_t *ev, ev_arg_t ev_arg ));
 void eth_reg_vlan ARGS(( eth_port_t *eth_port, eth_port_t *vlan_port ));
+void eth_restart_ioctl ARGS(( eth_port_t *eth_port ));
 
 #endif /* ETH_INT_H */
 
index e76f890af23c0846b4c7e34e521903530fd8cca6..50dbb7de6652dbfd9ff4fed13faac2b11d363167 100644 (file)
@@ -50,9 +50,13 @@ PUBLIC void osdep_eth_init()
 #endif 
                if (r != OK)
                {
+                       /* Eventually, we expect ethernet drivers to be
+                        * started after INET. So we always end up here. And
+                        * the findproc can be removed.
+                        */
                        printf("eth%d: unable to find task %s: %d\n",
                                i, ecp->ec_task, r);
-                       continue;
+                       tasknr= ANY;
                }
 
                eth_port->etp_osdep.etp_port= ecp->ec_port;
@@ -64,45 +68,55 @@ PUBLIC void osdep_eth_init()
                mess.DL_PROC= this_proc;
                mess.DL_MODE= DL_NOMODE;
 
-               r= send(eth_port->etp_osdep.etp_task, &mess);
-               if (r<0)
+               if (tasknr == ANY)
+                       r= ENXIO;
+               else
                {
-                       printf(
+                       r= send(eth_port->etp_osdep.etp_task, &mess);
+                       if (r<0)
+                       {
+                               printf(
                "osdep_eth_init: unable to send to ethernet task, error= %d\n",
-                               r);
-                       continue;
+                                       r);
+                       }
                }
 
-               r= receive(eth_port->etp_osdep.etp_task, &mess);
-               if (r<0)
+               if (r == OK)
                {
-                       printf(
+                       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);
-                       continue;
+                                       r);
+                       }
                }
 
-               if (mess.m3_i1 == ENXIO)
+               if (r == OK)
                {
-                       printf(
+                       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);
-                       continue;
-               }
-               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((
+                                       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));
+                                       mess.m3_i1,
+                                       eth_port->etp_osdep.etp_port));
+                       }
                }
-
-               eth_port->etp_ethaddr= *(ether_addr_t *)mess.m3_ca1;
-
+                       
                sr_add_minor(if2minor(ecp->ec_ifno, ETH_DEV_OFF),
                        i, eth_open, eth_close, eth_read, 
                        eth_write, eth_ioctl, eth_cancel, eth_select);
@@ -112,7 +126,12 @@ PUBLIC void osdep_eth_init()
                eth_port->etp_vlan_port= NULL;
                eth_port->etp_wr_pack= 0;
                eth_port->etp_rd_pack= 0;
-               setup_read (eth_port);
+               if (r == OK)
+               {
+                       eth_port->etp_ethaddr= *(ether_addr_t *)mess.m3_ca1;
+                       eth_port->etp_flags |= EPF_GOT_ADDR;
+                       setup_read (eth_port);
+               }
        }
 
        /* And now come the VLANs */
@@ -144,7 +163,11 @@ PUBLIC void osdep_eth_init()
                        continue;
                }
                
-               eth_port->etp_ethaddr= rep->etp_ethaddr;
+               if (rep->etp_flags & EPF_GOT_ADDR)
+               {
+                       eth_port->etp_ethaddr= rep->etp_ethaddr;
+                       eth_port->etp_flags |= EPF_GOT_ADDR;
+               }
 
                sr_add_minor(if2minor(ecp->ec_ifno, ETH_DEV_OFF),
                        i, eth_open, eth_close, eth_read, 
@@ -454,6 +477,13 @@ u32_t flags;
 
        assert(!eth_port->etp_vlan);
 
+       if (!(eth_port->etp_flags & EPF_GOT_ADDR))
+       {
+               /* We have never seen the device. */
+               printf("eth_set_rec_conf: waiting for device to appear\n");
+               return;
+       }
+
        eth_port->etp_osdep.etp_recvconf= flags;
        dl_flags= DL_NOMODE;
        if (flags & NWEO_EN_BROAD)
@@ -746,14 +776,10 @@ static void eth_restart(eth_port, tasknr)
 eth_port_t *eth_port;
 int tasknr;
 {
-       int r;
+       int i, r;
        unsigned flags, dl_flags;
        message mess;
-#if 0
-       int i, r, rport;
-       struct eth_conf *ecp;
-       eth_port_t *rep;
-#endif
+       eth_port_t *loc_port;
 
        printf("eth_restart: restarting eth%d, task %d, port %d\n",
                eth_port-eth_port_table, tasknr,
@@ -803,9 +829,29 @@ int tasknr;
                        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_flags |= EPF_ENABLED;
        if (eth_port->etp_wr_pack)
        {
                bf_afree(eth_port->etp_wr_pack);