]>
Commit | Line | Data |
---|---|---|
a3c5f87a | 1 | /** @file\r |
4cda7726 | 2 | Implementation of transmitting a packet.\r |
d1102dba LG |
3 | \r |
4 | Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r | |
9d510e61 | 5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
a3c5f87a | 6 | \r |
a3c5f87a | 7 | **/\r |
8 | \r | |
9 | #include "Snp.h"\r | |
10 | \r | |
a3c5f87a | 11 | /**\r |
f3816027 | 12 | Call UNDI to create the meadia header for the given data buffer.\r |
a3c5f87a | 13 | \r |
f3816027 | 14 | @param Snp Pointer to SNP driver structure.\r |
15 | @param MacHeaderPtr Address where the media header will be filled in.\r | |
16 | @param HeaderSize Size of the memory at MacHeaderPtr.\r | |
17 | @param Buffer Data buffer pointer.\r | |
18 | @param BufferSize Size of data in the Buffer\r | |
19 | @param DestAddr Address of the destination mac address buffer.\r | |
20 | @param SrcAddr Address of the source mac address buffer.\r | |
21 | @param ProtocolPtr Address of the protocol type.\r | |
a3c5f87a | 22 | \r |
f3816027 | 23 | @retval EFI_SUCCESS Successfully completed the undi call.\r |
24 | @retval Other Error return from undi call.\r | |
a3c5f87a | 25 | \r |
26 | **/\r | |
a3c5f87a | 27 | EFI_STATUS\r |
4cda7726 | 28 | PxeFillHeader (\r |
d1050b9d MK |
29 | SNP_DRIVER *Snp,\r |
30 | VOID *MacHeaderPtr,\r | |
31 | UINTN HeaderSize,\r | |
32 | VOID *Buffer,\r | |
33 | UINTN BufferSize,\r | |
34 | EFI_MAC_ADDRESS *DestAddr,\r | |
35 | EFI_MAC_ADDRESS *SrcAddr,\r | |
36 | UINT16 *ProtocolPtr\r | |
a3c5f87a | 37 | )\r |
38 | {\r | |
4cda7726 | 39 | PXE_CPB_FILL_HEADER_FRAGMENTED *Cpb;\r |
a3c5f87a | 40 | \r |
4cda7726 | 41 | Cpb = Snp->Cpb;\r |
42 | if (SrcAddr != NULL) {\r | |
a3c5f87a | 43 | CopyMem (\r |
d1050b9d MK |
44 | (VOID *)Cpb->SrcAddr,\r |
45 | (VOID *)SrcAddr,\r | |
4cda7726 | 46 | Snp->Mode.HwAddressSize\r |
a3c5f87a | 47 | );\r |
48 | } else {\r | |
49 | CopyMem (\r | |
d1050b9d MK |
50 | (VOID *)Cpb->SrcAddr,\r |
51 | (VOID *)&(Snp->Mode.CurrentAddress),\r | |
4cda7726 | 52 | Snp->Mode.HwAddressSize\r |
a3c5f87a | 53 | );\r |
54 | }\r | |
55 | \r | |
56 | CopyMem (\r | |
d1050b9d MK |
57 | (VOID *)Cpb->DestAddr,\r |
58 | (VOID *)DestAddr,\r | |
4cda7726 | 59 | Snp->Mode.HwAddressSize\r |
a3c5f87a | 60 | );\r |
61 | \r | |
62 | //\r | |
63 | // we need to do the byte swapping\r | |
64 | //\r | |
d1050b9d | 65 | Cpb->Protocol = (UINT16)PXE_SWAP_UINT16 (*ProtocolPtr);\r |
a3c5f87a | 66 | \r |
d1050b9d MK |
67 | Cpb->PacketLen = (UINT32)(BufferSize);\r |
68 | Cpb->MediaHeaderLen = (UINT16)HeaderSize;\r | |
a3c5f87a | 69 | \r |
d1050b9d MK |
70 | Cpb->FragCnt = 2;\r |
71 | Cpb->reserved = 0;\r | |
a3c5f87a | 72 | \r |
d1050b9d MK |
73 | Cpb->FragDesc[0].FragAddr = (UINT64)(UINTN)MacHeaderPtr;\r |
74 | Cpb->FragDesc[0].FragLen = (UINT32)HeaderSize;\r | |
75 | Cpb->FragDesc[1].FragAddr = (UINT64)(UINTN)Buffer;\r | |
76 | Cpb->FragDesc[1].FragLen = (UINT32)BufferSize;\r | |
a3c5f87a | 77 | \r |
4cda7726 | 78 | Cpb->FragDesc[0].reserved = Cpb->FragDesc[1].reserved = 0;\r |
a3c5f87a | 79 | \r |
d1050b9d MK |
80 | Snp->Cdb.OpCode = PXE_OPCODE_FILL_HEADER;\r |
81 | Snp->Cdb.OpFlags = PXE_OPFLAGS_FILL_HEADER_FRAGMENTED;\r | |
a3c5f87a | 82 | \r |
d1050b9d MK |
83 | Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;\r |
84 | Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;\r | |
a3c5f87a | 85 | \r |
d1050b9d MK |
86 | Snp->Cdb.CPBsize = (UINT16)sizeof (PXE_CPB_FILL_HEADER_FRAGMENTED);\r |
87 | Snp->Cdb.CPBaddr = (UINT64)(UINTN)Cpb;\r | |
a3c5f87a | 88 | \r |
d1050b9d MK |
89 | Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;\r |
90 | Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r | |
91 | Snp->Cdb.IFnum = Snp->IfNum;\r | |
92 | Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r | |
a3c5f87a | 93 | \r |
94 | //\r | |
95 | // Issue UNDI command and check result.\r | |
96 | //\r | |
c49ca4a2 | 97 | DEBUG ((DEBUG_NET, "\nSnp->undi.fill_header() "));\r |
a3c5f87a | 98 | \r |
d1050b9d | 99 | (*Snp->IssueUndi32Command)((UINT64)(UINTN)&Snp->Cdb);\r |
a3c5f87a | 100 | \r |
4cda7726 | 101 | switch (Snp->Cdb.StatCode) {\r |
d1050b9d MK |
102 | case PXE_STATCODE_SUCCESS:\r |
103 | return EFI_SUCCESS;\r | |
104 | \r | |
105 | case PXE_STATCODE_INVALID_PARAMETER:\r | |
106 | DEBUG (\r | |
107 | (DEBUG_ERROR,\r | |
108 | "\nSnp->undi.fill_header() %xh:%xh\n",\r | |
109 | Snp->Cdb.StatFlags,\r | |
110 | Snp->Cdb.StatCode)\r | |
111 | );\r | |
112 | \r | |
113 | return EFI_INVALID_PARAMETER;\r | |
114 | \r | |
115 | default:\r | |
116 | DEBUG (\r | |
117 | (DEBUG_ERROR,\r | |
118 | "\nSnp->undi.fill_header() %xh:%xh\n",\r | |
119 | Snp->Cdb.StatFlags,\r | |
120 | Snp->Cdb.StatCode)\r | |
121 | );\r | |
122 | \r | |
123 | return EFI_DEVICE_ERROR;\r | |
a3c5f87a | 124 | }\r |
125 | }\r | |
126 | \r | |
a3c5f87a | 127 | /**\r |
128 | This routine calls undi to transmit the given data buffer\r | |
129 | \r | |
4cda7726 | 130 | @param Snp pointer to SNP driver structure\r |
131 | @param Buffer data buffer pointer\r | |
132 | @param BufferSize Size of data in the Buffer\r | |
a3c5f87a | 133 | \r |
134 | @retval EFI_SUCCESS if successfully completed the undi call\r | |
135 | @retval Other error return from undi call.\r | |
136 | \r | |
137 | **/\r | |
a3c5f87a | 138 | EFI_STATUS\r |
4cda7726 | 139 | PxeTransmit (\r |
d1050b9d MK |
140 | SNP_DRIVER *Snp,\r |
141 | VOID *Buffer,\r | |
142 | UINTN BufferSize\r | |
a3c5f87a | 143 | )\r |
144 | {\r | |
4cda7726 | 145 | PXE_CPB_TRANSMIT *Cpb;\r |
a3c5f87a | 146 | EFI_STATUS Status;\r |
147 | \r | |
d1050b9d MK |
148 | Cpb = Snp->Cpb;\r |
149 | Cpb->FrameAddr = (UINT64)(UINTN)Buffer;\r | |
150 | Cpb->DataLen = (UINT32)BufferSize;\r | |
a3c5f87a | 151 | \r |
4cda7726 | 152 | Cpb->MediaheaderLen = 0;\r |
153 | Cpb->reserved = 0;\r | |
a3c5f87a | 154 | \r |
d1050b9d | 155 | Snp->Cdb.OpFlags = PXE_OPFLAGS_TRANSMIT_WHOLE;\r |
a3c5f87a | 156 | \r |
d1050b9d MK |
157 | Snp->Cdb.CPBsize = (UINT16)sizeof (PXE_CPB_TRANSMIT);\r |
158 | Snp->Cdb.CPBaddr = (UINT64)(UINTN)Cpb;\r | |
a3c5f87a | 159 | \r |
d1050b9d MK |
160 | Snp->Cdb.OpCode = PXE_OPCODE_TRANSMIT;\r |
161 | Snp->Cdb.DBsize = PXE_DBSIZE_NOT_USED;\r | |
162 | Snp->Cdb.DBaddr = PXE_DBADDR_NOT_USED;\r | |
a3c5f87a | 163 | \r |
d1050b9d MK |
164 | Snp->Cdb.StatCode = PXE_STATCODE_INITIALIZE;\r |
165 | Snp->Cdb.StatFlags = PXE_STATFLAGS_INITIALIZE;\r | |
166 | Snp->Cdb.IFnum = Snp->IfNum;\r | |
167 | Snp->Cdb.Control = PXE_CONTROL_LAST_CDB_IN_LIST;\r | |
a3c5f87a | 168 | \r |
169 | //\r | |
170 | // Issue UNDI command and check result.\r | |
171 | //\r | |
c49ca4a2 MK |
172 | DEBUG ((DEBUG_NET, "\nSnp->undi.transmit() "));\r |
173 | DEBUG ((DEBUG_NET, "\nSnp->Cdb.OpCode == %x", Snp->Cdb.OpCode));\r | |
174 | DEBUG ((DEBUG_NET, "\nSnp->Cdb.CPBaddr == %LX", Snp->Cdb.CPBaddr));\r | |
175 | DEBUG ((DEBUG_NET, "\nSnp->Cdb.DBaddr == %LX", Snp->Cdb.DBaddr));\r | |
176 | DEBUG ((DEBUG_NET, "\nCpb->FrameAddr == %LX\n", Cpb->FrameAddr));\r | |
a3c5f87a | 177 | \r |
d1050b9d | 178 | (*Snp->IssueUndi32Command)((UINT64)(UINTN)&Snp->Cdb);\r |
a3c5f87a | 179 | \r |
c49ca4a2 | 180 | DEBUG ((DEBUG_NET, "\nexit Snp->undi.transmit() "));\r |
a3c5f87a | 181 | \r |
182 | //\r | |
183 | // we will unmap the buffers in get_status call, not here\r | |
184 | //\r | |
4cda7726 | 185 | switch (Snp->Cdb.StatCode) {\r |
d1050b9d MK |
186 | case PXE_STATCODE_SUCCESS:\r |
187 | return EFI_SUCCESS;\r | |
188 | \r | |
189 | case PXE_STATCODE_BUFFER_FULL:\r | |
190 | case PXE_STATCODE_QUEUE_FULL:\r | |
191 | case PXE_STATCODE_BUSY:\r | |
192 | Status = EFI_NOT_READY;\r | |
193 | DEBUG (\r | |
194 | (DEBUG_NET,\r | |
195 | "\nSnp->undi.transmit() %xh:%xh\n",\r | |
196 | Snp->Cdb.StatFlags,\r | |
197 | Snp->Cdb.StatCode)\r | |
198 | );\r | |
199 | break;\r | |
200 | \r | |
201 | default:\r | |
202 | DEBUG (\r | |
203 | (DEBUG_ERROR,\r | |
204 | "\nSnp->undi.transmit() %xh:%xh\n",\r | |
205 | Snp->Cdb.StatFlags,\r | |
206 | Snp->Cdb.StatCode)\r | |
207 | );\r | |
208 | Status = EFI_DEVICE_ERROR;\r | |
a3c5f87a | 209 | }\r |
210 | \r | |
a3c5f87a | 211 | return Status;\r |
212 | }\r | |
213 | \r | |
a3c5f87a | 214 | /**\r |
4cda7726 | 215 | Places a packet in the transmit queue of a network interface.\r |
d1102dba | 216 | \r |
4cda7726 | 217 | This function places the packet specified by Header and Buffer on the transmit\r |
d1102dba LG |
218 | queue. If HeaderSize is nonzero and HeaderSize is not equal to\r |
219 | This->Mode->MediaHeaderSize, then EFI_INVALID_PARAMETER will be returned. If\r | |
4cda7726 | 220 | BufferSize is less than This->Mode->MediaHeaderSize, then EFI_BUFFER_TOO_SMALL\r |
d1102dba | 221 | will be returned. If Buffer is NULL, then EFI_INVALID_PARAMETER will be\r |
4cda7726 | 222 | returned. If HeaderSize is nonzero and DestAddr or Protocol is NULL, then\r |
223 | EFI_INVALID_PARAMETER will be returned. If the transmit engine of the network\r | |
d1102dba LG |
224 | interface is busy, then EFI_NOT_READY will be returned. If this packet can be\r |
225 | accepted by the transmit engine of the network interface, the packet contents\r | |
226 | specified by Buffer will be placed on the transmit queue of the network\r | |
227 | interface, and EFI_SUCCESS will be returned. GetStatus() can be used to\r | |
228 | determine when the packet has actually been transmitted. The contents of the\r | |
229 | Buffer must not be modified until the packet has actually been transmitted.\r | |
4cda7726 | 230 | The Transmit() function performs nonblocking I/O. A caller who wants to perform\r |
d1102dba | 231 | blocking I/O, should call Transmit(), and then GetStatus() until the\r |
4cda7726 | 232 | transmitted buffer shows up in the recycled transmit buffer.\r |
233 | If the driver has not been initialized, EFI_DEVICE_ERROR will be returned.\r | |
234 | \r | |
235 | @param This A pointer to the EFI_SIMPLE_NETWORK_PROTOCOL instance.\r | |
d1102dba | 236 | @param HeaderSize The size, in bytes, of the media header to be filled in by the\r |
4cda7726 | 237 | Transmit() function. If HeaderSize is nonzero, then it must\r |
238 | be equal to This->Mode->MediaHeaderSize and the DestAddr and\r | |
239 | Protocol parameters must not be NULL.\r | |
240 | @param BufferSize The size, in bytes, of the entire packet (media header and\r | |
241 | data) to be transmitted through the network interface.\r | |
d1102dba LG |
242 | @param Buffer A pointer to the packet (media header followed by data) to be\r |
243 | transmitted. This parameter cannot be NULL. If HeaderSize is\r | |
4cda7726 | 244 | zero, then the media header in Buffer must already be filled\r |
d1102dba | 245 | in by the caller. If HeaderSize is nonzero, then the media\r |
4cda7726 | 246 | header will be filled in by the Transmit() function.\r |
d1102dba LG |
247 | @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this\r |
248 | parameter is ignored. If HeaderSize is nonzero and SrcAddr\r | |
249 | is NULL, then This->Mode->CurrentAddress is used for the\r | |
4cda7726 | 250 | source HW MAC address.\r |
d1102dba | 251 | @param DestAddr The destination HW MAC address. If HeaderSize is zero, then\r |
4cda7726 | 252 | this parameter is ignored.\r |
d1102dba LG |
253 | @param Protocol The type of header to build. If HeaderSize is zero, then this\r |
254 | parameter is ignored. See RFC 1700, section "Ether Types,"\r | |
4cda7726 | 255 | for examples.\r |
256 | \r | |
257 | @retval EFI_SUCCESS The packet was placed on the transmit queue.\r | |
258 | @retval EFI_NOT_STARTED The network interface has not been started.\r | |
259 | @retval EFI_NOT_READY The network interface is too busy to accept this\r | |
260 | transmit request.\r | |
261 | @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.\r | |
262 | @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported\r | |
263 | value.\r | |
264 | @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.\r | |
265 | @retval EFI_UNSUPPORTED This function is not supported by the network interface.\r | |
a3c5f87a | 266 | \r |
267 | **/\r | |
268 | EFI_STATUS\r | |
269 | EFIAPI\r | |
4cda7726 | 270 | SnpUndi32Transmit (\r |
d1050b9d MK |
271 | IN EFI_SIMPLE_NETWORK_PROTOCOL *This,\r |
272 | IN UINTN HeaderSize,\r | |
273 | IN UINTN BufferSize,\r | |
274 | IN VOID *Buffer,\r | |
275 | IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,\r | |
276 | IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,\r | |
277 | IN UINT16 *Protocol OPTIONAL\r | |
a3c5f87a | 278 | )\r |
279 | {\r | |
4cda7726 | 280 | SNP_DRIVER *Snp;\r |
a3c5f87a | 281 | EFI_STATUS Status;\r |
282 | EFI_TPL OldTpl;\r | |
283 | \r | |
4cda7726 | 284 | if (This == NULL) {\r |
a3c5f87a | 285 | return EFI_INVALID_PARAMETER;\r |
286 | }\r | |
287 | \r | |
4cda7726 | 288 | Snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);\r |
a3c5f87a | 289 | \r |
290 | OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r | |
291 | \r | |
4cda7726 | 292 | if (Snp == NULL) {\r |
a3c5f87a | 293 | return EFI_DEVICE_ERROR;\r |
294 | }\r | |
295 | \r | |
4cda7726 | 296 | switch (Snp->Mode.State) {\r |
d1050b9d MK |
297 | case EfiSimpleNetworkInitialized:\r |
298 | break;\r | |
a3c5f87a | 299 | \r |
d1050b9d MK |
300 | case EfiSimpleNetworkStopped:\r |
301 | Status = EFI_NOT_STARTED;\r | |
302 | goto ON_EXIT;\r | |
a3c5f87a | 303 | \r |
d1050b9d MK |
304 | default:\r |
305 | Status = EFI_DEVICE_ERROR;\r | |
306 | goto ON_EXIT;\r | |
a3c5f87a | 307 | }\r |
308 | \r | |
4cda7726 | 309 | if (Buffer == NULL) {\r |
a3c5f87a | 310 | Status = EFI_INVALID_PARAMETER;\r |
311 | goto ON_EXIT;\r | |
312 | }\r | |
313 | \r | |
4cda7726 | 314 | if (BufferSize < Snp->Mode.MediaHeaderSize) {\r |
a3c5f87a | 315 | Status = EFI_BUFFER_TOO_SMALL;\r |
316 | goto ON_EXIT;\r | |
317 | }\r | |
318 | \r | |
319 | //\r | |
4cda7726 | 320 | // if the HeaderSize is non-zero, we need to fill up the header and for that\r |
a3c5f87a | 321 | // we need the destination address and the protocol\r |
322 | //\r | |
4cda7726 | 323 | if (HeaderSize != 0) {\r |
d1050b9d | 324 | if ((HeaderSize != Snp->Mode.MediaHeaderSize) || (DestAddr == 0) || (Protocol == 0)) {\r |
a3c5f87a | 325 | Status = EFI_INVALID_PARAMETER;\r |
326 | goto ON_EXIT;\r | |
327 | }\r | |
328 | \r | |
4cda7726 | 329 | Status = PxeFillHeader (\r |
d1050b9d MK |
330 | Snp,\r |
331 | Buffer,\r | |
332 | HeaderSize,\r | |
333 | (UINT8 *)Buffer + HeaderSize,\r | |
334 | BufferSize - HeaderSize,\r | |
335 | DestAddr,\r | |
336 | SrcAddr,\r | |
337 | Protocol\r | |
338 | );\r | |
a3c5f87a | 339 | \r |
340 | if (EFI_ERROR (Status)) {\r | |
341 | goto ON_EXIT;\r | |
342 | }\r | |
343 | }\r | |
344 | \r | |
4cda7726 | 345 | Status = PxeTransmit (Snp, Buffer, BufferSize);\r |
a3c5f87a | 346 | \r |
347 | ON_EXIT:\r | |
348 | gBS->RestoreTPL (OldTpl);\r | |
349 | \r | |
350 | return Status;\r | |
351 | }\r |