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.
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;
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;
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" ));
}
}
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
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;
#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;
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);
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 */
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,
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)
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,
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);