gpt4 book ai didi

c - 如何在不使用 sockaddr_ll 的情况下使用 sendto 通过原始以太网套接字发送数据?

转载 作者:太空狗 更新时间:2023-10-29 17:26:05 27 4
gpt4 key购买 nike

我正在开展一个项目,我们使用 Enea OSE,这是一个实时嵌入式操作系统。我想你们中的许多人都不熟悉这个操作系统,但我认为您无论如何都可以回答我的问题。我想使用接口(interface)“eth1”在两张卡之间发送一个原始以太网帧,这些接口(interface)通过以太网电缆直接连接到另一张(没有交换机或任何东西)。 “eth1”接口(interface)未分配任何 ip 地址。

我可以简单地声明一个套接字使用

int s = socket(AF_INET, RAW_SOCKET, ...)

然后我可以使用以下方法将套接字绑定(bind)到适当的设备接口(interface):

setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, "eth1", 4);

为了将数据从一张卡发送到另一张卡,我的计划是手动用源和目标 MAC 地址填充以太网缓冲区数组。然后使用 sendto(....) 发送数据

然而,sendto 例程还需要一个包含信息的 sockaddr 结构:

  sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);

在我在互联网上找到的示例中,当 IP 地址已知时使用 sockaddr_in,对于原始帧使用 sockaddr_ll。但是 OSE 不提供 sockaddr_ll 结构。但是它提供了 sockaddr ,我不知道我是否可以将其用于原始以太网帧?

struct sockaddr {
unsigned short sa_family; // address family, AF_xxx
char sa_data[14]; // 14 bytes of protocol address
};

我也试过用NULL,调用sendto()时sockaddr字段,发送失败。这让我想到了我的问题。我可以在不使用任何 IP 的情况下使用简单的 sockaddr 结构来填充目标 MAC 地址吗?那看起来怎么样? (我还没有看到任何代码显示这一点)。为什么我们甚至必须提供一个 sockaddr 结构?以太网数据缓冲区不是已经包含此信息了吗?最后,在不为网络设备分配 IP 地址的情况下,我想要实现的目标是否可行?

我知道我正在尝试做的事情看起来很奇怪,但这是有原因的 :) 如果您能告诉我如何在不使用 sockaddr_ll 结构。

最佳答案

对之前模糊的回答感到抱歉。这是我的完整答案。希望对您有所帮助。

回答您的问题:是的,您可以只使用 MAC 地址发送。

像这样声明套接字:

int sockfd = socket(AF_PACKET, SOCK_RAW, IPPROTO_RAW)

出错时,套接字文件描述符 sockfd 将返回 -1。

以太网帧的结构可以这样构造:

struct ethernet_msg{
char destination_mac[6];
char source_mac[6];
char transport_protocol[2];
char data1[6];
char data2[6];
char data3[8];
char data4[8];
char data5[8];
char data6[2];
char data7[2];
char data8[6];
char data9[4];
char data10[6];
};
struct ethernet_msg my_msg = {
{0x91, 0xe0, 0xf0, 0x01, 0x00, 0x00},//destination_mac
{0x08, 0x00, 0x27, 0x90, 0x5f, 0xae},//source_mac
{0x22, 0xf0},//transport_protocol
{0xfc, 0x06, 0x00, 0x2c, 0x00, 0x00},//data1
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//data2
{0x08, 0x00, 0x27, 0xff, 0xfe, 0x90, 0x5f, 0xae},//data3
{0xd8, 0x80, 0x39, 0xff, 0xfe, 0xd0, 0xac, 0xb5},//data4
{0xd8, 0x80, 0x39, 0xff, 0xfe, 0xd0, 0x9b, 0xc8},//data5
{0x00, 0x00},//data6
{0x00, 0x00},//data7
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},//data8
{0x00, 0x00, 0x00, 0x5f},//data9
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00}//data10
};

请注意我是如何将不同长度的字符数组放入框架内的。您可以根据自己的需要进行设置。要获取要发送的接口(interface)的 MAC 地址:

void get_interface_MAC(char interface_name[IFNAMSIZ], int sockfd)
{
struct ifreq if_mac;
memset(&if_mac, 0, sizeof(struct ifreq));
strncpy(if_mac.ifr_name, interface_name, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFHWADDR, &if_mac) < 0)
perror("SIOCGIFHWADDR");
}

然后获取网络设备的索引:

/* Get the index of the interface to send on */
int get_interface_index(char interface_name[IFNAMSIZ], int sockfd)
{
struct ifreq if_idx;
memset(&if_idx, 0, sizeof(struct ifreq));
strncpy(if_idx.ifr_name, interface_name, IFNAMSIZ-1);
if (ioctl(sockfd, SIOCGIFINDEX, &if_idx) < 0)
perror("SIOCGIFINDEX");

return if_idx.ifr_ifindex;
}

socket_address.sll_ifindex = get_interface_index(interface_name, sockfd);
/* Address length*/
socket_address.sll_halen = ETH_ALEN;
/* Destination MAC */
memcpy(socket_address.sll_addr, avdecc_msg.destination_mac, ETH_ALEN);

然后最终通过套接字发送:

/* Send packet */
if (sendto(sockfd, &avdecc_msg, sizeof(avdecc_msg), 0, (struct sockaddr*)&socket_address, sizeof(struct sockaddr_ll)) < 0)
printf("Send failed\n");

希望对您有所帮助。我用了这个 link并完善代码以实现这一目标。它对我有用。

关于c - 如何在不使用 sockaddr_ll 的情况下使用 sendto 通过原始以太网套接字发送数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21411851/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com