AF_PACKET 和以太网

AF_PACKET and Ethernet

我很困惑 AF_PACKET 套接字系列(对于 SOCK_RAW 套接字)与以太网 (IEEE 802.3) 的具体关系。

目前我的理解:

不明白的地方:


我的问题:

使用 AF_PACKET 是否意味着您保证 始终 接收具有 14 字节以太网 header 的数据包?

如果是这样,是否也意味着 AF_PACKET 只能用于以太网设备(与其他第 2 层技术相反,如 Wifi、令牌环、蓝牙、Infiniband 等)?

如果这些问题中的任何一个的答案是 ,那么应用程序如何以编程方式确定在接收数据报时预期的第 2 层类型 header AF_PACKET 插座?

警告: 这是因为我为使用 PF_PACKET 的生产软件编写的一些代码进行了蚕食,这些代码仅适用于以太网,因此 可能 为 incomplete/inaccurate.

您正在使用 ETH_P_ALL 为您提供任何东西。但是,有许多 ETH_P_* 符号可供选择(例如 ETH_P_802_3_MIN)。

binding/selection 不仅基于 socket 调用,还基于给定的 接口

首先你需要你想要的接口名称(例如eth0),你可以从ifconfig.

获得列表

然后,使用 ioctl(SIOCGIFINDEX,...) 从接口名称中获取接口 index [或者,您可以硬编码它,因为 ifconfig 会打印出来按索引顺序]。

然后,根据接口索引,bind到那个接口。

既然你知道接口的类型(例如你选择eth0或wifi等),之后,你应该能够消化物理层header因为你知道它是否是struct eth_hdr与否。

请注意,您可以使用许多其他 SIOCGIF* ioctl 来获取接口列表和其他信息,这些信息可以让您辨别接口类型 [以及因此,物理 header期待].

无论如何,这是我所做的一些示例代码:

int
init(const char *intf)
// intf -- interface name (e.g. eth0, etc. -- whatever comes from ifconfig)
{
    int err;

#if 1
    int styp = SOCK_RAW;
#else
    int styp = SOCK_DGRAM;
#endif

    int netsock = socket(PF_PACKET,styp,htons(ETH_P_ALL));

    struct ifreq ifr;
    memset(&ifr,0,sizeof(ifr));
    strncpy(ifr.ifr_name,intf,sizeof(ifr.ifr_name));

    // get the index number of the interface
    err = ioctl(netsock,SIOCGIFINDEX,&ifr);
    if (err < 0)
        do_whatever;

    printf("init: IFRIDX ifr_ifindex=%d\n",ifr.ifr_ifindex);
    int ifidx = ifr.ifr_ifindex;

    struct sockaddr_ll addr;
    addr.sll_family = AF_PACKET;
    addr.sll_protocol = htons(ETH_P_ALL);
    addr.sll_ifindex = ifidx;

    err = bind(netsock,(struct sockaddr *) &addr,
        sizeof(struct sockaddr_ll));
    if (err < 0)
        do_whatever;

    return netsock;
}