Browse Source

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.
tags/v0.9.3
Michael Brown 17 years ago
parent
commit
2ac7694c3e
1 changed files with 21 additions and 6 deletions
  1. 21
    6
      src/arch/i386/drivers/net/undinet.c

+ 21
- 6
src/arch/i386/drivers/net/undinet.c View File

@@ -418,6 +418,7 @@ static void undinet_poll ( struct net_device *netdev ) {
418 418
 	struct io_buffer *iobuf = NULL;
419 419
 	size_t len;
420 420
 	size_t frag_len;
421
+	size_t max_frag_len;
421 422
 	int rc;
422 423
 
423 424
 	if ( ! undinic->isr_processing ) {
@@ -446,6 +447,14 @@ static void undinet_poll ( struct net_device *netdev ) {
446 447
 			/* Packet fragment received */
447 448
 			len = undi_isr.FrameLength;
448 449
 			frag_len = undi_isr.BufferLength;
450
+			if ( ( len == 0 ) || ( len < frag_len ) ) {
451
+				/* Don't laugh.  VMWare does it. */
452
+				DBGC ( undinic, "UNDINIC %p reported insane "
453
+				       "fragment (%zd of %zd bytes)\n",
454
+				       undinic, frag_len, len );
455
+				netdev_rx_err ( netdev, NULL, -EINVAL );
456
+				break;
457
+			}
449 458
 			if ( ! iobuf )
450 459
 				iobuf = alloc_iob ( len );
451 460
 			if ( ! iobuf ) {
@@ -456,10 +465,13 @@ static void undinet_poll ( struct net_device *netdev ) {
456 465
 				netdev_rx_err ( netdev, NULL, -ENOMEM );
457 466
 				goto done;
458 467
 			}
459
-			if ( frag_len > iob_tailroom ( iobuf ) ) {
460
-				DBGC ( undinic, "UNDINIC %p fragment too "
461
-				       "large\n", undinic );
462
-				frag_len = iob_tailroom ( iobuf );
468
+			max_frag_len = iob_tailroom ( iobuf );
469
+			if ( frag_len > max_frag_len ) {
470
+				DBGC ( undinic, "UNDINIC %p fragment too big "
471
+				       "(%zd+%zd does not fit into %zd)\n",
472
+				       undinic, iob_len ( iobuf ), frag_len,
473
+				       ( iob_len ( iobuf ) + max_frag_len ) );
474
+				frag_len = max_frag_len;
463 475
 			}
464 476
 			copy_from_real ( iob_put ( iobuf, frag_len ),
465 477
 					 undi_isr.Frame.segment,
@@ -473,6 +485,8 @@ static void undinet_poll ( struct net_device *netdev ) {
473 485
 				 */
474 486
 				if ( undinic->hacks & UNDI_HACK_EB54 )
475 487
 					--last_trigger_count;
488
+				/** HACK: effective RX quota of 1 */
489
+				goto done;
476 490
 			}
477 491
 			break;
478 492
 		case PXENV_UNDI_ISR_OUT_DONE:
@@ -491,8 +505,9 @@ static void undinet_poll ( struct net_device *netdev ) {
491 505
 
492 506
  done:
493 507
 	if ( iobuf ) {
494
-		DBGC ( undinic, "UNDINIC %p returned incomplete packet\n",
495
-		       undinic );
508
+		DBGC ( undinic, "UNDINIC %p returned incomplete packet "
509
+		       "(%zd of %zd)\n", undinic, iob_len ( iobuf ),
510
+		       ( iob_len ( iobuf ) + iob_tailroom ( iobuf ) ) );
496 511
 		netdev_rx_err ( netdev, iobuf, -EINVAL );
497 512
 	}
498 513
 }

Loading…
Cancel
Save