Browse Source

[efi] Expose an UNDI interface alongside the existing SNP interface

UEFI UNDI is a hideously ugly lump of poorly specified garbage bolted
on as an appendix of the UEFI specification.  My personal favourite
line from the UNDI 'specification' is section E.2.2, which states
"Basically, the rule is: Do it right, or don't do it at all".  The
author appears to believe that such exhortations are a viable
substitute for documenting what it is that the wretched reader is
supposed to, in fact, do.

(Second favourite is the section listing the pros and cons of various
driver types.  This fails to identify a single con for the mythical
"Hardware UNDI", a design so insanely intrinsically slow that it
appears to have been the inspiration for the EFI_USB_IO_PROTOCOL.)

UNDI is functionally isomorphic to the substantially less preposterous
EFI_SIMPLE_NETWORK_PROTOCOL.  Provide an UNDI interface (as a thin
wrapper around the existing SNP interface) to allow for use by
third-party software that has made poor life choices.

Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
300a371bfb
1 changed files with 676 additions and 23 deletions
  1. 676
    23
      src/interface/efi/efi_snp.c

+ 676
- 23
src/interface/efi/efi_snp.c View File

183
 	struct efi_snp_device *snpdev =
183
 	struct efi_snp_device *snpdev =
184
 		container_of ( snp, struct efi_snp_device, snp );
184
 		container_of ( snp, struct efi_snp_device, snp );
185
 
185
 
186
-	DBGC2 ( snpdev, "SNPDEV %p START\n", snpdev );
186
+	DBGC ( snpdev, "SNPDEV %p START\n", snpdev );
187
 
187
 
188
 	/* Fail if net device is currently claimed for use by iPXE */
188
 	/* Fail if net device is currently claimed for use by iPXE */
189
 	if ( efi_snp_claimed )
189
 	if ( efi_snp_claimed )
205
 	struct efi_snp_device *snpdev =
205
 	struct efi_snp_device *snpdev =
206
 		container_of ( snp, struct efi_snp_device, snp );
206
 		container_of ( snp, struct efi_snp_device, snp );
207
 
207
 
208
-	DBGC2 ( snpdev, "SNPDEV %p STOP\n", snpdev );
208
+	DBGC ( snpdev, "SNPDEV %p STOP\n", snpdev );
209
 
209
 
210
 	/* Fail if net device is currently claimed for use by iPXE */
210
 	/* Fail if net device is currently claimed for use by iPXE */
211
 	if ( efi_snp_claimed )
211
 	if ( efi_snp_claimed )
213
 
213
 
214
 	snpdev->started = 0;
214
 	snpdev->started = 0;
215
 	efi_snp_set_state ( snpdev );
215
 	efi_snp_set_state ( snpdev );
216
+
216
 	return 0;
217
 	return 0;
217
 }
218
 }
218
 
219
 
231
 		container_of ( snp, struct efi_snp_device, snp );
232
 		container_of ( snp, struct efi_snp_device, snp );
232
 	int rc;
233
 	int rc;
233
 
234
 
234
-	DBGC2 ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
235
-		snpdev, ( ( unsigned long ) extra_rx_bufsize ),
236
-		( ( unsigned long ) extra_tx_bufsize ) );
235
+	DBGC ( snpdev, "SNPDEV %p INITIALIZE (%ld extra RX, %ld extra TX)\n",
236
+	       snpdev, ( ( unsigned long ) extra_rx_bufsize ),
237
+	       ( ( unsigned long ) extra_tx_bufsize ) );
237
 
238
 
238
 	/* Fail if net device is currently claimed for use by iPXE */
239
 	/* Fail if net device is currently claimed for use by iPXE */
239
 	if ( efi_snp_claimed )
240
 	if ( efi_snp_claimed )
262
 		container_of ( snp, struct efi_snp_device, snp );
263
 		container_of ( snp, struct efi_snp_device, snp );
263
 	int rc;
264
 	int rc;
264
 
265
 
265
-	DBGC2 ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
266
-		snpdev, ( ext_verify ? "with" : "without" ) );
266
+	DBGC ( snpdev, "SNPDEV %p RESET (%s extended verification)\n",
267
+	       snpdev, ( ext_verify ? "with" : "without" ) );
267
 
268
 
268
 	/* Fail if net device is currently claimed for use by iPXE */
269
 	/* Fail if net device is currently claimed for use by iPXE */
269
 	if ( efi_snp_claimed )
270
 	if ( efi_snp_claimed )
294
 	struct efi_snp_device *snpdev =
295
 	struct efi_snp_device *snpdev =
295
 		container_of ( snp, struct efi_snp_device, snp );
296
 		container_of ( snp, struct efi_snp_device, snp );
296
 
297
 
297
-	DBGC2 ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
298
+	DBGC ( snpdev, "SNPDEV %p SHUTDOWN\n", snpdev );
298
 
299
 
299
 	/* Fail if net device is currently claimed for use by iPXE */
300
 	/* Fail if net device is currently claimed for use by iPXE */
300
 	if ( efi_snp_claimed )
301
 	if ( efi_snp_claimed )
326
 		container_of ( snp, struct efi_snp_device, snp );
327
 		container_of ( snp, struct efi_snp_device, snp );
327
 	unsigned int i;
328
 	unsigned int i;
328
 
329
 
