在 
UEFI 下,想要撰寫 TCP / IP 的程式,說難不是太難,說簡單也不是很簡單。
簡單來說,如果很久以前曾在 Linux or Unix 下寫過 socket 程式,那我想這就不是一件很難的事,只要注意一些 header 檔案的位置跟傳統的不一樣即可。
 
從上圖可以得知,要在 UEFI Shell 下使用網路,需具備 4 要件:
1. 要有網卡。
2. 要有 UNDI driver。
3. 載入 Simple Network Protocol。
4. 載入 TCP / IP Stack。
註:從 Intel 的文件 "
UEFI Driver Development Guide
for Network Boot Devices" 來看,
SNP 和 
TCP / IP Stack 中間似乎還有一層 
MNP ( Managed Network Protocol ),不過這邊我們可以先忽略它。
以我的小電腦來說,除了 Simple Network Protocol 以外,其餘皆已內建,故我從 UDK2014 code base 中 build 出此 driver 即可﹝
C:\edk2-UDK2014\MdeModulePkg\Universal\Network﹞,接著開機時,使用 "
load" command 載入 driver,便可以順利使用 "
ifconfig" command 取得 IP。
再來就是跟以前撰寫 socket 程式一樣,呼叫 socket, connect, send, close 等函式完成想要完成的工作,底下為 Client 端發送封包的例子。
2025/06/14 更新
拿掉之前的測試程式,因為只是範例,連 main 都沒有。
TCPClient.c
//#include  <Uefi.h>
//#include  <Library/UefiLib.h>
//#include  <Library/ShellCEntryLib.h>
#include <netinet/in.h>
#include <sys/EfiSysCall.h>
//#include <sys/endian.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int
testTCPSocket (
  IN unsigned long serverIP,
  IN int serverPort
  )
{
    int rc;
    int sock;
    struct sockaddr_in v4;
    char data[1024];
    size_t sent_bytes;
    size_t sendstrlen;
    sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    //sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_TCP);
    if (sock == -1)
    {
        printf("init socket error\n");
        return -1;
    }
    memset(&v4, 0x00, sizeof(v4));
    v4.sin_len = sizeof(v4);
    v4.sin_family = AF_INET;
    v4.sin_addr.s_addr = serverIP;
    v4.sin_port = htons(serverPort);
    rc = connect(sock, (struct sockaddr*)&v4, sizeof(v4));
    if (rc == -1)
    {
        printf("connect() failed (%d)\n", rc);
        //return -1;
    }
    printf("input string to send or 'q' to exit connection\n");
    while (1)
    {
        memset(data, 0x00, sizeof(data));
        //scanf("%s", data);
        fgets(data, sizeof(data) - 1, stdin);
        if (data[0] == 'q')
        {
            printf("ready to exit connection\n");
            break;
        }
        sendstrlen = strlen(data);
        if (sendstrlen > 0 && sendstrlen < 1023)
        {
            sent_bytes = send(sock, data, sendstrlen, 0);
            printf("\t !!! Sent data: %s(%d) --- \n", data, sent_bytes);
        }
    }
    close(sock);
    return 0;
}
unsigned long
getServerIP (
  IN int Argc,
  IN char **Argv
  )
{
    UINT32 ip[4];
    int rc;
    unsigned long serverIP;
    int i;
    if (Argc < 2)
    {
        return 0;
    }
    rc = sscanf(Argv[1], "%d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]);
    if (rc != 4)
    {
        return 0;
    }
    for (i = 0; i < 4; i++)
    {
        if (ip[i] > 255 || ip[i] < 0)
        {
            return 0;
        }
    }
    serverIP = (ip[3] << 24)
             | (ip[2] << 16)
             | (ip[1] << 8)
             |  ip[0];
    return serverIP;
}
int
main (
  IN int Argc,
  IN char **Argv
  )
{
    unsigned long serverIP;
    int serverPort;
    int rc;
    if (Argc != 3)
    {
        printf("error argv \n");
        printf("TCPClient 127.0.0.1 8080\n");
        return 0;
    }
    serverIP = inet_addr(Argv[1]);
    //serverIP = getServerIP(Argc, Argv);
    serverPort = atoi(Argv[2]);
    printf("TCPClient Start \n");
    rc = testTCPSocket(serverIP, serverPort);
    printf("Send Socket (%d)\n", rc);
    return 0;
}
TCPClient.inf
## @file
#   A simple, basic, application showing how the Hello application could be
#   built using the "Standard C Libraries" from StdLib.
#
#  Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
#  This program and the accompanying materials
#  are licensed and made available under the terms and conditions of the BSD License
#  which accompanies this distribution. The full text of the license may be found at
#  http://opensource.org/licenses/bsd-license.
#
#  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
#  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
##
[Defines]
  INF_VERSION                    = 0x00010006
  BASE_NAME                      = TCPClient
  FILE_GUID                      = 60a0b517-eb12-444d-8792-f6368622f9cb
  MODULE_TYPE                    = UEFI_APPLICATION
  VERSION_STRING                 = 0.1
  ENTRY_POINT                    = ShellCEntryLib
#
#  VALID_ARCHITECTURES           = IA32 X64 IPF
#
[Sources]
  TCPClient.c
[Packages]
  StdLib/StdLib.dec
  MdePkg/MdePkg.dec
  ShellPkg/ShellPkg.dec
[LibraryClasses]
  BsdSocketLib
  EfiSocketLib
  LibC
  LibNetUtil
[Protocols]
[BuildOptions]
  INTEL:*_*_*_CC_FLAGS = /Qdiag-disable:181,186
   MSFT:*_*_*_CC_FLAGS = /Od
    GCC:*_*_*_CC_FLAGS = -O0 -Wno-unused-variable