[技術] 在Linux User-Space下實做L3 Protocol

Written on 4:01 下午 by Yu Lai

其實這篇應該是要接續上一篇寫的,因為用到的方法是和上一篇相同
的,但由於主題比較不太一樣,所以就分開來寫了。

在Linux中,一般要實做新的L3 protocol,大都是從kernel去下手,
效能較好,能存取的資源也比較多。但在開發embedded system下往
往有專案時間壓力以及軟體彈性的需求,去改kernel來達到這些要求
也就有點不太實際。所以我採用了在上一篇中使用的方法,也就是
Raw Socket與LPF(Linux Packet Filter)來完成一個L3 Protocol的
實做。

和Sniffer一樣的,我們使用了Raw Socket與LPF,比較不同的地方在
於LPF所使用的Filter。由於我們的protocol是定義成採用0x1219的
ether type,所以在配合tcpdump生成BPF code時用了以下的指令。

# tcpdump -dd -s 2048 ether proto 0x1219
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 1, 0x00001219 },
{ 0x6, 0, 0, 0x00000800 },
{ 0x6, 0, 0, 0x00000000 }

以下是部份的實做的程式碼:

#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <net/if.h>
#include <netinet/in.h>
#include <linux/types.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/filter.h>
#include <linux/sockios.h>


void *mcpV2Handler(void *arg) {

int sock, n;
int rr;
U8 buf[2048];
U8 tmp[8], tmpSlot;
U8 lastBegMac[6];
U32 lastBegTime = 0;
U32 * pGroupKey;
tMcpFrame *frame;
tMcpPacket *packet;
tMcpCardInfo *cardInfo;
pthread_t mcpV2Sender_tid;
pthread_t mcpV2TxRx_tid;
struct sock_fprog filter;

/* Using tcpdump to generate BPF code */
/*
# tcpdump -d -s 2048 ether proto 0x1219
(000) ldh [12]
(001) jeq #0x1219 jt 2 jf 3
(002) ret #2048
(003) ret #0
*/
struct sock_filter bpf_code[]= {
{ 0x28, 0, 0, 0x0000000c },
{ 0x15, 0, 1, 0x00001219 },
{ 0x6, 0, 0, 0x00000800 },
{ 0x6, 0, 0, 0x00000000 }
};

filter.len = sizeof(bpf_code)/sizeof(bpf_code[0]);
filter.filter = bpf_code;

/* set detached thread */
pthread_detach(pthread_self());

if ((sock=socket(PF_PACKET, SOCK_PACKET, htons(ETH_P_ALL)))<0) {
perror("socket");
exit(1);
}

/* Attach the bpf filter to the socket */
if (setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter))<0){
perror("setsockopt");
close(sock);
exit(1);
}

/* ----------- Start implement ----------- */

while(1) {
n = recvfrom(sock, buf, sizeof(buf), 0, NULL, NULL);
if(n < 22) { /* 6+6+2+2+4+2+N */
printf("invalid packet\n");
continue;
}

frame = (tMcpFrame *)buf;

if(memcmp(frame->srcAddr, myMac, 6) == 0)
continue;

MCP_LOG("Dump: %02x%02x%02x%02x%02x%02x|"
"%02x%02x%02x%02x%02x%02x|"
"%04x|%04x|%08x|%04x|"
"%02x %02x %02x %02x %02x %02x %02x %02x %02x",
frame->dstAddr[0], frame->dstAddr[1], frame->dstAddr[2],
frame->dstAddr[3], frame->dstAddr[4], frame->dstAddr[5],
frame->srcAddr[0], frame->srcAddr[1], frame->srcAddr[2],
frame->srcAddr[3], frame->srcAddr[4], frame->srcAddr[5],
ntohs(frame->etherType),
ntohs(frame->mcpProtoType),
ntohl(frame->groupKey),
ntohs(frame->dataLength),
frame->data[0], frame->data[1], frame->data[2], frame->data[3],
frame->data[4], frame->data[5], frame->data[6], frame->data[7], frame->data[8]);

if(ntohs(frame->mcpProtoType) == 1 && ntohl(frame->groupKey) == myGroupKey) {
/* blah blah */
/* blah blah */
/* blah blah */
}

}

close(sock);

}

If you enjoyed this post Subscribe to our feed

No Comment

張貼留言