329
-	DBGC2 ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n",
330
-		snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
331
-		( ( unsigned long ) mcast_count ) );
330
+	DBGC ( snpdev, "SNPDEV %p RECEIVE_FILTERS %08x&~%08x%s %ld mcast\n",
331
+	       snpdev, enable, disable, ( mcast_reset ? " reset" : "" ),
332
+	       ( ( unsigned long ) mcast_count ) );
332
 	for ( i = 0 ; i < mcast_count ; i++ ) {
333
 	for ( i = 0 ; i < mcast_count ; i++ ) {
333
 		DBGC2_HDA ( snpdev, i, &mcast[i],
334
 		DBGC2_HDA ( snpdev, i, &mcast[i],
334
 			    snpdev->netdev->ll_protocol->ll_addr_len );
335
 			    snpdev->netdev->ll_protocol->ll_addr_len );
359
 		container_of ( snp, struct efi_snp_device, snp );
360
 		container_of ( snp, struct efi_snp_device, snp );
360
 	struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
361
 	struct ll_protocol *ll_protocol = snpdev->netdev->ll_protocol;
361
 
362
 
362
-	DBGC2 ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
363
-		( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
363
+	DBGC ( snpdev, "SNPDEV %p STATION_ADDRESS %s\n", snpdev,
364
+	       ( reset ? "reset" : ll_protocol->ntoa ( new ) ) );
364
 
365
 
365
 	/* Fail if net device is currently claimed for use by iPXE */
366
 	/* Fail if net device is currently claimed for use by iPXE */
366
 	if ( efi_snp_claimed )
367
 	if ( efi_snp_claimed )
396
 		container_of ( snp, struct efi_snp_device, snp );
397
 		container_of ( snp, struct efi_snp_device, snp );
397
 	EFI_NETWORK_STATISTICS stats_buf;
398
 	EFI_NETWORK_STATISTICS stats_buf;
398
 
399
 
399
-	DBGC2 ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
400
-		( reset ? " reset" : "" ) );
400
+	DBGC ( snpdev, "SNPDEV %p STATISTICS%s", snpdev,
401
+	       ( reset ? " reset" : "" ) );
401
 
402
 
402
 	/* Fail if net device is currently claimed for use by iPXE */
403
 	/* Fail if net device is currently claimed for use by iPXE */
403
 	if ( efi_snp_claimed )
404
 	if ( efi_snp_claimed )
449
 
450
 
450
 	ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
451
 	ip_str = ( ipv6 ? "(IPv6)" /* FIXME when we have inet6_ntoa() */ :
451
 		   inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
452
 		   inet_ntoa ( *( ( struct in_addr * ) ip ) ) );
452
-	DBGC2 ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
453
+	DBGC ( snpdev, "SNPDEV %p MCAST_IP_TO_MAC %s\n", snpdev, ip_str );
453
 
454
 
454
 	/* Fail if net device is currently claimed for use by iPXE */
455
 	/* Fail if net device is currently claimed for use by iPXE */
455
 	if ( efi_snp_claimed )
456
 	if ( efi_snp_claimed )
482
 	struct efi_snp_device *snpdev =
483
 	struct efi_snp_device *snpdev =
483
 		container_of ( snp, struct efi_snp_device, snp );
484
 		container_of ( snp, struct efi_snp_device, snp );
484
 
485
 
485
-	DBGC2 ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
486
-		( read ? "read" : "write" ), ( ( unsigned long ) offset ),
487
-		( ( unsigned long ) len ) );
486
+	DBGC ( snpdev, "SNPDEV %p NVDATA %s %lx+%lx\n", snpdev,
487
+	       ( read ? "read" : "write" ), ( ( unsigned long ) offset ),
488
+	       ( ( unsigned long ) len ) );
488
 	if ( ! read )
489
 	if ( ! read )
489
 		DBGC2_HDA ( snpdev, offset, data, len );
490
 		DBGC2_HDA ( snpdev, offset, data, len );
490
 
491
 
802
 	.Receive	= efi_snp_receive,
803
 	.Receive	= efi_snp_receive,
803
 };
804
 };
804
 
805
 
