【求助】怎么填充一个sk_buffer,发送一个UDP包?

daidai_____DD 2010-01-30 09:14:07
请问哪位大侠有在内核态,申请sk_buffer空间,并填充,发送UDP包的代码?借来学习学习,研究了1个星期了,还没发送成功过。
...全文
217 点赞 收藏 9
写回复
9 条回复
lvyinghong 2010年02月10日
内核里面本来就有这种代码,见netpoll实现

void netpoll_send_udp(struct netpoll *np, const char *msg, int len)
{
int total_len, eth_len, ip_len, udp_len;
struct sk_buff *skb;
struct udphdr *udph;
struct iphdr *iph;
struct ethhdr *eth;

udp_len = len + sizeof(*udph);
ip_len = eth_len = udp_len + sizeof(*iph);
total_len = eth_len + ETH_HLEN + NET_IP_ALIGN;

skb = find_skb(np, total_len, total_len - len);
if (!skb)
return;

skb_copy_to_linear_data(skb, msg, len);
skb->len += len;

skb_push(skb, sizeof(*udph));
skb_reset_transport_header(skb);
udph = udp_hdr(skb);
udph->source = htons(np->local_port);
udph->dest = htons(np->remote_port);
udph->len = htons(udp_len);
udph->check = 0;
udph->check = csum_tcpudp_magic(np->local_ip,
np->remote_ip,
udp_len, IPPROTO_UDP,
csum_partial(udph, udp_len, 0));
if (udph->check == 0)
udph->check = CSUM_MANGLED_0;

skb_push(skb, sizeof(*iph));
skb_reset_network_header(skb);
iph = ip_hdr(skb);

/* iph->version = 4; iph->ihl = 5; */
put_unaligned(0x45, (unsigned char *)iph);
iph->tos = 0;
put_unaligned(htons(ip_len), &(iph->tot_len));
iph->id = 0;
iph->frag_off = 0;
iph->ttl = 64;
iph->protocol = IPPROTO_UDP;
iph->check = 0;
put_unaligned(np->local_ip, &(iph->saddr));
put_unaligned(np->remote_ip, &(iph->daddr));
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);

eth = (struct ethhdr *) skb_push(skb, ETH_HLEN);
skb_reset_mac_header(skb);
skb->protocol = eth->h_proto = htons(ETH_P_IP);
memcpy(eth->h_source, np->dev->dev_addr, ETH_ALEN);
memcpy(eth->h_dest, np->remote_mac, ETH_ALEN);

skb->dev = np->dev;

netpoll_send_skb(np, skb);
}

回复 点赞
jiura 2010年02月09日
这个帖子不错...mark
回复 点赞
george3038 2010年02月03日
其实基本思路有两种,一种是申请skb,调用ip_output发送skb,当然发送以前要调用ip_route_output把目的IP的路由查出来填到skb中。
另外一个思路是,申请skb,直接调用驱动的发送接口dev_queue_xmit入队列将报文发送出去。
比如:
s
kb = alloc_skb(len, GFP_ATOMIC)
//...
//填充IP头,UDP头
dev_queue_xmit(skb);


或者
if (ip_route_output(&rt, dst, 0, 0, dev->ifindex))

skb=alloc_skb(IGMP_SIZE+dev->hard_header_len+15, GFP_ATOMIC);
if (skb == NULL) {
ip_rt_put(rt);
return -1;
}

