summaryrefslogtreecommitdiffstats
path: root/NetworkPkg/SnpDxe/Receive.c
blob: 1efb2ad8dbd64d33c3a6ab6a8f1a187eda5db2e5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
/** @file
  Implementation of receiving a packet from a network interface.

Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent

**/


#include "Snp.h"

/**
  Call UNDI to receive a packet and fills in the data in the input pointers.

  @param  Snp          Pointer to snp driver structure
  @param  Buffer       Pointer to the memory for the received data
  @param  BufferSize   Pointer to the length of the buffer on entry and contains
                       the length of the received data on return
  @param  HeaderSize   Pointer to the header portion of the data received.
  @param  SrcAddr      Pointer to contain the source ethernet address on return
  @param  DestAddr     Pointer to contain the destination ethernet address on
                       return
  @param  Protocol     Pointer to contain the protocol type from the ethernet
                       header on return


  @retval EFI_SUCCESS           The received data was stored in Buffer, and
                                BufferSize has been updated to the number of
                                bytes received.
  @retval EFI_DEVICE_ERROR      Fail to execute UNDI command.
  @retval EFI_NOT_READY         No packets have been received on the network
                                interface.
  @retval EFI_BUFFER_TOO_SMALL  BufferSize is too small for the received
                                packets. BufferSize has been updated to the
                                required size.

**/
EFI_STATUS
PxeReceive (
  SNP_DRIVER      *Snp,
  VOID            *Buffer,
  UINTN           *BufferSize,
  UINTN           *HeaderSize,
  EFI_MAC_ADDRESS *SrcAddr,
  EFI_MAC_ADDRESS *DestAddr,
  UINT16          *Protocol
  )
{
  PXE_CPB_RECEIVE *Cpb;
  PXE_DB_RECEIVE  *Db;
  UINTN           BuffSize;

  Cpb       = Snp->Cpb;
  Db        = Snp->Db;
  BuffSize  = *BufferSize;

  Cpb->BufferAddr = (UINT64)(UINTN) Buffer;
  Cpb->BufferLen  = (UINT32) *BufferSize;

  Cpb->reserved       = 0;

  Snp->Cdb.OpCode     = PXE_OPCODE_RECEIVE;
  Snp->Cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;

  Snp->Cdb.CPBsize    = (UINT16) sizeof (PXE_CPB_RECEIVE);
  Snp->Cdb.CPBaddr    = (UINT64)(UINTN) Cpb;

  Snp->Cdb.DBsize     = (UINT16) sizeof (PXE_DB_RECEIVE);
  Snp->Cdb.DBaddr     = (UINT64)(UINTN) Db;

  Snp->Cdb.StatCode   = PXE_STATCODE_INITIALIZE;
  Snp->Cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;
  Snp->Cdb.IFnum      = Snp->IfNum;
  Snp->Cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;

  //
  // Issue UNDI command and check result.
  //
  DEBUG ((DEBUG_NET, "\nsnp->undi.receive ()  "));

  (*Snp->IssueUndi32Command) ((UINT64)(UINTN) &Snp->Cdb);

  switch (Snp->Cdb.StatCode) {
  case PXE_STATCODE_SUCCESS:
    break;

  case PXE_STATCODE_NO_DATA:
    DEBUG (
      (DEBUG_NET,
      "\nsnp->undi.receive ()  %xh:%xh\n",
      Snp->Cdb.StatFlags,
      Snp->Cdb.StatCode)
      );

    return EFI_NOT_READY;

  default:
    DEBUG (
      (DEBUG_ERROR,
      "\nsnp->undi.receive()  %xh:%xh\n",
      Snp->Cdb.StatFlags,
      Snp->Cdb.StatCode)
      );

    return EFI_DEVICE_ERROR;
  }

  *BufferSize = Db->FrameLen;

  if (HeaderSize != NULL) {
    *HeaderSize = Db->MediaHeaderLen;
  }

  if (SrcAddr != NULL) {
    CopyMem (SrcAddr, &Db->SrcAddr, Snp->Mode.HwAddressSize);
  }

  if (DestAddr != NULL) {
    CopyMem (DestAddr, &Db->DestAddr, Snp->Mode.HwAddressSize);
  }

  if (Protocol != NULL) {
    //
    // We need to do the byte swapping
    //
    *Protocol = (UINT16) PXE_SWAP_UINT16 (Db->Protocol);
  }

  //
  // We have received a packet from network interface, which implies that the
  // network cable should be present. While, some UNDI driver may not report
  // correct media status during Snp->Initialize(). So, we need ensure
  // MediaPresent in SNP mode data is set to correct value.
  //
  if (Snp->Mode.MediaPresentSupported && !Snp->Mode.MediaPresent) {
    Snp->Mode.MediaPresent = TRUE;
  }

  return (*BufferSize <= BuffSize) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;
}

