00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 FILE_LICENCE ( GPL2_OR_LATER );
00026
00027 #include <stdint.h>
00028 #include <stdio.h>
00029 #include <string.h>
00030 #include <byteswap.h>
00031 #include <basemem_packet.h>
00032 #include <gpxe/netdevice.h>
00033 #include <gpxe/iobuf.h>
00034 #include <gpxe/device.h>
00035 #include <gpxe/pci.h>
00036 #include <gpxe/if_ether.h>
00037 #include <gpxe/ip.h>
00038 #include <gpxe/arp.h>
00039 #include <gpxe/rarp.h>
00040 #include "pxe.h"
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 static int undi_tx_count = 0;
00052
00053 struct net_device *pxe_netdev = NULL;
00054
00055
00056
00057
00058
00059
00060 void pxe_set_netdev ( struct net_device *netdev ) {
00061 if ( pxe_netdev )
00062 netdev_put ( pxe_netdev );
00063 pxe_netdev = NULL;
00064 if ( netdev )
00065 pxe_netdev = netdev_get ( netdev );
00066 }
00067
00068
00069
00070
00071
00072
00073 static int pxe_netdev_open ( void ) {
00074 int rc;
00075
00076 if ( ( rc = netdev_open ( pxe_netdev ) ) != 0 )
00077 return rc;
00078
00079 netdev_irq ( pxe_netdev, 1 );
00080 return 0;
00081 }
00082
00083
00084
00085
00086
00087 static void pxe_netdev_close ( void ) {
00088 netdev_irq ( pxe_netdev, 0 );
00089 netdev_close ( pxe_netdev );
00090 undi_tx_count = 0;
00091 }
00092
00093
00094
00095
00096
00097
00098 static void pxe_dump_mcast_list ( struct s_PXENV_UNDI_MCAST_ADDRESS *mcast ) {
00099 struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
00100 unsigned int i;
00101
00102 for ( i = 0 ; i < mcast->MCastAddrCount ; i++ ) {
00103 DBG ( " %s", ll_protocol->ntoa ( mcast->McastAddr[i] ) );
00104 }
00105 }
00106
00107
00108
00109
00110
00111 PXENV_EXIT_t pxenv_undi_startup ( struct s_PXENV_UNDI_STARTUP *undi_startup ) {
00112 DBG ( "PXENV_UNDI_STARTUP\n" );
00113
00114 undi_startup->Status = PXENV_STATUS_SUCCESS;
00115 return PXENV_EXIT_SUCCESS;
00116 }
00117
00118
00119
00120
00121
00122 PXENV_EXIT_t pxenv_undi_cleanup ( struct s_PXENV_UNDI_CLEANUP *undi_cleanup ) {
00123 DBG ( "PXENV_UNDI_CLEANUP\n" );
00124
00125 pxe_netdev_close();
00126
00127 undi_cleanup->Status = PXENV_STATUS_SUCCESS;
00128 return PXENV_EXIT_SUCCESS;
00129 }
00130
00131
00132
00133
00134
00135 PXENV_EXIT_t pxenv_undi_initialize ( struct s_PXENV_UNDI_INITIALIZE
00136 *undi_initialize ) {
00137 DBG ( "PXENV_UNDI_INITIALIZE protocolini %08x\n",
00138 undi_initialize->ProtocolIni );
00139
00140 undi_initialize->Status = PXENV_STATUS_SUCCESS;
00141 return PXENV_EXIT_SUCCESS;
00142 }
00143
00144
00145
00146
00147
00148 PXENV_EXIT_t pxenv_undi_reset_adapter ( struct s_PXENV_UNDI_RESET
00149 *undi_reset_adapter ) {
00150 int rc;
00151
00152 DBG ( "PXENV_UNDI_RESET_ADAPTER" );
00153 pxe_dump_mcast_list ( &undi_reset_adapter->R_Mcast_Buf );
00154 DBG ( "\n" );
00155
00156 pxe_netdev_close();
00157 if ( ( rc = pxe_netdev_open() ) != 0 ) {
00158 DBG ( "PXENV_UNDI_RESET_ADAPTER could not reopen %s: %s\n",
00159 pxe_netdev->name, strerror ( rc ) );
00160 undi_reset_adapter->Status = PXENV_STATUS ( rc );
00161 return PXENV_EXIT_FAILURE;
00162 }
00163
00164 undi_reset_adapter->Status = PXENV_STATUS_SUCCESS;
00165 return PXENV_EXIT_SUCCESS;
00166 }
00167
00168
00169
00170
00171
00172 PXENV_EXIT_t pxenv_undi_shutdown ( struct s_PXENV_UNDI_SHUTDOWN
00173 *undi_shutdown ) {
00174 DBG ( "PXENV_UNDI_SHUTDOWN\n" );
00175
00176 pxe_netdev_close();
00177
00178 undi_shutdown->Status = PXENV_STATUS_SUCCESS;
00179 return PXENV_EXIT_SUCCESS;
00180 }
00181
00182
00183
00184
00185
00186 PXENV_EXIT_t pxenv_undi_open ( struct s_PXENV_UNDI_OPEN *undi_open ) {
00187 int rc;
00188
00189 DBG ( "PXENV_UNDI_OPEN flag %04x filter %04x",
00190 undi_open->OpenFlag, undi_open->PktFilter );
00191 pxe_dump_mcast_list ( &undi_open->R_Mcast_Buf );
00192 DBG ( "\n" );
00193
00194 if ( ( rc = pxe_netdev_open() ) != 0 ) {
00195 DBG ( "PXENV_UNDI_OPEN could not open %s: %s\n",
00196 pxe_netdev->name, strerror ( rc ) );
00197 undi_open->Status = PXENV_STATUS ( rc );
00198 return PXENV_EXIT_FAILURE;
00199 }
00200
00201 undi_open->Status = PXENV_STATUS_SUCCESS;
00202 return PXENV_EXIT_SUCCESS;
00203 }
00204
00205
00206
00207
00208
00209 PXENV_EXIT_t pxenv_undi_close ( struct s_PXENV_UNDI_CLOSE *undi_close ) {
00210 DBG ( "PXENV_UNDI_CLOSE\n" );
00211
00212 pxe_netdev_close();
00213
00214 undi_close->Status = PXENV_STATUS_SUCCESS;
00215 return PXENV_EXIT_SUCCESS;
00216 }
00217
00218
00219
00220
00221
00222 PXENV_EXIT_t pxenv_undi_transmit ( struct s_PXENV_UNDI_TRANSMIT
00223 *undi_transmit ) {
00224 struct s_PXENV_UNDI_TBD tbd;
00225 struct DataBlk *datablk;
00226 struct io_buffer *iobuf;
00227 struct net_protocol *net_protocol;
00228 struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
00229 char destaddr[MAX_LL_ADDR_LEN];
00230 const void *ll_dest;
00231 size_t ll_hlen = ll_protocol->ll_header_len;
00232 size_t len;
00233 unsigned int i;
00234 int rc;
00235
00236 DBG2 ( "PXENV_UNDI_TRANSMIT" );
00237
00238
00239
00240
00241
00242 netdev_irq ( pxe_netdev, 1 );
00243
00244
00245 switch ( undi_transmit->Protocol ) {
00246 case P_IP: net_protocol = &ipv4_protocol; break;
00247 case P_ARP: net_protocol = &arp_protocol; break;
00248 case P_RARP: net_protocol = &rarp_protocol; break;
00249 case P_UNKNOWN:
00250 net_protocol = NULL;
00251 ll_hlen = 0;
00252 break;
00253 default:
00254 DBG2 ( " %02x invalid protocol\n", undi_transmit->Protocol );
00255 undi_transmit->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
00256 return PXENV_EXIT_FAILURE;
00257 }
00258 DBG2 ( " %s", ( net_protocol ? net_protocol->name : "RAW" ) );
00259
00260
00261 copy_from_real ( &tbd, undi_transmit->TBD.segment,
00262 undi_transmit->TBD.offset, sizeof ( tbd ) );
00263 len = tbd.ImmedLength;
00264 DBG2 ( " %04x:%04x+%x", tbd.Xmit.segment, tbd.Xmit.offset,
00265 tbd.ImmedLength );
00266 for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
00267 datablk = &tbd.DataBlock[i];
00268 len += datablk->TDDataLen;
00269 DBG2 ( " %04x:%04x+%x", datablk->TDDataPtr.segment,
00270 datablk->TDDataPtr.offset, datablk->TDDataLen );
00271 }
00272
00273
00274 iobuf = alloc_iob ( ll_hlen + len );
00275 if ( ! iobuf ) {
00276 DBG2 ( " could not allocate iobuf\n" );
00277 undi_transmit->Status = PXENV_STATUS_OUT_OF_RESOURCES;
00278 return PXENV_EXIT_FAILURE;
00279 }
00280 iob_reserve ( iobuf, ll_hlen );
00281 copy_from_real ( iob_put ( iobuf, tbd.ImmedLength ), tbd.Xmit.segment,
00282 tbd.Xmit.offset, tbd.ImmedLength );
00283 for ( i = 0 ; i < tbd.DataBlkCount ; i++ ) {
00284 datablk = &tbd.DataBlock[i];
00285 copy_from_real ( iob_put ( iobuf, datablk->TDDataLen ),
00286 datablk->TDDataPtr.segment,
00287 datablk->TDDataPtr.offset,
00288 datablk->TDDataLen );
00289 }
00290
00291
00292 if ( net_protocol != NULL ) {
00293
00294
00295 if ( undi_transmit->XmitFlag == XMT_DESTADDR ) {
00296 copy_from_real ( destaddr,
00297 undi_transmit->DestAddr.segment,
00298 undi_transmit->DestAddr.offset,
00299 ll_protocol->ll_addr_len );
00300 ll_dest = destaddr;
00301 DBG2 ( " DEST %s", ll_protocol->ntoa ( ll_dest ) );
00302 } else {
00303 ll_dest = pxe_netdev->ll_broadcast;
00304 DBG2 ( " BCAST" );
00305 }
00306
00307
00308 if ( ( rc = ll_protocol->push ( pxe_netdev, iobuf, ll_dest,
00309 pxe_netdev->ll_addr,
00310 net_protocol->net_proto ))!=0){
00311 DBG2 ( " could not add link-layer header: %s\n",
00312 strerror ( rc ) );
00313 free_iob ( iobuf );
00314 undi_transmit->Status = PXENV_STATUS ( rc );
00315 return PXENV_EXIT_FAILURE;
00316 }
00317 }
00318
00319
00320
00321
00322
00323 undi_tx_count++;
00324
00325
00326 DBG2 ( "\n" );
00327 if ( ( rc = netdev_tx ( pxe_netdev, iobuf ) ) != 0 ) {
00328 DBG2 ( "PXENV_UNDI_TRANSMIT could not transmit: %s\n",
00329 strerror ( rc ) );
00330 undi_tx_count--;
00331 undi_transmit->Status = PXENV_STATUS ( rc );
00332 return PXENV_EXIT_FAILURE;
00333 }
00334
00335 undi_transmit->Status = PXENV_STATUS_SUCCESS;
00336 return PXENV_EXIT_SUCCESS;
00337 }
00338
00339
00340
00341
00342
00343 PXENV_EXIT_t
00344 pxenv_undi_set_mcast_address ( struct s_PXENV_UNDI_SET_MCAST_ADDRESS
00345 *undi_set_mcast_address ) {
00346 DBG ( "PXENV_UNDI_SET_MCAST_ADDRESS" );
00347 pxe_dump_mcast_list ( &undi_set_mcast_address->R_Mcast_Buf );
00348 DBG ( "\n" );
00349
00350 undi_set_mcast_address->Status = PXENV_STATUS_SUCCESS;
00351 return PXENV_EXIT_SUCCESS;
00352 }
00353
00354
00355
00356
00357
00358 PXENV_EXIT_t
00359 pxenv_undi_set_station_address ( struct s_PXENV_UNDI_SET_STATION_ADDRESS
00360 *undi_set_station_address ) {
00361 struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
00362
00363 DBG ( "PXENV_UNDI_SET_STATION_ADDRESS %s",
00364 ll_protocol->ntoa ( undi_set_station_address->StationAddress ) );
00365
00366
00367
00368
00369 if ( netdev_is_open ( pxe_netdev ) ) {
00370 DBG ( " failed: netdev is open\n" );
00371 undi_set_station_address->Status =
00372 PXENV_STATUS_UNDI_INVALID_STATE;
00373 return PXENV_EXIT_FAILURE;
00374 }
00375
00376
00377 memcpy ( pxe_netdev->ll_addr,
00378 &undi_set_station_address->StationAddress,
00379 ll_protocol->ll_addr_len );
00380
00381 DBG ( "\n" );
00382 undi_set_station_address->Status = PXENV_STATUS_SUCCESS;
00383 return PXENV_EXIT_SUCCESS;
00384 }
00385
00386
00387
00388
00389
00390
00391 PXENV_EXIT_t
00392 pxenv_undi_set_packet_filter ( struct s_PXENV_UNDI_SET_PACKET_FILTER
00393 *undi_set_packet_filter ) {
00394
00395 DBG ( "PXENV_UNDI_SET_PACKET_FILTER %02x\n",
00396 undi_set_packet_filter->filter );
00397
00398
00399
00400
00401
00402 undi_set_packet_filter->Status = PXENV_STATUS_SUCCESS;
00403
00404 return PXENV_EXIT_SUCCESS;
00405 }
00406
00407
00408
00409
00410
00411 PXENV_EXIT_t pxenv_undi_get_information ( struct s_PXENV_UNDI_GET_INFORMATION
00412 *undi_get_information ) {
00413 struct device *dev = pxe_netdev->dev;
00414 struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
00415 size_t ll_addr_len = ll_protocol->ll_addr_len;
00416
00417 DBG ( "PXENV_UNDI_GET_INFORMATION" );
00418
00419 undi_get_information->BaseIo = dev->desc.ioaddr;
00420 undi_get_information->IntNumber = dev->desc.irq;
00421
00422 undi_get_information->MaxTranUnit = ETH_MAX_MTU;
00423 undi_get_information->HwType = ntohs ( ll_protocol->ll_proto );
00424 undi_get_information->HwAddrLen = ll_addr_len;
00425 assert ( ll_addr_len <=
00426 sizeof ( undi_get_information->CurrentNodeAddress ) );
00427 memcpy ( &undi_get_information->CurrentNodeAddress,
00428 pxe_netdev->ll_addr,
00429 sizeof ( undi_get_information->CurrentNodeAddress ) );
00430 ll_protocol->init_addr ( pxe_netdev->hw_addr,
00431 &undi_get_information->PermNodeAddress );
00432 undi_get_information->ROMAddress = 0;
00433
00434
00435
00436
00437 undi_get_information->RxBufCt = 1;
00438 undi_get_information->TxBufCt = 1;
00439
00440 DBG ( " io %04x irq %d mtu %d %s %s\n",
00441 undi_get_information->BaseIo, undi_get_information->IntNumber,
00442 undi_get_information->MaxTranUnit, ll_protocol->name,
00443 ll_protocol->ntoa ( &undi_get_information->CurrentNodeAddress ));
00444 undi_get_information->Status = PXENV_STATUS_SUCCESS;
00445 return PXENV_EXIT_SUCCESS;
00446 }
00447
00448
00449
00450
00451
00452 PXENV_EXIT_t pxenv_undi_get_statistics ( struct s_PXENV_UNDI_GET_STATISTICS
00453 *undi_get_statistics ) {
00454 DBG ( "PXENV_UNDI_GET_STATISTICS" );
00455
00456 undi_get_statistics->XmtGoodFrames = pxe_netdev->tx_stats.good;
00457 undi_get_statistics->RcvGoodFrames = pxe_netdev->rx_stats.good;
00458 undi_get_statistics->RcvCRCErrors = pxe_netdev->rx_stats.bad;
00459 undi_get_statistics->RcvResourceErrors = pxe_netdev->rx_stats.bad;
00460
00461 DBG ( " txok %d rxok %d rxcrc %d rxrsrc %d\n",
00462 undi_get_statistics->XmtGoodFrames,
00463 undi_get_statistics->RcvGoodFrames,
00464 undi_get_statistics->RcvCRCErrors,
00465 undi_get_statistics->RcvResourceErrors );
00466 undi_get_statistics->Status = PXENV_STATUS_SUCCESS;
00467 return PXENV_EXIT_SUCCESS;
00468 }
00469
00470
00471
00472
00473
00474 PXENV_EXIT_t pxenv_undi_clear_statistics ( struct s_PXENV_UNDI_CLEAR_STATISTICS
00475 *undi_clear_statistics ) {
00476 DBG ( "PXENV_UNDI_CLEAR_STATISTICS\n" );
00477
00478 memset ( &pxe_netdev->tx_stats, 0, sizeof ( pxe_netdev->tx_stats ) );
00479 memset ( &pxe_netdev->rx_stats, 0, sizeof ( pxe_netdev->rx_stats ) );
00480
00481 undi_clear_statistics->Status = PXENV_STATUS_SUCCESS;
00482 return PXENV_EXIT_SUCCESS;
00483 }
00484
00485
00486
00487
00488
00489
00490 PXENV_EXIT_t pxenv_undi_initiate_diags ( struct s_PXENV_UNDI_INITIATE_DIAGS
00491 *undi_initiate_diags ) {
00492 DBG ( "PXENV_UNDI_INITIATE_DIAGS failed: unsupported\n" );
00493
00494 undi_initiate_diags->Status = PXENV_STATUS_UNSUPPORTED;
00495 return PXENV_EXIT_FAILURE;
00496 }
00497
00498
00499
00500
00501
00502
00503 PXENV_EXIT_t pxenv_undi_force_interrupt ( struct s_PXENV_UNDI_FORCE_INTERRUPT
00504 *undi_force_interrupt ) {
00505 DBG ( "PXENV_UNDI_FORCE_INTERRUPT failed: unsupported\n" );
00506
00507 undi_force_interrupt->Status = PXENV_STATUS_UNSUPPORTED;
00508 return PXENV_EXIT_FAILURE;
00509 }
00510
00511
00512
00513
00514
00515 PXENV_EXIT_t
00516 pxenv_undi_get_mcast_address ( struct s_PXENV_UNDI_GET_MCAST_ADDRESS
00517 *undi_get_mcast_address ) {
00518 struct ll_protocol *ll_protocol = pxe_netdev->ll_protocol;
00519 struct in_addr ip = { .s_addr = undi_get_mcast_address->InetAddr };
00520 int rc;
00521
00522 DBG ( "PXENV_UNDI_GET_MCAST_ADDRESS %s", inet_ntoa ( ip ) );
00523
00524 if ( ( rc = ll_protocol->mc_hash ( AF_INET, &ip,
00525 undi_get_mcast_address->MediaAddr ))!=0){
00526 DBG ( " failed: %s\n", strerror ( rc ) );
00527 undi_get_mcast_address->Status = PXENV_STATUS ( rc );
00528 return PXENV_EXIT_FAILURE;
00529 }
00530 DBG ( "=>%s\n",
00531 ll_protocol->ntoa ( undi_get_mcast_address->MediaAddr ) );
00532
00533 undi_get_mcast_address->Status = PXENV_STATUS_SUCCESS;
00534 return PXENV_EXIT_SUCCESS;
00535 }
00536
00537
00538
00539
00540
00541 PXENV_EXIT_t pxenv_undi_get_nic_type ( struct s_PXENV_UNDI_GET_NIC_TYPE
00542 *undi_get_nic_type ) {
00543 struct device *dev = pxe_netdev->dev;
00544
00545 DBG ( "PXENV_UNDI_GET_NIC_TYPE" );
00546
00547 memset ( &undi_get_nic_type->info, 0,
00548 sizeof ( undi_get_nic_type->info ) );
00549
00550 switch ( dev->desc.bus_type ) {
00551 case BUS_TYPE_PCI: {
00552 struct pci_nic_info *info = &undi_get_nic_type->info.pci;
00553
00554 undi_get_nic_type->NicType = PCI_NIC;
00555 info->Vendor_ID = dev->desc.vendor;
00556 info->Dev_ID = dev->desc.device;
00557 info->Base_Class = PCI_BASE_CLASS ( dev->desc.class );
00558 info->Sub_Class = PCI_SUB_CLASS ( dev->desc.class );
00559 info->Prog_Intf = PCI_PROG_INTF ( dev->desc.class );
00560 info->BusDevFunc = dev->desc.location;
00561
00562
00563
00564 undi_get_nic_type->info.pci.SubVendor_ID = 0xffff;
00565 undi_get_nic_type->info.pci.SubDevice_ID = 0xffff;
00566 DBG ( " PCI %02x:%02x.%x %04x:%04x (%04x:%04x) %02x%02x%02x "
00567 "rev %02x\n", PCI_BUS ( info->BusDevFunc ),
00568 PCI_SLOT ( info->BusDevFunc ),
00569 PCI_FUNC ( info->BusDevFunc ), info->Vendor_ID,
00570 info->Dev_ID, info->SubVendor_ID, info->SubDevice_ID,
00571 info->Base_Class, info->Sub_Class, info->Prog_Intf,
00572 info->Rev );
00573 break; }
00574 case BUS_TYPE_ISAPNP: {
00575 struct pnp_nic_info *info = &undi_get_nic_type->info.pnp;
00576
00577 undi_get_nic_type->NicType = PnP_NIC;
00578 info->EISA_Dev_ID = ( ( dev->desc.vendor << 16 ) |
00579 dev->desc.device );
00580 info->CardSelNum = dev->desc.location;
00581
00582
00583
00584 DBG ( " ISAPnP CSN %04x %08x %02x%02x%02x\n",
00585 info->CardSelNum, info->EISA_Dev_ID,
00586 info->Base_Class, info->Sub_Class, info->Prog_Intf );
00587 break; }
00588 default:
00589 DBG ( " failed: unknown bus type\n" );
00590 undi_get_nic_type->Status = PXENV_STATUS_FAILURE;
00591 return PXENV_EXIT_FAILURE;
00592 }
00593
00594 undi_get_nic_type->Status = PXENV_STATUS_SUCCESS;
00595 return PXENV_EXIT_SUCCESS;
00596 }
00597
00598
00599
00600
00601
00602 PXENV_EXIT_t pxenv_undi_get_iface_info ( struct s_PXENV_UNDI_GET_IFACE_INFO
00603 *undi_get_iface_info ) {
00604 DBG ( "PXENV_UNDI_GET_IFACE_INFO" );
00605
00606
00607
00608
00609 snprintf ( ( char * ) undi_get_iface_info->IfaceType,
00610 sizeof ( undi_get_iface_info->IfaceType ), "DIX+802.3" );
00611 undi_get_iface_info->LinkSpeed = 10000000;
00612 undi_get_iface_info->ServiceFlags =
00613 ( SUPPORTED_BROADCAST | SUPPORTED_MULTICAST |
00614 SUPPORTED_SET_STATION_ADDRESS | SUPPORTED_RESET |
00615 SUPPORTED_OPEN_CLOSE | SUPPORTED_IRQ );
00616 memset ( undi_get_iface_info->Reserved, 0,
00617 sizeof(undi_get_iface_info->Reserved) );
00618
00619 DBG ( " %s %dbps flags %08x\n", undi_get_iface_info->IfaceType,
00620 undi_get_iface_info->LinkSpeed,
00621 undi_get_iface_info->ServiceFlags );
00622 undi_get_iface_info->Status = PXENV_STATUS_SUCCESS;
00623 return PXENV_EXIT_SUCCESS;
00624 }
00625
00626
00627
00628
00629
00630 PXENV_EXIT_t pxenv_undi_get_state ( struct s_PXENV_UNDI_GET_STATE
00631 *undi_get_state ) {
00632 DBG ( "PXENV_UNDI_GET_STATE failed: unsupported\n" );
00633
00634 undi_get_state->Status = PXENV_STATUS_UNSUPPORTED;
00635 return PXENV_EXIT_FAILURE;
00636 };
00637
00638
00639
00640
00641
00642 PXENV_EXIT_t pxenv_undi_isr ( struct s_PXENV_UNDI_ISR *undi_isr ) {
00643 struct io_buffer *iobuf;
00644 size_t len;
00645 struct ll_protocol *ll_protocol;
00646 const void *ll_dest;
00647 const void *ll_source;
00648 uint16_t net_proto;
00649 size_t ll_hlen;
00650 struct net_protocol *net_protocol;
00651 unsigned int prottype;
00652 int rc;
00653
00654
00655
00656
00657 DBGC2 ( &pxenv_undi_isr, "PXENV_UNDI_ISR" );
00658
00659
00660
00661
00662 undi_isr->BufferLength = 0;
00663 undi_isr->FrameLength = 0;
00664 undi_isr->FrameHeaderLength = 0;
00665 undi_isr->ProtType = 0;
00666 undi_isr->PktType = 0;
00667
00668 switch ( undi_isr->FuncFlag ) {
00669 case PXENV_UNDI_ISR_IN_START :
00670 DBGC2 ( &pxenv_undi_isr, " START" );
00671
00672
00673
00674
00675 netdev_poll ( pxe_netdev );
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689 if ( netdev_irq_enabled ( pxe_netdev ) ) {
00690 DBGC2 ( &pxenv_undi_isr, " OURS" );
00691 undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_OURS;
00692 } else {
00693 DBGC2 ( &pxenv_undi_isr, " NOT OURS" );
00694 undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_NOT_OURS;
00695 }
00696
00697
00698 netdev_irq ( pxe_netdev, 0 );
00699
00700 break;
00701 case PXENV_UNDI_ISR_IN_PROCESS :
00702 case PXENV_UNDI_ISR_IN_GET_NEXT :
00703 DBGC2 ( &pxenv_undi_isr, " %s",
00704 ( ( undi_isr->FuncFlag == PXENV_UNDI_ISR_IN_PROCESS ) ?
00705 "PROCESS" : "GET_NEXT" ) );
00706
00707
00708
00709
00710
00711
00712
00713
00714 netdev_poll ( pxe_netdev );
00715
00716
00717
00718
00719 if ( undi_tx_count && list_empty ( &pxe_netdev->tx_queue ) ) {
00720 DBGC2 ( &pxenv_undi_isr, " TXC" );
00721 undi_tx_count--;
00722 undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_TRANSMIT;
00723 break;
00724 }
00725
00726
00727 iobuf = netdev_rx_dequeue ( pxe_netdev );
00728 if ( ! iobuf ) {
00729 DBGC2 ( &pxenv_undi_isr, " DONE" );
00730
00731 undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
00732
00733 netdev_irq ( pxe_netdev, 1 );
00734 break;
00735 }
00736
00737
00738 len = iob_len ( iobuf );
00739 DBGC2 ( &pxenv_undi_isr, " RX" );
00740 if ( len > sizeof ( basemem_packet ) ) {
00741
00742 DBGC2 ( &pxenv_undi_isr, " overlength (%zx)", len );
00743 len = sizeof ( basemem_packet );
00744 }
00745 memcpy ( basemem_packet, iobuf->data, len );
00746
00747
00748 ll_protocol = pxe_netdev->ll_protocol;
00749 if ( ( rc = ll_protocol->pull ( pxe_netdev, iobuf, &ll_dest,
00750 &ll_source, &net_proto )) !=0){
00751
00752 net_proto = 0;
00753 ll_source = NULL;
00754 }
00755 ll_hlen = ( len - iob_len ( iobuf ) );
00756
00757
00758 switch ( net_proto ) {
00759 case htons ( ETH_P_IP ):
00760 net_protocol = &ipv4_protocol;
00761 prottype = P_IP;
00762 break;
00763 case htons ( ETH_P_ARP ):
00764 net_protocol = &arp_protocol;
00765 prottype = P_ARP;
00766 break;
00767 case htons ( ETH_P_RARP ):
00768 net_protocol = &rarp_protocol;
00769 prottype = P_RARP;
00770 break;
00771 default:
00772 net_protocol = NULL;
00773 prottype = P_UNKNOWN;
00774 break;
00775 }
00776
00777
00778 undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_RECEIVE;
00779 undi_isr->BufferLength = len;
00780 undi_isr->FrameLength = len;
00781 undi_isr->FrameHeaderLength = ll_hlen;
00782 undi_isr->Frame.segment = rm_ds;
00783 undi_isr->Frame.offset = __from_data16 ( basemem_packet );
00784 undi_isr->ProtType = prottype;
00785 undi_isr->PktType = XMT_DESTADDR;
00786 DBGC2 ( &pxenv_undi_isr, " %04x:%04x+%x(%x) %s hlen %d",
00787 undi_isr->Frame.segment, undi_isr->Frame.offset,
00788 undi_isr->BufferLength, undi_isr->FrameLength,
00789 ( net_protocol ? net_protocol->name : "RAW" ),
00790 undi_isr->FrameHeaderLength );
00791
00792
00793 free_iob ( iobuf );
00794 break;
00795 default :
00796 DBGC2 ( &pxenv_undi_isr, " INVALID(%04x)\n",
00797 undi_isr->FuncFlag );
00798
00799
00800 undi_isr->FuncFlag = PXENV_UNDI_ISR_OUT_DONE;
00801 undi_isr->Status = PXENV_STATUS_UNDI_INVALID_PARAMETER;
00802 return PXENV_EXIT_FAILURE;
00803 }
00804
00805 DBGC2 ( &pxenv_undi_isr, "\n" );
00806 undi_isr->Status = PXENV_STATUS_SUCCESS;
00807 return PXENV_EXIT_SUCCESS;
00808 }