inet: fix state transitions in driver receipt code

This resolves a problem with ioctl(NIOCGETHSTAT) hanging forever
as identified by Erik van der Kouwe, and possibly many other corner
cases.

Change-Id: I2350c882dc6a0862e16454ec6b6c320d78780bcd
This commit is contained in:
David van Moolenbroek 2015-07-17 18:44:39 +00:00
parent 86e41e22cf
commit 85fb986ba7

View file

@ -177,14 +177,9 @@ acc_t *pack;
void eth_rec(message *m) void eth_rec(message *m)
{ {
int i, r, m_type, flags; int i, r, flags;
eth_port_t *loc_port, *vlan_port; eth_port_t *loc_port, *vlan_port;
m_type= m->m_type;
assert(m_type == DL_CONF_REPLY || m_type == DL_TASK_REPLY ||
m_type == DL_STAT_REPLY);
for (i=0, loc_port= eth_port_table; i<eth_conf_nr; i++, loc_port++) for (i=0, loc_port= eth_port_table; i<eth_conf_nr; i++, loc_port++)
{ {
if (loc_port->etp_osdep.etp_task == m->m_source) if (loc_port->etp_osdep.etp_task == m->m_source)
@ -193,28 +188,16 @@ void eth_rec(message *m)
if (i >= eth_conf_nr) if (i >= eth_conf_nr)
{ {
printf("eth_rec: message 0x%x from unknown driver %d\n", printf("eth_rec: message 0x%x from unknown driver %d\n",
m_type, m->m_source); m->m_type, m->m_source);
return; return;
} }
if (loc_port->etp_osdep.etp_state == OEPS_CONF_SENT) switch (m->m_type) {
{ case DL_CONF_REPLY:
if (m_type == DL_TASK_REPLY) if (loc_port->etp_osdep.etp_state != OEPS_CONF_SENT) {
{ printf("eth_rec: got DL_CONF_REPLY from %d while in "
flags= m->m_netdrv_net_dl_task.flags; "state %d (ignoring)\n", m->m_source,
loc_port->etp_osdep.etp_state);
if (flags & DL_PACK_SEND)
write_int(loc_port);
if (flags & DL_PACK_RECV)
read_int(loc_port, m->m_netdrv_net_dl_task.count);
return;
}
if (m_type != DL_CONF_REPLY)
{
printf(
"eth_rec: got bad message type 0x%x from %d in CONF state\n",
m_type, m->m_source);
return; return;
} }
@ -257,44 +240,17 @@ void eth_rec(message *m)
eth_restart_ioctl(vlan_port); eth_restart_ioctl(vlan_port);
} }
} }
if (!(loc_port->etp_flags & EPF_READ_IP)) if (!(loc_port->etp_flags & EPF_READ_IP))
setup_read (loc_port); loc_port->etp_osdep.etp_flags |= OEPF_NEED_RECV;
#if 0 break;
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");
}
#endif
return; case DL_STAT_REPLY:
} if (loc_port->etp_osdep.etp_state != OEPS_GETSTAT_SENT) {
if (loc_port->etp_osdep.etp_state == OEPS_GETSTAT_SENT) printf("eth_rec: got DL_STAT_REPLY from %d while in "
{ "state %d (ignoring)\n", m->m_source,
if (m_type == DL_TASK_REPLY) loc_port->etp_osdep.etp_state);
{
flags= m->m_netdrv_net_dl_task.flags;
if (flags & DL_PACK_SEND)
write_int(loc_port);
if (flags & DL_PACK_RECV)
read_int(loc_port, m->m_netdrv_net_dl_task.count);
return;
}
if (m_type != DL_STAT_REPLY)
{
printf(
"eth_rec: got bad message type 0x%x from %d in GETSTAT state\n",
m_type, m->m_source);
return; return;
} }
@ -310,43 +266,25 @@ void eth_rec(message *m)
assert(loc_port->etp_flags & EPF_GOT_ADDR); assert(loc_port->etp_flags & EPF_GOT_ADDR);
eth_restart_ioctl(loc_port); eth_restart_ioctl(loc_port);
#if 0 break;
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");
}
#endif
#if 0 case DL_TASK_REPLY:
if (loc_port->etp_osdep.etp_state == OEPS_IDLE && if (loc_port->etp_osdep.etp_state == OEPS_RECV_SENT ||
(loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF)) loc_port->etp_osdep.etp_state == OEPS_SEND_SENT)
{ loc_port->etp_osdep.etp_state= OEPS_IDLE;
eth_set_rec_conf(loc_port,
loc_port->etp_osdep.etp_recvconf); flags= m->m_netdrv_net_dl_task.flags;
}
#endif if (flags & DL_PACK_SEND)
return; write_int(loc_port);
if (flags & DL_PACK_RECV)
read_int(loc_port, m->m_netdrv_net_dl_task.count);
break;
default:
panic("invalid ethernet reply %d", m->m_type);
} }
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;
flags= m->m_netdrv_net_dl_task.flags;
if (flags & DL_PACK_SEND)
write_int(loc_port);
if (flags & DL_PACK_RECV)
read_int(loc_port, m->m_netdrv_net_dl_task.count);
if (loc_port->etp_osdep.etp_state == OEPS_IDLE && 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)
@ -362,11 +300,11 @@ void eth_rec(message *m)
if (!(loc_port->etp_flags & EPF_READ_IP)) if (!(loc_port->etp_flags & EPF_READ_IP))
setup_read (loc_port); setup_read (loc_port);
} }
if (loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF) if (loc_port->etp_osdep.etp_state == OEPS_IDLE &&
(loc_port->etp_osdep.etp_flags & OEPF_NEED_CONF))
{ {
#if 0 eth_set_rec_conf(loc_port,
printf("eth_rec: OEPF_NEED_CONF is set\n"); loc_port->etp_osdep.etp_recvconf);
#endif
} }
if (loc_port->etp_osdep.etp_state == OEPS_IDLE && if (loc_port->etp_osdep.etp_state == OEPS_IDLE &&
(loc_port->etp_osdep.etp_flags & OEPF_NEED_STAT)) (loc_port->etp_osdep.etp_flags & OEPF_NEED_STAT))