806
+/******************************************************************************
807
+ *
808
+ * UNDI protocol
809
+ *
810
+ ******************************************************************************
811
+ */
812
+
813
+/** Union type for command parameter blocks */
814
+typedef union {
815
+	PXE_CPB_STATION_ADDRESS station_address;
816
+	PXE_CPB_FILL_HEADER fill_header;
817
+	PXE_CPB_FILL_HEADER_FRAGMENTED fill_header_fragmented;
818
+	PXE_CPB_TRANSMIT transmit;
819
+	PXE_CPB_RECEIVE receive;
820
+} PXE_CPB_ANY;
821
+
822
+/** Union type for data blocks */
823
+typedef union {
824
+	PXE_DB_GET_INIT_INFO get_init_info;
825
+	PXE_DB_STATION_ADDRESS station_address;
826
+	PXE_DB_GET_STATUS get_status;
827
+	PXE_DB_RECEIVE receive;
828
+} PXE_DB_ANY;
829
+
830
+/**
831
+ * Calculate UNDI byte checksum
832
+ *
833
+ * @v data		Data
834
+ * @v len		Length of data
835
+ * @ret sum		Checksum
836
+ */
837
+static uint8_t efi_undi_checksum ( void *data, size_t len ) {
838
+	uint8_t *bytes = data;
839
+	uint8_t sum = 0;
840
+
841
+	while ( len-- )
842
+		sum += *bytes++;
843
+	return sum;
844
+}
845
+
846
+/**
847
+ * Get UNDI SNP device interface number
848
+ *
849
+ * @v snpdev		SNP device
850
+ * @ret ifnum		UNDI interface number
851
+ */
852
+static unsigned int efi_undi_ifnum ( struct efi_snp_device *snpdev ) {
853
+
854
+	/* iPXE network device indexes are one-based (leaving zero
855
+	 * meaning "unspecified").  UNDI interface numbers are
856
+	 * zero-based.
857
+	 */
858
+	return ( snpdev->netdev->index - 1 );
859
+}
860
+
861
+/**
862
+ * Identify UNDI SNP device
863
+ *
864
+ * @v ifnum		Interface number
865
+ * @ret snpdev		SNP device, or NULL if not found
866
+ */
867
+static struct efi_snp_device * efi_undi_snpdev ( unsigned int ifnum ) {
868
+	struct efi_snp_device *snpdev;
869
+
870
+	list_for_each_entry ( snpdev, &efi_snp_devices, list ) {
871
+		if ( efi_undi_ifnum ( snpdev ) == ifnum )
872
+			return snpdev;
873
+	}
874
+	return NULL;
875
+}
876
+
877
+/**
878
+ * Convert EFI status code to UNDI status code
879
+ *
880
+ * @v efirc		EFI status code
881
+ * @ret statcode	UNDI status code
882
+ */
883
+static PXE_STATCODE efi_undi_statcode ( EFI_STATUS efirc ) {
884
+
885
+	switch ( efirc ) {
886
+	case EFI_INVALID_PARAMETER:	return PXE_STATCODE_INVALID_PARAMETER;
887
+	case EFI_UNSUPPORTED:		return PXE_STATCODE_UNSUPPORTED;
888
+	case EFI_OUT_OF_RESOURCES:	return PXE_STATCODE_BUFFER_FULL;
889
+	case EFI_PROTOCOL_ERROR:	return PXE_STATCODE_DEVICE_FAILURE;
890
+	case EFI_NOT_READY:		return PXE_STATCODE_NO_DATA;
891
+	default:
892
+		return PXE_STATCODE_INVALID_CDB;
893
+	}
894
+}
895
+
896
+/**
897
+ * Get state
898
+ *
899
+ * @v snpdev		SNP device
900
+ * @v cdb		Command description block
901
+ * @ret efirc		EFI status code
902
+ */
903
+static EFI_STATUS efi_undi_get_state ( struct efi_snp_device *snpdev,
904
+				       PXE_CDB *cdb ) {
905
+	EFI_SIMPLE_NETWORK_MODE *mode = &snpdev->mode;
906
+
907
+	DBGC ( snpdev, "UNDI %p GET STATE\n", snpdev );
908
+
909
+	/* Return current state */
910
+	if ( mode->State == EfiSimpleNetworkInitialized ) {
911
+		cdb->StatFlags |= PXE_STATFLAGS_GET_STATE_INITIALIZED;
912
+	} else if ( mode->State == EfiSimpleNetworkStarted ) {
913
+		cdb->StatFlags |= PXE_STATFLAGS_GET_STATE_STARTED;
914
+	} else {
915
+		cdb->StatFlags |= PXE_STATFLAGS_GET_STATE_STOPPED;
916
+	}
917
+
918
+	return 0;
919
+}
920
+
921
+/**
922
+ * Start
923
+ *
924
+ * @v snpdev		SNP device
925
+ * @ret efirc		EFI status code
926
+ */
927
+static EFI_STATUS efi_undi_start ( struct efi_snp_device *snpdev ) {
928
+	EFI_STATUS efirc;
929
+
930
+	DBGC ( snpdev, "UNDI %p START\n", snpdev );
931
+
932
+	/* Start SNP device */
933
+	if ( ( efirc = efi_snp_start ( &snpdev->snp ) ) != 0 )
934
+		return efirc;
935
+
936
+	return 0;
937
+}
938
+
939
+/**
940
+ * Stop
941
+ *
942
+ * @v snpdev		SNP device
943
+ * @ret efirc		EFI status code
944
+ */
945
+static EFI_STATUS efi_undi_stop ( struct efi_snp_device *snpdev ) {
946
+	EFI_STATUS efirc;
947
+
948
+	DBGC ( snpdev, "UNDI %p STOP\n", snpdev );
949
+
950
+	/* Stop SNP device */
951
+	if ( ( efirc = efi_snp_stop ( &snpdev->snp ) ) != 0 )
952
+		return efirc;
953
+
954
+	return 0;
955
+}
956
+
957
+/**
958
+ * Get initialisation information
959
+ *
960
+ * @v snpdev		SNP device
961
+ * @v cdb		Command description block
962
+ * @v db		Data block
963
+ * @ret efirc		EFI status code
964
+ */
965
+static EFI_STATUS efi_undi_get_init_info ( struct efi_snp_device *snpdev,
966
+					   PXE_CDB *cdb,
967
+					   PXE_DB_GET_INIT_INFO *db ) {
968
+	struct net_device *netdev = snpdev->netdev;
969
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
970
+
971
+	DBGC ( snpdev, "UNDI %p GET INIT INFO\n", snpdev );
972
+
973
+	/* Populate structure */
974
+	memset ( db, 0, sizeof ( *db ) );
975
+	db->FrameDataLen = ( netdev->max_pkt_len - ll_protocol->ll_header_len );
976
+	db->MediaHeaderLen = ll_protocol->ll_header_len;
977
+	db->HWaddrLen = ll_protocol->ll_addr_len;
978
+	db->IFtype = ntohs ( ll_protocol->ll_proto );
979
+	cdb->StatFlags |= ( PXE_STATFLAGS_CABLE_DETECT_SUPPORTED |
980
+			    PXE_STATFLAGS_GET_STATUS_NO_MEDIA_SUPPORTED );
981
+
982
+	return 0;
983
+}
984
+
985
+/**
986
+ * Initialise
987
+ *
988
+ * @v snpdev		SNP device
989
+ * @v cdb		Command description block
990
+ * @v efirc		EFI status code
991
+ */
992
+static EFI_STATUS efi_undi_initialize ( struct efi_snp_device *snpdev,
993
+					PXE_CDB *cdb ) {
994
+	struct net_device *netdev = snpdev->netdev;
995
+	EFI_STATUS efirc;
996
+
997
+	DBGC ( snpdev, "UNDI %p INITIALIZE\n", snpdev );
998
+
999
+	/* Reset SNP device */
1000
+	if ( ( efirc = efi_snp_initialize ( &snpdev->snp, 0, 0 ) ) != 0 )
1001
+		return efirc;
1002
+
1003
+	/* Report link state */
1004
+	if ( ! netdev_link_ok ( netdev ) )
1005
+		cdb->StatFlags |= PXE_STATFLAGS_INITIALIZED_NO_MEDIA;
1006
+
1007
+	return 0;
1008
+}
1009
+
1010
+/**
1011
+ * Reset
1012
+ *
1013
+ * @v snpdev		SNP device
1014
+ * @v efirc		EFI status code
1015
+ */
1016
+static EFI_STATUS efi_undi_reset ( struct efi_snp_device *snpdev ) {
1017
+	EFI_STATUS efirc;
1018
+
1019
+	DBGC ( snpdev, "UNDI %p RESET\n", snpdev );
1020
+
1021
+	/* Reset SNP device */
1022
+	if ( ( efirc = efi_snp_reset ( &snpdev->snp, 0 ) ) != 0 )
1023
+		return efirc;
1024
+
1025
+	return 0;
1026
+}
1027
+
1028
+/**
1029
+ * Shutdown
1030
+ *
1031
+ * @v snpdev		SNP device
1032
+ * @v efirc		EFI status code
1033
+ */
1034
+static EFI_STATUS efi_undi_shutdown ( struct efi_snp_device *snpdev ) {
1035
+	EFI_STATUS efirc;
1036
+
1037
+	DBGC ( snpdev, "UNDI %p SHUTDOWN\n", snpdev );
1038
+
1039
+	/* Reset SNP device */
1040
+	if ( ( efirc = efi_snp_shutdown ( &snpdev->snp ) ) != 0 )
1041
+		return efirc;
1042
+
1043
+	return 0;
1044
+}
1045
+
1046
+/**
1047
+ * Get/set receive filters
1048
+ *
1049
+ * @v snpdev		SNP device
1050
+ * @v cdb		Command description block
1051
+ * @v efirc		EFI status code
1052
+ */
1053
+static EFI_STATUS efi_undi_receive_filters ( struct efi_snp_device *snpdev,
1054
+					     PXE_CDB *cdb ) {
1055
+
1056
+	DBGC ( snpdev, "UNDI %p RECEIVE FILTERS\n", snpdev );
1057
+
1058
+	/* Mark everything as supported */
1059
+	cdb->StatFlags |= ( PXE_STATFLAGS_RECEIVE_FILTER_UNICAST |
1060
+			    PXE_STATFLAGS_RECEIVE_FILTER_BROADCAST |
1061
+			    PXE_STATFLAGS_RECEIVE_FILTER_PROMISCUOUS |
1062
+			    PXE_STATFLAGS_RECEIVE_FILTER_ALL_MULTICAST );
1063
+
1064
+	return 0;
1065
+}
1066
+
1067
+/**
1068
+ * Get/set station address
1069
+ *
1070
+ * @v snpdev		SNP device
1071
+ * @v cdb		Command description block
1072
+ * @v cpb		Command parameter block
1073
+ * @v efirc		EFI status code
1074
+ */
1075
+static EFI_STATUS efi_undi_station_address ( struct efi_snp_device *snpdev,
1076
+					     PXE_CDB *cdb,
1077
+					     PXE_CPB_STATION_ADDRESS *cpb,
1078
+					     PXE_DB_STATION_ADDRESS *db ) {
1079
+	struct net_device *netdev = snpdev->netdev;
1080
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
1081
+	void *mac;
1082
+	int reset;
1083
+	EFI_STATUS efirc;
1084
+
1085
+	DBGC ( snpdev, "UNDI %p STATION ADDRESS\n", snpdev );
1086
+
1087
+	/* Update address if applicable */
1088
+	reset = ( cdb->OpFlags & PXE_OPFLAGS_STATION_ADDRESS_RESET );
1089
+	mac = ( cpb ? &cpb->StationAddr : NULL );
1090
+	if ( ( reset || mac ) &&
1091
+	     ( ( efirc = efi_snp_station_address ( &snpdev->snp, reset,
1092
+						   mac ) ) != 0 ) )
1093
+		return efirc;
1094
+
1095
+	/* Fill in current addresses, if applicable */
1096
+	if ( db ) {
1097
+		memset ( db, 0, sizeof ( *db ) );
1098
+		memcpy ( &db->StationAddr, netdev->ll_addr,
1099
+			 ll_protocol->ll_addr_len );
1100
+		memcpy ( &db->BroadcastAddr, netdev->ll_broadcast,
1101
+			 ll_protocol->ll_addr_len );
1102
+		memcpy ( &db->PermanentAddr, netdev->hw_addr,
1103
+			 ll_protocol->hw_addr_len );
1104
+	}
1105
+
1106
+	return 0;
1107
+}
1108
+
1109
+/**
1110
+ * Get interrupt status
1111
+ *
1112
+ * @v snpdev		SNP device
1113
+ * @v cdb		Command description block
1114
+ * @v db		Data block
1115
+ * @v efirc		EFI status code
1116
+ */
1117
+static EFI_STATUS efi_undi_get_status ( struct efi_snp_device *snpdev,
1118
+					PXE_CDB *cdb, PXE_DB_GET_STATUS *db ) {
1119
+	UINT32 interrupts;
1120
+	VOID *txbuf;
1121
+	struct io_buffer *rxbuf;
1122
+	EFI_STATUS efirc;
1123
+
1124
+	DBGC2 ( snpdev, "UNDI %p GET STATUS\n", snpdev );
1125
+
1126
+	/* Get status */
1127
+	if ( ( efirc = efi_snp_get_status ( &snpdev->snp, &interrupts,
1128
+					    &txbuf ) ) != 0 )
1129
+		return efirc;
1130
+
1131
+	/* Report status */
1132
+	memset ( db, 0, sizeof ( *db ) );
1133
+	if ( interrupts & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT )
1134
+		cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_RECEIVE;
1135
+	if ( interrupts & EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT )
1136
+		cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_TRANSMIT;
1137
+	if ( txbuf ) {
1138
+		db->TxBuffer[0] = ( ( intptr_t ) txbuf );
1139
+	} else {
1140
+		cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_TXBUFS_WRITTEN;
1141
+		/* The specification states clearly that UNDI drivers
1142
+		 * should set TXBUF_QUEUE_EMPTY if all completed
1143
+		 * buffer addresses are written into the returned data
1144
+		 * block.  However, SnpDxe chooses to interpret
1145
+		 * TXBUF_QUEUE_EMPTY as a synonym for
1146
+		 * NO_TXBUFS_WRITTEN, thereby rendering it entirely
1147
+		 * pointless.  Work around this UEFI stupidity, as per
1148
+		 * usual.
1149
+		 */
1150
+		if ( snpdev->tx_prod == snpdev->tx_cons )
1151
+			cdb->StatFlags |=
1152
+				PXE_STATFLAGS_GET_STATUS_TXBUF_QUEUE_EMPTY;
1153
+	}
1154
+	rxbuf = list_first_entry ( &snpdev->rx, struct io_buffer, list );
1155
+	if ( rxbuf )
1156
+		db->RxFrameLen = iob_len ( rxbuf );
1157
+	if ( ! netdev_link_ok ( snpdev->netdev ) )
1158
+		cdb->StatFlags |= PXE_STATFLAGS_GET_STATUS_NO_MEDIA;
1159
+
1160
+	return 0;
1161
+}
1162
+
1163
+/**
1164
+ * Fill header
1165
+ *
1166
+ * @v snpdev		SNP device
1167
+ * @v cdb		Command description block
1168
+ * @v cpb		Command parameter block
1169
+ * @v efirc		EFI status code
1170
+ */
1171
+static EFI_STATUS efi_undi_fill_header ( struct efi_snp_device *snpdev,
1172
+					 PXE_CDB *cdb, PXE_CPB_ANY *cpb ) {
1173
+	struct net_device *netdev = snpdev->netdev;
1174
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
1175
+	PXE_CPB_FILL_HEADER *whole = &cpb->fill_header;
1176
+	PXE_CPB_FILL_HEADER_FRAGMENTED *fragged = &cpb->fill_header_fragmented;
1177
+	VOID *data;
1178
+	void *dest;
1179
+	void *src;
1180
+	uint16_t proto;
1181
+	struct io_buffer iobuf;
1182
+	int rc;
1183
+
1184
+	/* SnpDxe will (pointlessly) use PXE_CPB_FILL_HEADER_FRAGMENTED
1185
+	 * even though we choose to explicitly not claim support for
1186
+	 * fragments via PXE_ROMID_IMP_FRAG_SUPPORTED.
1187
+	 */
1188
+	if ( cdb->OpFlags & PXE_OPFLAGS_FILL_HEADER_FRAGMENTED ) {
1189
+		data = ( ( void * ) ( intptr_t ) fragged->FragDesc[0].FragAddr);
1190
+		dest = &fragged->DestAddr;
1191
+		src = &fragged->SrcAddr;
1192
+		proto = fragged->Protocol;
1193
+	} else {
1194
+		data = ( ( void * ) ( intptr_t ) whole->MediaHeader );
1195
+		dest = &whole->DestAddr;
1196
+		src = &whole->SrcAddr;
1197
+		proto = whole->Protocol;
1198
+	}
1199
+
1200
+	/* Construct link-layer header */
1201
+	iob_populate ( &iobuf, data, 0, ll_protocol->ll_header_len );
1202
+	iob_reserve ( &iobuf, ll_protocol->ll_header_len );
1203
+	if ( ( rc = ll_protocol->push ( netdev, &iobuf, dest, src,
1204
+					proto ) ) != 0 )
1205
+		return EFIRC ( rc );
1206
+
1207
+	return 0;
1208
+}
1209
+
1210
+/**
1211
+ * Transmit
1212
+ *
1213
+ * @v snpdev		SNP device
1214
+ * @v cpb		Command parameter block
1215
+ * @v efirc		EFI status code
1216
+ */
1217
+static EFI_STATUS efi_undi_transmit ( struct efi_snp_device *snpdev,
1218
+				      PXE_CPB_TRANSMIT *cpb ) {
1219
+	VOID *data = ( ( void * ) ( intptr_t ) cpb->FrameAddr );
1220
+	EFI_STATUS efirc;
1221
+
1222
+	DBGC2 ( snpdev, "UNDI %p TRANSMIT\n", snpdev );
1223
+
1224
+	/* Transmit packet */
1225
+	if ( ( efirc = efi_snp_transmit ( &snpdev->snp, 0, cpb->DataLen,
1226
+					  data, NULL, NULL, NULL ) ) != 0 )
1227
+		return efirc;
1228
+
1229
+	return 0;
1230
+}
1231
+
1232
+/**
1233
+ * Receive
1234
+ *
1235
+ * @v snpdev		SNP device
1236
+ * @v cpb		Command parameter block
1237
+ * @v efirc		EFI status code
1238
+ */
1239
+static EFI_STATUS efi_undi_receive ( struct efi_snp_device *snpdev,
1240
+				     PXE_CPB_RECEIVE *cpb,
1241
+				     PXE_DB_RECEIVE *db ) {
1242
+	struct net_device *netdev = snpdev->netdev;
1243
+	struct ll_protocol *ll_protocol = netdev->ll_protocol;
1244
+	VOID *data = ( ( void * ) ( intptr_t ) cpb->BufferAddr );
1245
+	UINTN hdr_len;
1246
+	UINTN len = cpb->BufferLen;
1247
+	EFI_MAC_ADDRESS src;
1248
+	EFI_MAC_ADDRESS dest;
1249
+	UINT16 proto;
1250
+	EFI_STATUS efirc;
1251
+
1252
+	DBGC2 ( snpdev, "UNDI %p RECEIVE\n", snpdev );
1253
+
1254
+	/* Receive packet */
1255
+	if ( ( efirc = efi_snp_receive ( &snpdev->snp, &hdr_len, &len, data,
1256
+					 &src, &dest, &proto ) ) != 0 )
1257
+		return efirc;
1258
+
1259
+	/* Describe frame */
1260
+	memset ( db, 0, sizeof ( *db ) );
1261
+	memcpy ( &db->SrcAddr, &src, ll_protocol->ll_addr_len );
1262
+	memcpy ( &db->DestAddr, &dest, ll_protocol->ll_addr_len );
1263
+	db->FrameLen = len;
1264
+	db->Protocol = proto;
1265
+	db->MediaHeaderLen = ll_protocol->ll_header_len;
1266
+	db->Type = PXE_FRAME_TYPE_PROMISCUOUS;
1267
+
1268
+	return 0;
1269
+}
1270
+
1271
+/** UNDI entry point */
1272
+static EFIAPI VOID efi_undi_issue ( UINT64 cdb_phys ) {
1273
+	PXE_CDB *cdb = ( ( void * ) ( intptr_t ) cdb_phys );
1274
+	PXE_CPB_ANY *cpb = ( ( void * ) ( intptr_t ) cdb->CPBaddr );
1275
+	PXE_DB_ANY *db = ( ( void * ) ( intptr_t ) cdb->DBaddr );
1276
+	struct efi_snp_device *snpdev;
1277
+	EFI_STATUS efirc;
1278
+
1279
+	/* Identify device */
1280
+	snpdev = efi_undi_snpdev ( cdb->IFnum );
1281
+	if ( ! snpdev ) {
1282
+		DBGC ( cdb, "UNDI invalid interface number %d\n", cdb->IFnum );
1283
+		cdb->StatCode = PXE_STATCODE_INVALID_CDB;
1284
+		cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1285
+		return;
1286
+	}
1287
+
1288
+	/* Fail if net device is currently claimed for use by iPXE */
1289
+	if ( efi_snp_claimed ) {
1290
+		cdb->StatCode = PXE_STATCODE_BUSY;
1291
+		cdb->StatFlags = PXE_STATFLAGS_COMMAND_FAILED;
1292
+		return;
1293
+	}
1294
+
1295
+	/* Handle opcode */
1296
+	cdb->StatCode = PXE_STATCODE_SUCCESS;
1297
+	cdb->StatFlags = PXE_STATFLAGS_COMMAND_COMPLETE;
1298
+	switch ( cdb->OpCode ) {
1299
+
1300
+	case PXE_OPCODE_GET_STATE:
1301
+		efirc = efi_undi_get_state ( snpdev, cdb );
1302
+		break;
1303
+
1304
+	case PXE_OPCODE_START:
1305
+		efirc = efi_undi_start ( snpdev );
1306
+		break;
1307
+
1308
+	case PXE_OPCODE_STOP:
1309
+		efirc = efi_undi_stop ( snpdev );
1310
+		break;
1311
+
1312
+	case PXE_OPCODE_GET_INIT_INFO:
1313
+		efirc = efi_undi_get_init_info ( snpdev, cdb,
1314
+						 &db->get_init_info );
1315
+		break;
1316
+
1317
+	case PXE_OPCODE_INITIALIZE:
1318
+		efirc = efi_undi_initialize ( snpdev, cdb );
1319
+		break;
1320
+
1321
+	case PXE_OPCODE_RESET:
1322
+		efirc = efi_undi_reset ( snpdev );
1323
+		break;
1324
+
1325
+	case PXE_OPCODE_SHUTDOWN:
1326
+		efirc = efi_undi_shutdown ( snpdev );
1327
+		break;
1328
+
1329
+	case PXE_OPCODE_RECEIVE_FILTERS:
1330
+		efirc = efi_undi_receive_filters ( snpdev, cdb );
1331
+		break;
1332
+
1333
+	case PXE_OPCODE_STATION_ADDRESS:
1334
+		efirc = efi_undi_station_address ( snpdev, cdb,
1335
+						   &cpb->station_address,
1336
+						   &db->station_address );
1337
+		break;
1338
+
1339
+	case PXE_OPCODE_GET_STATUS:
1340
+		efirc = efi_undi_get_status ( snpdev, cdb, &db->get_status );
1341
+		break;
1342
+
1343
+	case PXE_OPCODE_FILL_HEADER:
1344
+		efirc = efi_undi_fill_header ( snpdev, cdb, cpb );
1345
+		break;
1346
+
1347
+	case PXE_OPCODE_TRANSMIT:
1348
+		efirc = efi_undi_transmit ( snpdev, &cpb->transmit );
1349
+		break;
1350
+
1351
+	case PXE_OPCODE_RECEIVE:
1352
+		efirc = efi_undi_receive ( snpdev, &cpb->receive,
1353
+					   &db->receive );
1354
+		break;
1355
+
1356
+	default:
1357
+		DBGC ( snpdev, "UNDI %p unsupported opcode %#04x\n",
1358
+		       snpdev, cdb->OpCode );
1359
+		efirc = EFI_UNSUPPORTED;
1360
+		break;
1361
+	}
1362
+
1363
+	/* Convert EFI status code to UNDI status code */
1364
+	if ( efirc != 0 ) {
1365
+		cdb->StatFlags &= ~PXE_STATFLAGS_STATUS_MASK;
1366
+		cdb->StatFlags |= PXE_STATFLAGS_COMMAND_FAILED;
1367
+		cdb->StatCode = efi_undi_statcode ( efirc );
1368
+	}
1369
+}
1370
+
1371
+/** UNDI interface
1372
+ *
1373
+ * Must be aligned on a 16-byte boundary, for no particularly good
1374
+ * reason.
1375
+ */
1376
+static PXE_SW_UNDI efi_snp_undi __attribute__ (( aligned ( 16 ) )) = {
1377
+	.Signature	= PXE_ROMID_SIGNATURE,
1378
+	.Len		= sizeof ( efi_snp_undi ),
1379
+	.Rev		= PXE_ROMID_REV,
1380
+	.MajorVer	= PXE_ROMID_MAJORVER,
1381
+	.MinorVer	= PXE_ROMID_MINORVER,
1382
+	.Implementation	= ( PXE_ROMID_IMP_SW_VIRT_ADDR |
1383
+			    PXE_ROMID_IMP_STATION_ADDR_SETTABLE |
1384
+			    PXE_ROMID_IMP_PROMISCUOUS_MULTICAST_RX_SUPPORTED |
1385
+			    PXE_ROMID_IMP_PROMISCUOUS_RX_SUPPORTED |
1386
+			    PXE_ROMID_IMP_BROADCAST_RX_SUPPORTED |
1387
+			    PXE_ROMID_IMP_TX_COMPLETE_INT_SUPPORTED |
1388
+			    PXE_ROMID_IMP_PACKET_RX_INT_SUPPORTED ),
1389
+	/* SnpDxe checks that BusCnt is non-zero.  It makes no further
1390
+	 * use of BusCnt, and never looks as BusType[].  As with much
1391
+	 * of the EDK2 code, this check seems to serve no purpose
1392
+	 * whatsoever but must nonetheless be humoured.
1393
+	 */
1394
+	.BusCnt		= 1,
1395
+	.BusType[0]	= PXE_BUSTYPE ( 'i', 'P', 'X', 'E' ),
1396
+};
1397
+
1398
+/** Network Identification Interface (NII) */
1399
+static EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL efi_snp_device_nii = {
1400
+	.Revision	= EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION,
1401
+	.StringId	= "UNDI",
1402
+	.Type		= EfiNetworkInterfaceUndi,
1403
+	.MajorVer	= 3,
1404
+	.MinorVer	= 1,
1405
+	.Ipv6Supported	= TRUE, /* This is a raw packet interface, FFS! */
1406
+};
1407
+
805
 /******************************************************************************
1408
 /******************************************************************************
806
  *
1409
  *
807
  * Component name protocol
1410
  * Component name protocol
939
 	EFI_DEVICE_PATH_PROTOCOL *path_end;
1542
 	EFI_DEVICE_PATH_PROTOCOL *path_end;
940
 	MAC_ADDR_DEVICE_PATH *macpath;
1543
 	MAC_ADDR_DEVICE_PATH *macpath;
941
 	size_t path_prefix_len = 0;
1544
 	size_t path_prefix_len = 0;
1545
+	unsigned int ifcnt;
1546
+	void *interface;
942
 	EFI_STATUS efirc;
1547
 	EFI_STATUS efirc;
943
 	int rc;
1548
 	int rc;
944
 
1549
 
986
 	efi_snp_set_mode ( snpdev );
1591
 	efi_snp_set_mode ( snpdev );
987
 
1592
 
988
 	/* Populate the NII structure */
