2010-07-14 4 views
3

간단히 말해서, 전선 위에 무언가를 얻기 위해 매우 뼈없는 UDP SKB를 만들려고합니다. 그 시나리오는 다음과 같습니다 :출구 장치 용 커널 sk_buff 빌드 리눅스 커널

로드 중의 커널 모듈은 /net/ipv4/udp.c에있는 표준 udp_sendmsg 함수의 메모리 위치를 덮어 씁니다. 여기에서 필자는 단순히 케이블에 연결할 수있는 지점까지 skb를 만들고 싶습니다. 일반적으로 udp_sendmsg는 약간의 UDP 부기를 수행하고 UDP 헤더를 집어 넣은 다음 라우팅, L3/L2 헤더 등을 보내기 위해 IP 계층으로 보냅니다. 기본적으로 sendmsg 기능으로 일부 기능을 가져옵니다. 이 때, 나는 단지 SKB 할당하고 있습니다 :

struct udphdr *uh; 
    skb->transport_header = skb_push(skb, sizeof(struct udphdr)); 
    uh = udp_hdr(skb); 
    uh->source = 5555; 
    uh->dest = dport; 
    uh->len = 18; 
    uh->check = 0; 

와 ip_hdr (단 기초를 잘 작성 : 다음

skb = alloc_skb(1500, GFP_KERNEL); 
    //skb has 1500 bytes of tail room only 
    skb_reserve(skb, 500); 
    //now has head and tail but no data space 
    data = skb_put(skb, 500); 
    //now we have an skb with 500 head, 500 data sec, 500 tail 

그리고 (일부 경로 테이블 seteup 후) 나는 udp_hdr를 추가하는 것을 시도하고있다) :

struct iphdr *iph; 
    skb->network_header = skb_push(skb, sizeof(struct iphdr)); 
    iph = ip_hdr(skb); 
    iph->version = 4; 
    iph->ihl = 5; 
    iph->tos = inet->tos; 
    iph->tot_len = htons(skb->len); 
    iph->protocol = IPPROTO_UDP; 
    iph->saddr = saddr; 
    iph->daddr = daddr; 
    skb->dst = dst_clone(&rt->u.dst); 

참고 : 나는 this page에서이 물건의 대부분을 가지고 있지만, 네트워크와 전송 헤더가 노동 조합을 어디 그들은 이전의 커널 (사전 2.6.24)을 사용하고 NH 및 시간 각각의 호출 어. 새로운 방법은 skb-> transport_header/skb-> network_header를 사용하고 이러한 도우미 기능을 사용하는 것입니다. 그러나 udp_sendmsg를 호출하려고 할 때 커널이 오작동하기 때문에 분명히 뭔가를하고 있습니다.

참고 : 이것은 oops없이 실행되었습니다.

skb->transport_header = skb_push(skb, sizeof(struct udphdr)); 

내가 사용 : 대신 때 와이어에 쓰레기를 버려. ​​

skb_reset_transport_header(skb); 

(및 network_header 상당하지만 위의 링크를 읽고 리눅스의 리셋 기능에 대한 소스보고 후 /sk_buff.h, 보지 못했습니다. 그것이 내가 원하는 것을하고있는 것처럼.

위 정의 문에서 정의되지 않은 변수는 내가 전체 함수를 포함하지 않았기 때문에 간단합니다.

나는이 질문이 매우 특정한 영역에 들어갈 수도 있다는 것을 알고 있지만, 새로운 skb 구조의 올바른 사용에 대한 지침은 매우 도움이 될 것입니다. 내 친구 google이 꽤 건조 해지고 있습니다.

아차 전화 추적 :

[<ffffffff813dbf98>] oops_end+0xb9/0xc1 
[<ffffffff81030e21>] no_context+0x1f6/0x205 
[<ffffffff81030fd3>] __bad_area_nosemaphore+0x1a3/0x1c9 
[<ffffffff8101184e>] ? apic_timer_interrupt+0xe/0x20 
[<ffffffff8103100c>] bad_area_nosemaphore+0x13/0x15 
[<ffffffff813dd30a>] do_page_fault+0x125/0x222 
[<ffffffff813db485>] page_fault+0x25/0x30 
[<ffffffffa010924f>] ? udp_sendmsg_offload+0x1e3/0x250 [testmodule] 
[<ffffffffa010922e>] ? udp_sendmsg_offload+0x1c2/0x250 [testmodule] 
[<ffffffff81390a00>] inet_sendmsg+0x54/0x5d 
[<ffffffff8132f142>] __sock_sendmsg+0x61/0x6c 
[<ffffffff8132f8b9>] sock_sendmsg+0xcc/0xe5 
+0

가 아차 우리에게 보여주십시오. – ninjalj

+0

oops를 반영하는 편집 된 게시물 –

답변

1

skb_push()가 전송 헤더에 포인터을 반환하지만 skb->transport_header가 있어야하는 sk_buff_data_t입니다 오프셋 - 어떻게 skb_transport_header() 참조 공장. 또한 헤더 정보를 네트워크 바이트 순서로 변환해야합니다.

당신은 UDP 헤더가 있어야한다 설정 부분 :

struct udphdr *uh; 
skb_push(skb, sizeof(struct udphdr)); 
skb_reset_transport_header(skb); 
uh = udp_hdr(skb); 
uh->source = __constant_htons(5555); 
/* ... */ 

와 마찬가지로 IP 헤더 :

struct iphdr *iph; 
skb_push(skb, sizeof(struct iphdr)); 
skb_reset_network_header(skb); 
iph = ip_hdr(skb); 
iph->version = 4; 
/* ... */ 
+0

그래, 나는 동의한다. 나는 skb-> transport_header의 사용이 __WORDSIZE에 의존하는 NET_SKBUFF_DATA_USES_OFFSET에 의존한다는 것을 skbuff에서 볼 때 어제 그 것을 만났습니다. 필자는 64 비트 플랫폼을 사용하기 때문에 전처리 기가 실제로이 방법을 사용하는 것 같습니다. 또한 바이트 순서를 지적 해 주셔서 감사합니다. 그 비트를 해킹 한 후 완전히 잊어 버렸습니다. –

+0

추신 :이 문제는 커널에서 발생합니다. (적어도 이전에는 어디에서 발생했는지는 알 수 없습니다.)하지만 여전히 내 목표는 없습니다. 나는 그것이 다른 게시를 위해있다라고 생각한다. –