Transmit.c revision 0e549d5be531a840503445d38b4dad2315ef3413
1/** @file 2Copyright (c) 2004 - 2007, Intel Corporation 3All rights reserved. This program and the accompanying materials 4are licensed and made available under the terms and conditions of the BSD License 5which accompanies this distribution. The full text of the license may be found at 6http://opensource.org/licenses/bsd-license.php 7 8THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 9WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 10 11Module name: 12 13 transmit.c 14 15Abstract: 16 17Revision history: 18 2000-Feb-03 M(f)J Genesis. 19 20**/ 21 22#include "Snp.h" 23 24 25/** 26 This routine calls undi to create the meadia header for the given data buffer. 27 28 @param snp pointer to SNP driver structure 29 @param MacHeaderPtr address where the media header will be filled in. 30 @param MacHeaderSize size of the memory at MacHeaderPtr 31 @param BufferPtr data buffer pointer 32 @param BufferLength Size of data in the BufferPtr 33 @param DestinationAddrPtr address of the destination mac address buffer 34 @param SourceAddrPtr address of the source mac address buffer 35 @param ProtocolPtr address of the protocol type 36 37 @retval EFI_SUCCESS if successfully completed the undi call 38 @retval Other error return from undi call. 39 40**/ 41STATIC 42EFI_STATUS 43pxe_fillheader ( 44 SNP_DRIVER *snp, 45 VOID *MacHeaderPtr, 46 UINTN MacHeaderSize, 47 VOID *BufferPtr, 48 UINTN BufferLength, 49 EFI_MAC_ADDRESS *DestinationAddrPtr, 50 EFI_MAC_ADDRESS *SourceAddrPtr, 51 UINT16 *ProtocolPtr 52 ) 53{ 54 PXE_CPB_FILL_HEADER_FRAGMENTED *cpb; 55 56 cpb = snp->cpb; 57 if (SourceAddrPtr) { 58 CopyMem ( 59 (VOID *) cpb->SrcAddr, 60 (VOID *) SourceAddrPtr, 61 snp->mode.HwAddressSize 62 ); 63 } else { 64 CopyMem ( 65 (VOID *) cpb->SrcAddr, 66 (VOID *) &(snp->mode.CurrentAddress), 67 snp->mode.HwAddressSize 68 ); 69 } 70 71 CopyMem ( 72 (VOID *) cpb->DestAddr, 73 (VOID *) DestinationAddrPtr, 74 snp->mode.HwAddressSize 75 ); 76 77 // 78 // we need to do the byte swapping 79 // 80 cpb->Protocol = (UINT16) PXE_SWAP_UINT16 (*ProtocolPtr); 81 82 cpb->PacketLen = (UINT32) (BufferLength); 83 cpb->MediaHeaderLen = (UINT16) MacHeaderSize; 84 85 cpb->FragCnt = 2; 86 cpb->reserved = 0; 87 88 cpb->FragDesc[0].FragAddr = (UINT64)(UINTN) MacHeaderPtr; 89 cpb->FragDesc[0].FragLen = (UINT32) MacHeaderSize; 90 cpb->FragDesc[1].FragAddr = (UINT64)(UINTN) BufferPtr; 91 cpb->FragDesc[1].FragLen = (UINT32) BufferLength; 92 93 cpb->FragDesc[0].reserved = cpb->FragDesc[1].reserved = 0; 94 95 snp->cdb.OpCode = PXE_OPCODE_FILL_HEADER; 96 snp->cdb.OpFlags = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED; 97 98 snp->cdb.DBsize = PXE_DBSIZE_NOT_USED; 99 snp->cdb.DBaddr = PXE_DBADDR_NOT_USED; 100 101 snp->cdb.CPBsize = sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED); 102 snp->cdb.CPBaddr = (UINT64)(UINTN) cpb; 103 104 snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; 105 snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; 106 snp->cdb.IFnum = snp->if_num; 107 snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; 108 109 // 110 // Issue UNDI command and check result. 111 // 112 DEBUG ((EFI_D_NET, "\nsnp->undi.fill_header() ")); 113 114 (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); 115 116 switch (snp->cdb.StatCode) { 117 case PXE_STATCODE_SUCCESS: 118 return EFI_SUCCESS; 119 120 case PXE_STATCODE_INVALID_PARAMETER: 121 DEBUG ( 122 (EFI_D_ERROR, 123 "\nsnp->undi.fill_header() %xh:%xh\n", 124 snp->cdb.StatFlags, 125 snp->cdb.StatCode) 126 ); 127 128 return EFI_INVALID_PARAMETER; 129 130 default: 131 DEBUG ( 132 (EFI_D_ERROR, 133 "\nsnp->undi.fill_header() %xh:%xh\n", 134 snp->cdb.StatFlags, 135 snp->cdb.StatCode) 136 ); 137 138 return EFI_DEVICE_ERROR; 139 } 140} 141 142 143/** 144 This routine calls undi to transmit the given data buffer 145 146 @param snp pointer to SNP driver structure 147 @param BufferPtr data buffer pointer 148 @param BufferLength Size of data in the BufferPtr 149 150 @retval EFI_SUCCESS if successfully completed the undi call 151 @retval Other error return from undi call. 152 153**/ 154STATIC 155EFI_STATUS 156pxe_transmit ( 157 SNP_DRIVER *snp, 158 VOID *BufferPtr, 159 UINTN BufferLength 160 ) 161{ 162 PXE_CPB_TRANSMIT *cpb; 163 EFI_STATUS Status; 164 165 cpb = snp->cpb; 166 cpb->FrameAddr = (UINT64) (UINTN) BufferPtr; 167 cpb->DataLen = (UINT32) BufferLength; 168 169 cpb->MediaheaderLen = 0; 170 cpb->reserved = 0; 171 172 snp->cdb.OpFlags = PXE_OPFLAGS_TRANSMIT_WHOLE; 173 174 snp->cdb.CPBsize = sizeof (PXE_CPB_TRANSMIT); 175 snp->cdb.CPBaddr = (UINT64)(UINTN) cpb; 176 177 snp->cdb.OpCode = PXE_OPCODE_TRANSMIT; 178 snp->cdb.DBsize = PXE_DBSIZE_NOT_USED; 179 snp->cdb.DBaddr = PXE_DBADDR_NOT_USED; 180 181 snp->cdb.StatCode = PXE_STATCODE_INITIALIZE; 182 snp->cdb.StatFlags = PXE_STATFLAGS_INITIALIZE; 183 snp->cdb.IFnum = snp->if_num; 184 snp->cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST; 185 186 // 187 // Issue UNDI command and check result. 188 // 189 DEBUG ((EFI_D_NET, "\nsnp->undi.transmit() ")); 190 DEBUG ((EFI_D_NET, "\nsnp->cdb.OpCode == %x", snp->cdb.OpCode)); 191 DEBUG ((EFI_D_NET, "\nsnp->cdb.CPBaddr == %LX", snp->cdb.CPBaddr)); 192 DEBUG ((EFI_D_NET, "\nsnp->cdb.DBaddr == %LX", snp->cdb.DBaddr)); 193 DEBUG ((EFI_D_NET, "\ncpb->FrameAddr == %LX\n", cpb->FrameAddr)); 194 195 (*snp->issue_undi32_command) ((UINT64) (UINTN) &snp->cdb); 196 197 DEBUG ((EFI_D_NET, "\nexit snp->undi.transmit() ")); 198 DEBUG ((EFI_D_NET, "\nsnp->cdb.StatCode == %r", snp->cdb.StatCode)); 199 200 // 201 // we will unmap the buffers in get_status call, not here 202 // 203 switch (snp->cdb.StatCode) { 204 case PXE_STATCODE_SUCCESS: 205 return EFI_SUCCESS; 206 207 case PXE_STATCODE_QUEUE_FULL: 208 case PXE_STATCODE_BUSY: 209 Status = EFI_NOT_READY; 210 break; 211 212 default: 213 Status = EFI_DEVICE_ERROR; 214 } 215 216 DEBUG ( 217 (EFI_D_ERROR, 218 "\nsnp->undi.transmit() %xh:%xh\n", 219 snp->cdb.StatFlags, 220 snp->cdb.StatCode) 221 ); 222 223 return Status; 224} 225 226 227/** 228 This is the snp interface routine for transmitting a packet. this routine 229 basically retrieves the snp structure, checks the snp state and calls 230 pxe_fill_header and pxe_transmit calls to complete the transmission. 231 232 @param this pointer to SNP driver context 233 @param MacHeaderSize size of the memory at MacHeaderPtr 234 @param BufferLength Size of data in the BufferPtr 235 @param BufferPtr data buffer pointer 236 @param SourceAddrPtr address of the source mac address buffer 237 @param DestinationAddrPtr address of the destination mac address buffer 238 @param ProtocolPtr address of the protocol type 239 240 @retval EFI_SUCCESS if successfully completed the undi call 241 @retval Other error return from undi call. 242 243**/ 244EFI_STATUS 245EFIAPI 246snp_undi32_transmit ( 247 IN EFI_SIMPLE_NETWORK_PROTOCOL * this, 248 IN UINTN MacHeaderSize, 249 IN UINTN BufferLength, 250 IN VOID *BufferPtr, 251 IN EFI_MAC_ADDRESS * SourceAddrPtr OPTIONAL, 252 IN EFI_MAC_ADDRESS * DestinationAddrPtr OPTIONAL, 253 IN UINT16 *ProtocolPtr OPTIONAL 254 ) 255{ 256 SNP_DRIVER *snp; 257 EFI_STATUS Status; 258 EFI_TPL OldTpl; 259 260 if (this == NULL) { 261 return EFI_INVALID_PARAMETER; 262 } 263 264 snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this); 265 266 OldTpl = gBS->RaiseTPL (TPL_CALLBACK); 267 268 if (snp == NULL) { 269 return EFI_DEVICE_ERROR; 270 } 271 272 switch (snp->mode.State) { 273 case EfiSimpleNetworkInitialized: 274 break; 275 276 case EfiSimpleNetworkStopped: 277 Status = EFI_NOT_STARTED; 278 goto ON_EXIT; 279 280 default: 281 Status = EFI_DEVICE_ERROR; 282 goto ON_EXIT; 283 } 284 285 if (BufferPtr == NULL) { 286 Status = EFI_INVALID_PARAMETER; 287 goto ON_EXIT; 288 } 289 290 if (BufferLength < snp->mode.MediaHeaderSize) { 291 Status = EFI_BUFFER_TOO_SMALL; 292 goto ON_EXIT; 293 } 294 295 // 296 // if the MacHeaderSize is non-zero, we need to fill up the header and for that 297 // we need the destination address and the protocol 298 // 299 if (MacHeaderSize != 0) { 300 if (MacHeaderSize != snp->mode.MediaHeaderSize || DestinationAddrPtr == 0 || ProtocolPtr == 0) { 301 Status = EFI_INVALID_PARAMETER; 302 goto ON_EXIT; 303 } 304 305 Status = pxe_fillheader ( 306 snp, 307 BufferPtr, 308 MacHeaderSize, 309 (UINT8 *) BufferPtr + MacHeaderSize, 310 BufferLength - MacHeaderSize, 311 DestinationAddrPtr, 312 SourceAddrPtr, 313 ProtocolPtr 314 ); 315 316 if (EFI_ERROR (Status)) { 317 goto ON_EXIT; 318 } 319 } 320 321 Status = pxe_transmit (snp, BufferPtr, BufferLength); 322 323ON_EXIT: 324 gBS->RestoreTPL (OldTpl); 325 326 return Status; 327} 328