我正在使用Enea OSE并希望通过打开原始套接字来发送没有任何IP的原始以太网帧。请注意,OSE使用的NetBSD堆栈似乎与Linux堆栈略有不同。
问题是我没有在OSE中找到任何好的示例,但是基本上存在相同的方法用于打开套接字并发送( sendto )等。但是* sockaddr_ll * struct哪个在Linux中用于发送OSE中不存在的原始以太网帧。但我找到了另一个结构,* sockaddr_dl *基本上似乎有相同的字段:
struct sockaddr_dl
{
uint8_t sdl_len;
sa_family_t sdl_family; //AF_LINK
uint16_t sdl_index;
uint8_t sdl_type;
uint8_t sdl_nlen;
uint8_t sdl_alen;
uint8_t sdl_slen;
char sdl_data[12];
}
我找到一篇讨论Linux和NetBSD堆栈之间差异的文章http://sock-raw.org/papers/sock_raw
我可以在没有任何错误的情况下打开套接字,但 sendto()函数失败,错误值 22,无效参数。问题可能是什么?我用这个错误读过的所有线程都是人们在指针上使用 sizeof 时并不小心,但这不是我想的那样。当然我不确定sockaddr_dl结构是否适合原始套接字,也许它可能存在一些问题?也许以太网缓冲区没有正确填写?另请注意,Linux中使用的套接字是以下列方式打开的:
int sock = socket(AF_PACKET, SOCK_RAW, ...)
但由于AF_PACKET未包含在OSE中,因此无法实现。从上面的文章看来,应该打开一个原始套接字,如下面的代码所示。
int sockfd;
char sendbuf[FRAME_SIZE];
int tx_len = FRAME_SIZE;
/* Open RAW socket to send on */
if ((sockfd = socket(AF_INET, SOCK_RAW, 0)) == -1) {
printf("Error when opening socket: %s\n", strerror(errno));
}
/*Fill sockaddr_dl struct (Link - Layer)*/
unsigned char src_mac[6] = {0x00, 0x80, 0x81, 0x82, 0x83, 0x84};
unsigned char dst_mac[6] = {0x00, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e};
struct sockaddr_dl sock_test;
memset(&sock_test, 0, sizeof (struct sockaddr_dl));
sock_test.sdl_family = AF_LINK;
sock_test.sdl_len = sizeof (struct sockaddr_dl);
sock_test.sdl_index = 0;
sock_test.sdl_type = IFT_ETHER;
sock_test.sdl_alen = ETH_LEN; //ETHER_ADDR_LEN = 6;
sock_test.sdl_data[0] = dst_mac[0];
sock_test.sdl_data[1] = dst_mac[1];
sock_test.sdl_data[2] = dst_mac[2];
sock_test.sdl_data[3] = dst_mac[3];
sock_test.sdl_data[4] = dst_mac[4];
sock_test.sdl_data[5] = dst_mac[5];
/*Fill in ethernet frame*/
unsigned char ether_type[2] = {0x08, 0x00};
memset((void*)sendbuf, 0, FRAME_SIZE); //Clear buffer
memcpy((void*)sendbuf, (void*)dst_mac, ETH_LEN);
memcpy((void*) (sendbuf+ETH_LEN), (void*)src_mac, ETH_LEN);
memcpy((void*) (sendbuf+2*ETH_LEN), (void*)ether_type, 2);
int status = sendto(sockfd, sendbuf, tx_len, 0, (struct sockaddr*)&sock_test, (socklen_t)sizeof(sock_test));
if(status < 0){
printf("Error: %s :::: with value %d\n", strerror(errno), errno);
}
else
printf("SENT DONE!!! \n");
欢迎任何建议!
答案 0 :(得分:0)
Linux AF_PACKET代码已移植到BSD bpf,例如:
替换
int sock = socket(AF_PACKET, SOCK_RAW, protocol);
使用
int sock = open(filename, O_RDWR);
文件名以“ / dev / bpf0”开头
将ioctl替换为
ioctl(sock, BIOCSETIF, ...) # bind interface
ioctl(sock, BIOCIMMEDIATE, ...) # enable "immediate mode"
ioctl(sock, BIOCSETF, ...) # set bpf program
使用bpf程序,例如:
struct bpf_insn bf_insn[] = {
/* Make sure this is a protocol packet... */
BPF_STMT(BPF_LD + BPF_H + BPF_ABS, 12),
BPF_JUMP(BPF_JMP + BPF_JEQ + BPF_K, protocol, 0, 1),
/* If we passed all the tests, ask for the whole packet. */
BPF_STMT(BPF_RET+BPF_K, (u_int)-1),
/* Otherwise, drop it. */
BPF_STMT(BPF_RET+BPF_K, 0),
};
struct bpf_program bf_program = {
sizeof (bf_insn) / (sizeof bf_insn[0]),
bf_insn
};
请注意bpf程序中的协议参数,该参数用于
int sock = socket(AF_PACKET, SOCK_RAW, protocol);
将recv()和send()替换为read()和write()
请注意,除非使用fcntl()为套接字设置了O_NONBLOCK,否则read()和write()将会被阻塞