]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeNetLib/NetDebug.c
Fixed EBC build issues.
[mirror_edk2.git] / MdeModulePkg / Library / DxeNetLib / NetDebug.c
CommitLineData
8a67d61d 1/** @file\r
2\r
3Copyright (c) 2005 - 2006, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 NetDebug.c\r
15\r
16Abstract:\r
17\r
18 Network debug facility. The debug information is wrapped in\r
19 SYSLOG packets, then sent over SNP. This debug facility can't\r
20 be used by SNP. Apply caution when used in MNP and non-network\r
21 module because SNP is most likely not "thread safe". We assume\r
22 that the SNP supports the EHTERNET.\r
23\r
24\r
25**/\r
26\r
27\r
28#include <PiDxe.h>\r
29\r
30#include <Protocol/SimpleNetwork.h>\r
31\r
32#include <Library/BaseLib.h>\r
33#include <Library/NetLib.h>\r
34#include <Library/UefiBootServicesTableLib.h>
35#include <Library/UefiRuntimeServicesTableLib.h>\r
36#include <Library/MemoryAllocationLib.h>\r
37#include <Library/BaseMemoryLib.h>\r
38#include <Library/PrintLib.h>\r
39\r
40\r
41//\r
42// Any error level digitally larger than mNetDebugLevelMax\r
43// will be silently discarded.\r
44//\r
45UINTN mNetDebugLevelMax = NETDEBUG_LEVEL_ERROR;\r
46UINT32 mSyslogPacketSeq = 0xDEADBEEF;\r
47\r
48//\r
49// You can change mSyslogDstMac mSyslogDstIp and mSyslogSrcIp\r
50// here to direct the syslog packets to the syslog deamon. The\r
51// default is broadcast to both the ethernet and IP.\r
52//\r
53UINT8 mSyslogDstMac [NET_ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};\r
54UINT32 mSyslogDstIp = 0xffffffff;\r
55UINT32 mSyslogSrcIp = 0;\r
56\r
57UINT8 *\r
58MonthName[] = {\r
59 "Jan",\r
60 "Feb",\r
61 "Mar",\r
62 "Apr",\r
63 "May",\r
64 "Jun",\r
65 "Jul",\r
66 "Aug",\r
67 "Sep",\r
68 "Oct",\r
69 "Nov",\r
70 "Dec"\r
71};\r
72\r
73\r
74/**\r
75 Locate the handles that support SNP, then open one of them\r
76 to send the syslog packets. The caller isn't required to close\r
77 the SNP after use because the SNP is opened by HandleProtocol.\r
78\r
79 None\r
80\r
81 @return The point to SNP if one is properly openned. Otherwise NULL\r
82\r
83**/\r
84EFI_SIMPLE_NETWORK_PROTOCOL *\r
85SyslogLocateSnp (\r
86 VOID\r
87 )\r
88{\r
89 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
90 EFI_STATUS Status;\r
91 EFI_HANDLE *Handles;\r
92 UINTN HandleCount;\r
93 UINTN Index;\r
94\r
95 //\r
96 // Locate the handles which has SNP installed.\r
97 //\r
98 Handles = NULL;\r
99 Status = gBS->LocateHandleBuffer (\r
100 ByProtocol,\r
101 &gEfiSimpleNetworkProtocolGuid,\r
102 NULL,\r
103 &HandleCount,\r
104 &Handles\r
105 );\r
106\r
107 if (EFI_ERROR (Status) || (HandleCount == 0)) {\r
108 return NULL;\r
109 }\r
110\r
111 //\r
112 // Try to open one of the ethernet SNP protocol to send packet\r
113 //\r
114 Snp = NULL;\r
115\r
116 for (Index = 0; Index < HandleCount; Index++) {\r
117 Status = gBS->HandleProtocol (\r
118 Handles[Index],\r
119 &gEfiSimpleNetworkProtocolGuid,\r
120 (VOID **) &Snp\r
121 );\r
122\r
123 if ((Status == EFI_SUCCESS) && (Snp != NULL) &&\r
124 (Snp->Mode->IfType == NET_IFTYPE_ETHERNET) &&\r
125 (Snp->Mode->MaxPacketSize >= NET_SYSLOG_PACKET_LEN)) {\r
126\r
127 break;\r
128 }\r
129\r
130 Snp = NULL;\r
131 }\r
132\r
133 gBS->FreePool (Handles);\r
134 return Snp;\r
135}\r
136\r
137\r
138/**\r
139 Transmit a syslog packet synchronously through SNP. The Packet\r
140 already has the ethernet header prepended. This function should\r
141 fill in the source MAC because it will try to locate a SNP each\r
142 time it is called to avoid the problem if SNP is unloaded.\r
143 This code snip is copied from MNP.\r
144\r
145 @param Packet The Syslog packet\r
146 @param Length The length of the packet\r
147\r
148 @retval EFI_DEVICE_ERROR Failed to locate a usable SNP protocol\r
149 @retval EFI_TIMEOUT Timeout happened to send the packet.\r
150 @retval EFI_SUCCESS Packet is sent.\r
151\r
152**/\r
153EFI_STATUS\r
154SyslogSendPacket (\r
155 IN UINT8 *Packet,\r
156 IN UINT32 Length\r
157 )\r
158{\r
159 EFI_SIMPLE_NETWORK_PROTOCOL *Snp;\r
160 ETHER_HEAD *Ether;\r
161 EFI_STATUS Status;\r
162 EFI_EVENT TimeoutEvent;\r
163 UINT8 *TxBuf;\r
164\r
165 Snp = SyslogLocateSnp ();\r
166\r
167 if (Snp == NULL) {\r
168 return EFI_DEVICE_ERROR;\r
169 }\r
170\r
171 Ether = (ETHER_HEAD *) Packet;\r
172 CopyMem (Ether->SrcMac, Snp->Mode->CurrentAddress.Addr, NET_ETHER_ADDR_LEN);\r
173\r
174 //\r
175 // Start the timeout event.\r
176 //\r
177 Status = gBS->CreateEvent (\r
178 EVT_TIMER,\r
179 TPL_NOTIFY,\r
180 NULL,\r
181 NULL,\r
182 &TimeoutEvent\r
183 );\r
184\r
185 if (EFI_ERROR (Status)) {\r
186 return Status;\r
187 }\r
188\r
189 Status = gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);\r
190\r
191 if (EFI_ERROR (Status)) {\r
192 goto ON_EXIT;\r
193 }\r
194\r
195 for (;;) {\r
196 //\r
197 // Transmit the packet through SNP.\r
198 //\r
199 Status = Snp->Transmit (Snp, 0, Length, Packet, NULL, NULL, NULL);\r
200\r
201 if ((Status != EFI_SUCCESS) && (Status != EFI_NOT_READY)) {\r
202 Status = EFI_DEVICE_ERROR;\r
203 break;\r
204 }\r
205\r
206 //\r
207 // If Status is EFI_SUCCESS, the packet is put in the transmit queue.\r
208 // if Status is EFI_NOT_READY, the transmit engine of the network\r
209 // interface is busy. Both need to sync SNP.\r
210 //\r
211 TxBuf = NULL;\r
212\r
213 do {\r
214 //\r
215 // Get the recycled transmit buffer status.\r
216 //\r
4eb65aff 217 Snp->GetStatus (Snp, NULL, (VOID **) &TxBuf);\r
8a67d61d 218\r
219 if (!EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {\r
220 Status = EFI_TIMEOUT;\r
221 break;\r
222 }\r
223\r
224 } while (TxBuf == NULL);\r
225\r
226 if ((Status == EFI_SUCCESS) || (Status == EFI_TIMEOUT)) {\r
227 break;\r
228 }\r
229\r
230 //\r
231 // Status is EFI_NOT_READY. Restart the timer event and\r
232 // call Snp->Transmit again.\r
233 //\r
234 gBS->SetTimer (TimeoutEvent, TimerRelative, NET_SYSLOG_TX_TIMEOUT);\r
235 }\r
236\r
237 gBS->SetTimer (TimeoutEvent, TimerCancel, 0);\r
238\r
239ON_EXIT:\r
240 gBS->CloseEvent (TimeoutEvent);\r
241 return Status;\r
242}\r
243\r
244\r
245/**\r
246 Compute checksum for a bulk of data. This code is copied from the\r
247 Netbuffer library.\r
248\r
249 @param Bulk Pointer to the data.\r
250 @param Len Length of the data, in bytes.\r
251\r
252 @retval UINT16 The computed checksum.\r
253\r
254**/\r
255UINT16\r
256SyslogChecksum (\r
257 IN UINT8 *Bulk,\r
258 IN UINT32 Len\r
259 )\r
260{\r
261 register UINT32 Sum;\r
262\r
263 Sum = 0;\r
264\r
265 while (Len > 1) {\r
266 Sum += *(UINT16 *) Bulk;\r
267 Bulk += 2;\r
268 Len -= 2;\r
269 }\r
270\r
271 //\r
272 // Add left-over byte, if any\r
273 //\r
274 if (Len > 0) {\r
275 Sum += *(UINT8 *) Bulk;\r
276 }\r
277\r
278 //\r
279 // Fold 32-bit sum to 16 bits\r
280 //\r
281 while (Sum >> 16) {\r
282 Sum = (Sum & 0xffff) + (Sum >> 16);\r
283 }\r
284\r
285 return (UINT16) ~Sum;\r
286}\r
287\r
288\r
289/**\r
290 Build a syslog packet, including the Ethernet/Ip/Udp headers\r
291 and user's message.\r
292\r
293 @param Buf The buffer to put the packet data\r
294 @param BufLen The lenght of the Buf\r
295 @param Level Syslog servity level\r
296 @param Module The module that generates the log\r
297 @param File The file that contains the current log\r
298 @param Line The line of code in the File that contains the\r
299 current log\r
300 @param Message The log message\r
301\r
302 @return The length of the syslog packet built.\r
303\r
304**/\r
305UINT32\r
306SyslogBuildPacket (\r
307 UINT8 *Buf,\r
308 UINT32 BufLen,\r
309 UINT32 Level,\r
310 UINT8 *Module,\r
311 UINT8 *File,\r
312 UINT32 Line,\r
313 UINT8 *Message\r
314 )\r
315{\r
316 ETHER_HEAD *Ether;\r
317 IP4_HEAD *Ip4;\r
318 EFI_UDP4_HEADER *Udp4;\r
319 EFI_TIME Time;\r
320 UINT32 Pri;\r
321 UINT32 Len;\r
322\r
323 //\r
324 // Fill in the Ethernet header. Leave alone the source MAC.\r
325 // SyslogSendPacket will fill in the address for us.\r
326 //\r
327 Ether = (ETHER_HEAD *) Buf;\r
328 CopyMem (Ether->DstMac, mSyslogDstMac, NET_ETHER_ADDR_LEN);\r
329 ZeroMem (Ether->SrcMac, NET_ETHER_ADDR_LEN);\r
330\r
331 Ether->EtherType = HTONS (0x0800); // IP protocol\r
332\r
333 Buf += sizeof (ETHER_HEAD);\r
334 BufLen -= sizeof (ETHER_HEAD);\r
335\r
336 //\r
337 // Fill in the IP header\r
338 //\r
339 Ip4 = (IP4_HEAD *) Buf;\r
340 Ip4->HeadLen = 5;\r
341 Ip4->Ver = 4;\r
342 Ip4->Tos = 0;\r
343 Ip4->TotalLen = 0;\r
344 Ip4->Id = (UINT16) mSyslogPacketSeq;\r
345 Ip4->Fragment = 0;\r
346 Ip4->Ttl = 16;\r
347 Ip4->Protocol = 0x11;\r
348 Ip4->Checksum = 0;\r
349 Ip4->Src = mSyslogSrcIp;\r
350 Ip4->Dst = mSyslogDstIp;\r
351\r
352 Buf += sizeof (IP4_HEAD);\r
353 BufLen -= sizeof (IP4_HEAD);\r
354\r
355 //\r
356 // Fill in the UDP header, Udp checksum is optional. Leave it zero.\r
357 //\r
358 Udp4 = (EFI_UDP4_HEADER*) Buf;\r
359 Udp4->SrcPort = HTONS (514);\r
360 Udp4->DstPort = HTONS (514);\r
361 Udp4->Length = 0;\r
362 Udp4->Checksum = 0;\r
363\r
364 Buf += sizeof (EFI_UDP4_HEADER);\r
365 BufLen -= sizeof (EFI_UDP4_HEADER);\r
366\r
367 //\r
368 // Build the syslog message body with <PRI> Timestamp machine module Message\r
369 //\r
370 Pri = ((NET_SYSLOG_FACILITY & 31) << 3) | (Level & 7);\r
371 gRT->GetTime (&Time, NULL);\r
372\r
373 //\r
374 // Use %a to format the ASCII strings, %s to format UNICODE strings\r
375 //\r
376 Len = 0;\r
377 Len += (UINT32) AsciiSPrint (\r
4eb65aff 378 (CHAR8 *) Buf,\r
8a67d61d 379 BufLen,\r
380 "<%d> %a %d %d:%d:%d ",\r
381 Pri,\r
382 MonthName [Time.Month-1],\r
383 Time.Day,\r
384 Time.Hour,\r
385 Time.Minute,\r
386 Time.Second\r
387 );\r
388 Len--;\r
389\r
390 Len += (UINT32) AsciiSPrint (\r
4eb65aff 391 (CHAR8 *) (Buf + Len),\r
8a67d61d 392 BufLen - Len,\r
393 "Tiano %a: %a (Line: %d File: %a)",\r
394 Module,\r
395 Message,\r
396 Line,\r
397 File\r
398 );\r
399 Len--;\r
400\r
401 //\r
402 // OK, patch the IP length/checksum and UDP length fields.\r
403 //\r
404 Len += sizeof (EFI_UDP4_HEADER);\r
405 Udp4->Length = HTONS ((UINT16) Len);\r
406\r
407 Len += sizeof (IP4_HEAD);\r
408 Ip4->TotalLen = HTONS ((UINT16) Len);\r
409 Ip4->Checksum = SyslogChecksum ((UINT8 *) Ip4, sizeof (IP4_HEAD));\r
410\r
411 return Len + sizeof (ETHER_HEAD);\r
412}\r
413\r
414\r
415/**\r
416 Allocate a buffer, then format the message to it. This is a\r
417 help function for the NET_DEBUG_XXX macros. The PrintArg of\r
418 these macros treats the variable length print parameters as a\r
419 single parameter, and pass it to the NetDebugASPrint. For\r
420 example, NET_DEBUG_TRACE ("Tcp", ("State transit to %a\n", Name))\r
421 if extracted to:\r
422 NetDebugOutput (\r
423 NETDEBUG_LEVEL_TRACE,\r
424 "Tcp",\r
425 __FILE__,\r
426 __LINE__,\r
427 NetDebugASPrint ("State transit to %a\n", Name)\r
428 )\r
429 This is exactly what we want.\r
430\r
431 @param Format The ASCII format string.\r
432 @param ... The variable length parameter whose format is\r
433 determined by the Format string.\r
434\r
435 @return The buffer containing the formatted message, or NULL if failed to\r
436 @return allocate memory.\r
437\r
438**/\r
439UINT8 *\r
440NetDebugASPrint (\r
441 UINT8 *Format,\r
442 ...\r
443 )\r
444{\r
445 VA_LIST Marker;\r
446 UINT8 *Buf;\r
447\r
448 Buf = AllocatePool (NET_DEBUG_MSG_LEN);\r
449\r
450 if (Buf == NULL) {\r
451 return NULL;\r
452 }\r
453\r
454 VA_START (Marker, Format);\r
4eb65aff 455 AsciiVSPrint ((CHAR8 *) Buf, NET_DEBUG_MSG_LEN, (CHAR8 *) Format, Marker);\r
8a67d61d 456 VA_END (Marker);\r
457\r
458 return Buf;\r
459}\r
460\r
461\r
462/**\r
463 Output a debug message to syslog. This function will locate a\r
464 instance of SNP then send the message through it. Because it\r
465 isn't open the SNP BY_DRIVER, apply caution when using it.\r
466\r
467 @param Level The servity level of the message.\r
468 @param Module The Moudle that generates the log.\r
469 @param File The file that contains the log.\r
470 @param Line The exact line that contains the log.\r
471 @param Message The user message to log.\r
472\r
473 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory for the packet\r
474 @retval EFI_SUCCESS The log is discard because that it is more verbose\r
475 than the mNetDebugLevelMax. Or, it has been sent\r
476 out.\r
477\r
478**/\r
479EFI_STATUS\r
480NetDebugOutput (\r
481 UINT32 Level,\r
482 UINT8 *Module,\r
483 UINT8 *File,\r
484 UINT32 Line,\r
485 UINT8 *Message\r
486 )\r
487{\r
488 UINT8 *Packet;\r
489 UINT32 Len;\r
490 EFI_STATUS Status;\r
491\r
492 //\r
493 // Check whether the message should be sent out\r
494 //\r
495 if (Message == NULL) {\r
496 return EFI_OUT_OF_RESOURCES;\r
497 }\r
498\r
499 if (Level > mNetDebugLevelMax) {\r
500 Status = EFI_SUCCESS;\r
501 goto ON_EXIT;\r
502 }\r
503\r
504 //\r
505 // Allocate a maxium of 1024 bytes, the caller should ensure\r
506 // that the message plus the ethernet/ip/udp header is shorter\r
507 // than this\r
508 //\r
509 Packet = AllocatePool (NET_SYSLOG_PACKET_LEN);\r
510\r
511 if (Packet == NULL) {\r
512 Status = EFI_OUT_OF_RESOURCES;\r
513 goto ON_EXIT;\r
514 }\r
515\r
516 //\r
517 // Build the message: Ethernet header + IP header + Udp Header + user data\r
518 //\r
519 Len = SyslogBuildPacket (\r
520 Packet,\r
521 NET_SYSLOG_PACKET_LEN,\r
522 Level,\r
523 Module,\r
524 File,\r
525 Line,\r
526 Message\r
527 );\r
528\r
529 mSyslogPacketSeq++;\r
530 Status = SyslogSendPacket (Packet, Len);\r
531 gBS->FreePool (Packet);\r
532\r
533ON_EXIT:\r
534 gBS->FreePool (Message);\r
535 return Status;\r
536}\r