1. Sync Tcp4 protocol definitions to match UEFI 2.1
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Network / SnpDxe / receive.c
1 /** @file\r
2 Copyright (c) 2004 - 2007, Intel Corporation\r
3 All rights reserved. This program and the accompanying materials\r
4 are licensed and made available under the terms and conditions of the BSD License\r
5 which accompanies this distribution.  The full text of the license may be found at\r
6 http://opensource.org/licenses/bsd-license.php\r
7 \r
8 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
9 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
10 \r
11 Module name:\r
12     receive.c\r
13 \r
14 Abstract:\r
15 \r
16 Revision history:\r
17     2000-Feb-03 M(f)J   Genesis.\r
18 \r
19 **/\r
20 \r
21 \r
22 #include "Snp.h"\r
23 \r
24 /**\r
25   this routine calls undi to receive a packet and fills in the data in the\r
26   input pointers!\r
27 \r
28   @param  snp                 pointer to snp driver structure\r
29   @param  BufferPtr           pointer to the memory for the received data\r
30   @param  BuffSizePtr         is a pointer to the length of the buffer on entry and\r
31                               contains the length of the received data on return\r
32   @param  HeaderSizePtr       pointer to the header portion of the data received.\r
33   @param  SourceAddrPtr       optional parameter, is a pointer to contain the\r
34                               source ethernet address on return\r
35   @param  DestinationAddrPtr  optional parameter, is a pointer to contain the\r
36                               destination ethernet address on return\r
37   @param  ProtocolPtr         optional parameter, is a pointer to contain the\r
38                               protocol type from the ethernet header on return\r
39 \r
40 \r
41 **/\r
42 STATIC\r
43 EFI_STATUS\r
44 pxe_receive (\r
45   SNP_DRIVER      *snp,\r
46   VOID            *BufferPtr,\r
47   UINTN           *BuffSizePtr,\r
48   UINTN           *HeaderSizePtr,\r
49   EFI_MAC_ADDRESS *SourceAddrPtr,\r
50   EFI_MAC_ADDRESS *DestinationAddrPtr,\r
51   UINT16          *ProtocolPtr\r
52   )\r
53 {\r
54   PXE_CPB_RECEIVE *cpb;\r
55   PXE_DB_RECEIVE  *db;\r
56   UINTN           buf_size;\r
57   UINT64          TempData;\r
58 \r
59   cpb       = snp->cpb;\r
60   db        = snp->db;\r
61   buf_size  = *BuffSizePtr;\r
62   //\r
63   // IMPORTANT NOTE:\r
64   // In case of the older 3.0 UNDI, if the input buffer address is beyond 4GB,\r
65   // DO NOT call the map function on the given buffer, instead use\r
66   // a global buffer. The reason is that UNDI3.0 has some unnecessary check of\r
67   // making sure that all the addresses (whether or not they will be given\r
68   // to the NIC ) supplied to it are below 4GB. It may or may not use\r
69   // the mapped address after all (like in case of CPB and DB)!\r
70   // Instead of using the global buffer whose address is allocated within the\r
71   // 2GB limit if I start mapping the given buffer we lose the data, here is\r
72   // why!!!\r
73   // if our address is > 4GB, the map call creates another buffer below 2GB and\r
74   // copies data to/from the original buffer to the mapped buffer either at\r
75   // map time or unmap time depending on the map direction.\r
76   // UNDI will not complain since we already mapped the buffer to be\r
77   // within the 2GB limit but will not use (I know undi) the mapped address\r
78   // since it does not give the user buffers to the NIC's receive unit,\r
79   // It just copies the received packet into the user buffer using the virtual\r
80   // (CPU) address rather than the mapped (device or physical) address.\r
81   // When the UNDI call returns, if we then unmap the buffer, we will lose\r
82   // the contents because unmap copies the contents of the mapped buffer into\r
83   // the original buffer (since the direction is FROM_DEVICE) !!!\r
84   //\r
85   // this is not a problem in Undi 3.1 because this undi uses it's map callback\r
86   // routine to map a cpu address to device address and it does it only if\r
87   // it is giving the address to the device and unmaps it before using the cpu\r
88   // address!\r
89   //\r
90   TempData = (UINT64) (UINTN) BufferPtr;\r
91   if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {\r
92     cpb->BufferAddr = (UINT64)(UINTN) snp->receive_buf;\r
93     cpb->BufferLen  = (UINT32) (snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);\r
94   } else {\r
95     cpb->BufferAddr = (UINT64)(UINTN) BufferPtr;\r
96     cpb->BufferLen  = (UINT32) *BuffSizePtr;\r
97   }\r
98 \r
99   cpb->reserved       = 0;\r
100 \r
101   snp->cdb.OpCode     = PXE_OPCODE_RECEIVE;\r
102   snp->cdb.OpFlags    = PXE_OPFLAGS_NOT_USED;\r
103 \r
104   snp->cdb.CPBsize    = sizeof (PXE_CPB_RECEIVE);\r
105   snp->cdb.CPBaddr    = (UINT64)(UINTN) cpb;\r
106 \r
107   snp->cdb.DBsize     = sizeof (PXE_DB_RECEIVE);\r
108   snp->cdb.DBaddr     = (UINT64)(UINTN) db;\r
109 \r
110   snp->cdb.StatCode   = PXE_STATCODE_INITIALIZE;\r
111   snp->cdb.StatFlags  = PXE_STATFLAGS_INITIALIZE;\r
112   snp->cdb.IFnum      = snp->if_num;\r
113   snp->cdb.Control    = PXE_CONTROL_LAST_CDB_IN_LIST;\r
114 \r
115   //\r
116   // Issue UNDI command and check result.\r
117   //\r
118   DEBUG ((EFI_D_NET, "\nsnp->undi.receive ()  "));\r
119 \r
120   (*snp->issue_undi32_command) ((UINT64)(UINTN) &snp->cdb);\r
121 \r
122   switch (snp->cdb.StatCode) {\r
123   case PXE_STATCODE_SUCCESS:\r
124     break;\r
125 \r
126   case PXE_STATCODE_NO_DATA:\r
127     DEBUG (\r
128       (EFI_D_NET,\r
129       "\nsnp->undi.receive ()  %xh:%xh\n",\r
130       snp->cdb.StatFlags,\r
131       snp->cdb.StatCode)\r
132       );\r
133 \r
134     return EFI_NOT_READY;\r
135 \r
136   default:\r
137     DEBUG (\r
138       (EFI_D_ERROR,\r
139       "\nsnp->undi.receive()  %xh:%xh\n",\r
140       snp->cdb.StatFlags,\r
141       snp->cdb.StatCode)\r
142       );\r
143 \r
144     return EFI_DEVICE_ERROR;\r
145   }\r
146 \r
147   *BuffSizePtr = db->FrameLen;\r
148 \r
149   if (HeaderSizePtr != NULL) {\r
150     *HeaderSizePtr = db->MediaHeaderLen;\r
151   }\r
152 \r
153   if (SourceAddrPtr != NULL) {\r
154     CopyMem (SourceAddrPtr, &db->SrcAddr, snp->mode.HwAddressSize);\r
155   }\r
156 \r
157   if (DestinationAddrPtr != NULL) {\r
158     CopyMem (DestinationAddrPtr, &db->DestAddr, snp->mode.HwAddressSize);\r
159   }\r
160 \r
161   if (ProtocolPtr != NULL) {\r
162     *ProtocolPtr = (UINT16) PXE_SWAP_UINT16 (db->Protocol); /*  we need to do the byte swapping */\r
163   }\r
164 \r
165   TempData = (UINT64) (UINTN) BufferPtr;\r
166   if (snp->IsOldUndi && (TempData >= FOUR_GIGABYTES)) {\r
167     CopyMem (BufferPtr, snp->receive_buf, snp->init_info.MediaHeaderLen + snp->init_info.FrameDataLen);\r
168   }\r
169 \r
170   return (*BuffSizePtr <= buf_size) ? EFI_SUCCESS : EFI_BUFFER_TOO_SMALL;\r
171 }\r
172 \r
173 \r
174 /**\r
175   This is the SNP interface routine for receiving network data.\r
176   This routine basically retrieves snp structure, checks the SNP state and\r
177   calls the pxe_receive routine to actually do the receive!\r
178 \r
179   @param  this                context pointer\r
180   @param  HeaderSizePtr       optional parameter and is a pointer to the header\r
181                               portion of the data received.\r
182   @param  BuffSizePtr         is a pointer to the length of the buffer on entry and\r
183                               contains the length of the received data on return\r
184   @param  BufferPtr           pointer to the memory for the received data\r
185   @param  SourceAddrPtr       optional parameter, is a pointer to contain the\r
186                               source ethernet address on return\r
187   @param  DestinationAddrPtr  optional parameter, is a pointer to contain the\r
188                               destination ethernet address on return\r
189   @param  ProtocolPtr         optional parameter, is a pointer to contain the\r
190                               protocol type from the ethernet header on return\r
191 \r
192 \r
193 **/\r
194 EFI_STATUS\r
195 EFIAPI\r
196 snp_undi32_receive (\r
197   IN EFI_SIMPLE_NETWORK_PROTOCOL * this,\r
198   OUT UINTN                      *HeaderSizePtr OPTIONAL,\r
199   IN OUT UINTN                   *BuffSizePtr,\r
200   OUT VOID                       *BufferPtr,\r
201   OUT EFI_MAC_ADDRESS            * SourceAddrPtr OPTIONAL,\r
202   OUT EFI_MAC_ADDRESS            * DestinationAddrPtr OPTIONAL,\r
203   OUT UINT16                     *ProtocolPtr OPTIONAL\r
204   )\r
205 {\r
206   SNP_DRIVER  *snp;\r
207   EFI_TPL     OldTpl;\r
208   EFI_STATUS  Status;\r
209 \r
210   if (this == NULL) {\r
211     return EFI_INVALID_PARAMETER;\r
212   }\r
213 \r
214   snp = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (this);\r
215 \r
216   OldTpl = gBS->RaiseTPL (TPL_CALLBACK);\r
217 \r
218   switch (snp->mode.State) {\r
219   case EfiSimpleNetworkInitialized:\r
220     break;\r
221 \r
222   case EfiSimpleNetworkStopped:\r
223     Status = EFI_NOT_STARTED;\r
224     goto ON_EXIT;\r
225 \r
226   default:\r
227     Status = EFI_DEVICE_ERROR;\r
228     goto ON_EXIT;\r
229   }\r
230 \r
231   if ((BuffSizePtr == NULL) || (BufferPtr == NULL)) {\r
232     Status = EFI_INVALID_PARAMETER;\r
233     goto ON_EXIT;\r
234   }\r
235 \r
236   if (!snp->mode.ReceiveFilterSetting) {\r
237     Status = EFI_DEVICE_ERROR;\r
238     goto ON_EXIT;\r
239   }\r
240 \r
241   Status = pxe_receive (\r
242              snp,\r
243              BufferPtr,\r
244              BuffSizePtr,\r
245              HeaderSizePtr,\r
246              SourceAddrPtr,\r
247              DestinationAddrPtr,\r
248              ProtocolPtr\r
249              );\r
250 \r
251 ON_EXIT:\r
252   gBS->RestoreTPL (OldTpl);\r
253 \r
254   return Status;\r
255 }\r