skb->dst = &rt->u.dst;
//填充ip头,udp头
ip_output(skb);
回复 点赞
daidai_____DD 2010年02月02日
void send_reset(struct sk_buff *oldskb)
是利用了oldskb的很多信息。
我的目的是从无到有的构造一个udp包来发送,skb的信息都要自己填充。
回复 点赞
猫已经找不回了 2010年01月31日
去看源码吧吗,应该在ip_input.c
回复 点赞
功名半纸 2010年01月31日
一个发送 tcp rst 的例子
改改就好了
void send_reset(struct sk_buff *oldskb)
{
struct sk_buff *nskb;
const struct iphdr *oiph;
struct iphdr *niph;
const struct tcphdr *oth;
struct tcphdr _otcph, *tcph;
struct ethhdr *neth;
char *pad;
int len;
int padlen = 0;
int tcplen = 0;
//struct dst_entry *dst = NULL;
//struct rtable *rt = NULL;
struct net_device *odev = NULL;

/* IP header checks: fragment. */
if ( giph( oldskb )->frag_off & htons(IP_OFFSET))
return;

//oth = skb_header_pointer(oldskb, giph( oldskb ) << 2 + 4,
// sizeof(_otcph), &_otcph);
oiph = giph( oldskb );
oth = (u8 *)oiph + ( oiph->ihl << 2 );
if (oth == NULL)
return;

if (oth->rst)
return;

//
odev = oldskb->dev;


len = sizeof(struct iphdr) + sizeof(struct tcphdr) +
ETH_HLEN + padlen;

nskb = alloc_skb( len + LL_MAX_HEADER, GFP_ATOMIC);
if (!nskb)
return;

skb_reserve(nskb, LL_MAX_HEADER);

nskb->dev = odev;
//nskb->pkt_type = PACKET_HOST;
//nskb->protocol = __constant_htons( ETH_P_IP );
// 取得ethhdr地址,
skb_reset_mac_header(nskb);
neth = (struct ethhdr *)skb_put(nskb, sizeof( struct ethhdr ) );
/*
if ( skb_mac_header_was_set( oldskb ) ) {

memcpy( neth->h_dest, eth_hdr( oldskb )->h_source, ETH_ALEN );
memcpy( neth->h_source, eth_hdr( oldskb )->h_dest, ETH_ALEN );
neth->h_proto = eth_hdr( oldskb )->h_proto;
}
*/

niph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
niph->version = 4;
niph->ihl = sizeof(struct iphdr) / 4;
niph->tos = 0;
niph->id = 0;
niph->frag_off = htons(IP_DF);
niph->protocol = IPPROTO_TCP;
niph->check = 0;

niph->saddr = oiph->daddr;
niph->daddr = oiph->saddr;

#if 0
niph->saddr = MKNL( 192, 168, 1, 12 );
//niph->daddr = MKNL( 8, 8, 8, 8 );
niph->daddr = MKNL( 192, 168, 1, 18 );
#endif

tcph = (struct tcphdr *)skb_put(nskb, sizeof(struct tcphdr));
memset(tcph, 0, sizeof(*tcph));
tcph->source = oth->dest;
tcph->dest = oth->source;
tcph->doff = sizeof(struct tcphdr) / 4;

if (oth->ack)
tcph->seq = oth->ack_seq;
else {
tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
oldskb->len - ip_hdrlen(oldskb) -
(oth->doff << 2));
tcph->ack = 1;
}

tcph->rst = 1;

pad = NULL;
//pad = skb_put( nskb, padlen );
//memset( pad, 0x0, padlen );

tcplen = sizeof(struct tcphdr) + padlen ;
tcph->check = 0;
tcph->check = tcp_v4_check( tcplen,
niph->saddr, niph->daddr,
csum_partial(tcph,
tcplen, 0));

niph->ttl = oiph->ttl;

#if 0
niph->tot_len = htons( len - ETH_HLEN );
niph->check = 0;
niph->check = ip_fast_csum( ( u8 * )niph, niph->ihl );
#endif
// 查找output route
if ( ip_route_out( nskb, niph ) != 0 ) {
goto free_nskb;
}

// 设置skb networker layer地址
__skb_pull( nskb, ETH_HLEN );
skb_reset_network_header(nskb);

//xmit_enqueue( nskb );
//local_out_enqueue( nskb );
ip_local_out(nskb);
return;

free_nskb:
trace( "free nskb.\n" );
kfree_skb(nskb);
return ;
}
回复 点赞
bgqsl11 2010年01月31日
参考内核协议栈吧。
回复 点赞
steptodream 2010年01月30日
http://hi.baidu.com/zkheartboy/blog/item/57ce84457627a33c869473e4.html
回复 点赞
Wenxy1 2010年01月30日
参数UDP的发送过程嘛。
回复 点赞
发动态
发帖子
Linux_Kernel
创建于2007-08-27

3141

社区成员

1.7w+

社区内容

Linux/Unix社区 内核源代码研究区
社区公告
暂无公告