summaryrefslogtreecommitdiffstats
path: root/src/arch/i386/drivers/net/undinet.c
diff options
context:
space:
mode:
authorMichael Brown2007-07-10 21:59:21 +0200
committerMichael Brown2007-07-10 21:59:21 +0200
commit2ac7694c3e0a2b9915a87d62618969f899fc175e (patch)
treede6d96fcf5961d5be854a8e2b9519623e605c9cf /src/arch/i386/drivers/net/undinet.c
parentSet up %ds *before* testing a value in our data segment (d'oh!). (diff)
downloadipxe-2ac7694c3e0a2b9915a87d62618969f899fc175e.tar.gz
ipxe-2ac7694c3e0a2b9915a87d62618969f899fc175e.tar.xz
ipxe-2ac7694c3e0a2b9915a87d62618969f899fc175e.zip
Improve error reporting for strange length combinations reported by
the UNDI stack. Ignore obviously invalid length combinations (as returned by e.g. VMWare's PXE stack). Limit to one packet per poll to avoid memory exhaustion.
Diffstat (limited to 'src/arch/i386/drivers/net/undinet.c')
-rw-r--r--src/arch/i386/drivers/net/undinet.c27
1 files changed, 21 insertions, 6 deletions
diff --git a/src/arch/i386/drivers/net/undinet.c b/src/arch/i386/drivers/net/undinet.c
index 03515fd5..2a097ff2 100644
--- a/src/arch/i386/drivers/net/undinet.c
+++ b/src/arch/i386/drivers/net/undinet.c
@@ -418,6 +418,7 @@ static void undinet_poll ( struct net_device *netdev ) {
struct io_buffer *iobuf = NULL;
size_t len;
size_t frag_len;
+ size_t max_frag_len;
int rc;
if ( ! undinic->isr_processing ) {
@@ -446,6 +447,14 @@ static void undinet_poll ( struct net_device *netdev ) {
/* Packet fragment received */
len = undi_isr.FrameLength;
frag_len = undi_isr.BufferLength;
+ if ( ( len == 0 ) || ( len < frag_len ) ) {
+ /* Don't laugh. VMWare does it. */
+ DBGC ( undinic, "UNDINIC %p reported insane "
+ "fragment (%zd of %zd bytes)\n",
+ undinic, frag_len, len );
+ netdev_rx_err ( netdev, NULL, -EINVAL );
+ break;
+ }
if ( ! iobuf )
iobuf = alloc_iob ( len );
if ( ! iobuf ) {
@@ -456,10 +465,13 @@ static void undinet_poll ( struct net_device *netdev ) {
netdev_rx_err ( netdev, NULL, -ENOMEM );
goto done;
}
- if ( frag_len > iob_tailroom ( iobuf ) ) {
- DBGC ( undinic, "UNDINIC %p fragment too "
- "large\n", undinic );
- frag_len = iob_tailroom ( iobuf );
+ max_frag_len = iob_tailroom ( iobuf );
+ if ( frag_len > max_frag_len ) {
+ DBGC ( undinic, "UNDINIC %p fragment too big "
+ "(%zd+%zd does not fit into %zd)\n",
+ undinic, iob_len ( iobuf ), frag_len,
+ ( iob_len ( iobuf ) + max_frag_len ) );
+ frag_len = max_frag_len;
}
copy_from_real ( iob_put ( iobuf, frag_len ),
undi_isr.Frame.segment,
@@ -473,6 +485,8 @@ static void undinet_poll ( struct net_device *netdev ) {
*/
if ( undinic->hacks & UNDI_HACK_EB54 )
--last_trigger_count;
+ /** HACK: effective RX quota of 1 */
+ goto done;
}
break;
case PXENV_UNDI_ISR_OUT_DONE:
@@ -491,8 +505,9 @@ static void undinet_poll ( struct net_device *netdev ) {
done:
if ( iobuf ) {
- DBGC ( undinic, "UNDINIC %p returned incomplete packet\n",
- undinic );
+ DBGC ( undinic, "UNDINIC %p returned incomplete packet "
+ "(%zd of %zd)\n", undinic, iob_len ( iobuf ),
+ ( iob_len ( iobuf ) + iob_tailroom ( iobuf ) ) );
netdev_rx_err ( netdev, iobuf, -EINVAL );
}
}