1593
 	/* Populate the NII structure */
989
-	snpdev->nii.Revision =
990
-		EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
991
-	strncpy ( snpdev->nii.StringId, "iPXE",
992
-		  sizeof ( snpdev->nii.StringId ) );
1594
+	memcpy ( &snpdev->nii, &efi_snp_device_nii, sizeof ( snpdev->nii ) );
1595
+	snpdev->nii.Id = ( ( intptr_t ) &efi_snp_undi );
1596
+	snpdev->nii.IfNum = efi_undi_ifnum ( snpdev );
1597
+	efi_snp_undi.EntryPoint = ( ( intptr_t ) efi_undi_issue );
1598
+	ifcnt = ( ( efi_snp_undi.IFcntExt << 8 ) | efi_snp_undi.IFcnt );
1599
+	if ( ifcnt < snpdev->nii.IfNum )
1600
+		ifcnt = snpdev->nii.IfNum;
1601
+	efi_snp_undi.IFcnt = ( ifcnt & 0xff );
1602
+	efi_snp_undi.IFcntExt = ( ifcnt >> 8 );
1603
+	efi_snp_undi.Fudge -= efi_undi_checksum ( &efi_snp_undi,
1604
+						  sizeof ( efi_snp_undi ) );
993
 
1605
 
994
 	/* Populate the component name structure */
