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