/**
  Receives a packet from a network interface.

  This function retrieves one packet from the receive queue of a network interface.
  If there are no packets on the receive queue, then EFI_NOT_READY will be
  returned. If there is a packet on the receive queue, and the size of the packet
  is smaller than BufferSize, then the contents of the packet will be placed in
  Buffer, and BufferSize will be updated with the actual size of the packet.
  In addition, if SrcAddr, DestAddr, and Protocol are not NULL, then these values
  will be extracted from the media header and returned. EFI_SUCCESS will be
  returned if a packet was successfully received.
  If BufferSize is smaller than the received packet, then the size of the receive
  packet will be placed in BufferSize and EFI_BUFFER_TOO_SMALL will be returned.
  If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.

  @param This       A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.
  @param HeaderSize The size, in bytes, of the media header received on the network
                    interface. If this parameter is NULL, then the media header size
                    will not be returned.
  @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
                    bytes, of the packet that was received on the network interface.
  @param Buffer     A pointer to the data buffer to receive both the media
                    header and the data.
  @param SrcAddr    The source HW MAC address. If this parameter is NULL, the HW
                    MAC source address will not be extracted from the media header.
  @param DestAddr   The destination HW MAC address. If this parameter is NULL,
                    the HW MAC destination address will not be extracted from
                    the media header.
  @param Protocol   The media header type. If this parameter is NULL, then the
                    protocol will not be extracted from the media header. See
                    RFC 1700 section "Ether Types" for examples.

  @retval EFI_SUCCESS           The received data was stored in Buffer, and
                                BufferSize has been updated to the number of
                                bytes received.
  @retval EFI_NOT_STARTED       The network interface has not been started.
  @retval EFI_NOT_READY         No packets have been received on the network interface.
  @retval EFI_BUFFER_TOO_SMALL  BufferSize is too small for the received packets.
                                BufferSize has been updated to the required size.
  @retval EFI_INVALID_PARAMETER One or more of the following conditions is TRUE:
                                * The This parameter is NULL
                                * The This parameter does not point to a valid
                                  EFI_SIMPLE_NETWORK_PROTOCOL structure.
                                * The BufferSize parameter is NULL
                                * The Buffer parameter is NULL
  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.

**/
EFI_STATUS
EFIAPI
SnpUndi32Receive (
  IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
  OUT UINTN                      *HeaderSize OPTIONAL,
  IN OUT UINTN                   *BufferSize,
  OUT VOID                       *Buffer,
  OUT EFI_MAC_ADDRESS            *SrcAddr OPTIONAL,
  OUT EFI_MAC_ADDRESS            *DestAddr OPTIONAL,
  OUT UINT16                     *Protocol OPTIONAL
  )
{
  SNP_DRIVER  *Snp;
  EFI_TPL     OldTpl;
  EFI_STATUS  Status;

  if (This == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);

  OldTpl = gBS->RaiseTPL (TPL_CALLBACK);

  switch (Snp->Mode.State) {
  case EfiSimpleNetworkInitialized:
    break;

  case EfiSimpleNetworkStopped:
    Status = EFI_NOT_STARTED;
    goto ON_EXIT;

  default:
    Status = EFI_DEVICE_ERROR;
    goto ON_EXIT;
  }

  if ((BufferSize == NULL) || (Buffer == NULL)) {
    Status = EFI_INVALID_PARAMETER;
    goto ON_EXIT;
  }

  if (Snp->Mode.ReceiveFilterSetting == 0) {
    Status = EFI_DEVICE_ERROR;
    goto ON_EXIT;
  }

  Status = PxeReceive (
             Snp,
             Buffer,
             BufferSize,
             HeaderSize,
             SrcAddr,
             DestAddr,
             Protocol
             );

ON_EXIT:
  gBS->RestoreTPL (OldTpl);

  return Status;
}