1606
 	/* Populate the component name structure */
995
 	efi_snprintf ( snpdev->driver_name,
1607
 	efi_snprintf ( snpdev->driver_name,
1056
 		goto err_install_protocol_interface;
1668
 		goto err_install_protocol_interface;
1057
 	}
1669
 	}
1058
 
1670
 
1671
+	/* SnpDxe will repeatedly start up and shut down our NII/UNDI
1672
+	 * interface (in order to obtain the MAC address) before
1673
+	 * discovering that it cannot install another SNP on the same
1674
+	 * handle.  This causes the underlying network device to be
1675
+	 * unexpectedly closed.
1676
+	 *
1677
+	 * Prevent this by opening our own NII (and NII31) protocol
1678
+	 * instances to prevent SnpDxe from attempting to bind to
1679
+	 * them.
1680
+	 */
1681
+	if ( ( efirc = bs->OpenProtocol ( snpdev->handle,
1682
+					  &efi_nii_protocol_guid, &interface,
1683
+					  efi_image_handle, snpdev->handle,
1684
+					  ( EFI_OPEN_PROTOCOL_BY_DRIVER |
1685
+					    EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){
1686
+		rc = -EEFI ( efirc );
1687
+		DBGC ( snpdev, "SNPDEV %p could not open NII protocol: %s\n",
1688
+		       snpdev, strerror ( rc ) );
1689
+		goto err_open_nii;
1690
+	}
1691
+	if ( ( efirc = bs->OpenProtocol ( snpdev->handle,
1692
+					  &efi_nii31_protocol_guid, &interface,
1693
+					  efi_image_handle, snpdev->handle,
1694
+					  ( EFI_OPEN_PROTOCOL_BY_DRIVER |
1695
+					    EFI_OPEN_PROTOCOL_EXCLUSIVE )))!=0){
1696
+		rc = -EEFI ( efirc );
1697
+		DBGC ( snpdev, "SNPDEV %p could not open NII31 protocol: %s\n",
1698
+		       snpdev, strerror ( rc ) );
1699
+		goto err_open_nii31;
1700
+	}
1701
+
1059
 	/* Add as child of EFI parent device */
1702
 	/* Add as child of EFI parent device */
1060
 	if ( ( rc = efi_child_add ( efidev->device, snpdev->handle ) ) != 0 ) {
1703
 	if ( ( rc = efi_child_add ( efidev->device, snpdev->handle ) ) != 0 ) {
1061
 		DBGC ( snpdev, "SNPDEV %p could not become child of %s: %s\n",
1704
 		DBGC ( snpdev, "SNPDEV %p could not become child of %s: %s\n",
1090
 		efi_snp_hii_uninstall ( snpdev );
1733
 		efi_snp_hii_uninstall ( snpdev );
1091
 	efi_child_del ( efidev->device, snpdev->handle );
1734
 	efi_child_del ( efidev->device, snpdev->handle );
1092
  err_efi_child_add:
1735
  err_efi_child_add:
1736
+	bs->CloseProtocol ( snpdev->handle, &efi_nii_protocol_guid,
1737
+			    efi_image_handle, snpdev->handle );
1738
+ err_open_nii:
1739
+	bs->CloseProtocol ( snpdev->handle, &efi_nii31_protocol_guid,
1740
+			    efi_image_handle, snpdev->handle );
1741
+ err_open_nii31:
1093
 	bs->UninstallMultipleProtocolInterfaces (
1742
 	bs->UninstallMultipleProtocolInterfaces (
1094
 			snpdev->handle,
1743
 			snpdev->handle,
1095
 			&efi_simple_network_protocol_guid, &snpdev->snp,
1744
 			&efi_simple_network_protocol_guid, &snpdev->snp,
1158
 	if ( snpdev->package_list )
1807
 	if ( snpdev->package_list )
1159
 		efi_snp_hii_uninstall ( snpdev );
1808
 		efi_snp_hii_uninstall ( snpdev );
1160
 	efi_child_del ( snpdev->efidev->device, snpdev->handle );
1809
 	efi_child_del ( snpdev->efidev->device, snpdev->handle );
1810
+	bs->CloseProtocol ( snpdev->handle, &efi_nii_protocol_guid,
1811
+			    efi_image_handle, snpdev->handle );
1812
+	bs->CloseProtocol ( snpdev->handle, &efi_nii31_protocol_guid,
1813
+			    efi_image_handle, snpdev->handle );
1161
 	bs->UninstallMultipleProtocolInterfaces (
1814
 	bs->UninstallMultipleProtocolInterfaces (
1162
 			snpdev->handle,
1815
 			snpdev->handle,
1163
 			&efi_simple_network_protocol_guid, &snpdev->snp,
1816
 			&efi_simple_network_protocol_guid, &snpdev->snp,

Loading…
Cancel
Save