|
int send_udp(struct net_device *odev, u16 local_port,
u32 remote_ip, u16 remote_port, u8 *msg, int len)
{
struct sk_buff *skb;
int total_len, eth_len, ip_len, udp_len, header_len;
struct udphdr *udph;
struct iphdr *iph;
struct ethhdr *eth;
u32 local_ip;
//local_ip = inet_select_addr(odev, remote_ip, RT_SCOPE_LINK);
// 选择网络设备地址
local_ip = inet_select_addr(odev, 0, RT_SCOPE_UNIVERSE);
printk( "local ip is "NIPQUAD_FMT"\n", NIPQUAD( local_ip ) );
local_ip = ntohl( local_ip );
if ( !local_ip ) {
return;
}
// 设置各个协议数据长度
udp_len = len + sizeof(*udph);
ip_len = eth_len = udp_len + sizeof(*iph);
total_len = eth_len + ETH_HLEN + NET_IP_ALIGN;
header_len = total_len - len;
// 分配skb
skb = alloc_skb( total_len + LL_MAX_HEADER, GFP_ATOMIC );
if ( !skb ) {
dbg_err( "alloc_skb fail.\n" );
return;
}
// 预先保留skb的协议首部长度大小
skb_reserve( skb, LL_MAX_HEADER + header_len );
// 拷贝负载数据
skb_copy_to_linear_data(skb, msg, len);
skb->len += len;
// skb->data 移动到udp首部
skb_push(skb, sizeof(*udph));
skb_reset_transport_header(skb);
udph = udp_hdr(skb);
udph->source = htons(local_port);
udph->dest = htons(remote_port);
udph->len = htons(udp_len);
udph->check = 0;
udph->check = csum_tcpudp_magic(htonl(local_ip),
htonl(remote_ip),
udp_len, IPPROTO_UDP,
csum_partial(udph, udp_len, 0));
if (udph->check == 0)
udph->check = CSUM_MANGLED_0;
// skb->data 移动到ip首部
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(htonl(local_ip), &(iph->saddr));
put_unaligned(htonl(remote_ip), &(iph->daddr));
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
/*
// skb->data 移动到eth首部
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, dev_addr, ETH_ALEN);
memcpy(eth->h_dest, remote_mac, ETH_ALEN);
*/
skb->dev = odev;
// 直接发送
//dev_queue_xmit( skb );
// 获取output rtable
if ( ip_route_out( skb, iph ) != 0 ) {
goto free_skb;
}
// 通过系统决定发送
ip_local_out(skb);
return;
free_skb:
trace( "free skb.\n" );
kfree_skb(skb);
return ;
}
ip_route_out 函数查找路由路径, 获取output rtable .
int ip_route_out( struct sk_buff *skb,
struct iphdr *iph )
{
int err = -1;
struct flowi fl = {};
struct rtable *rt = NULL;
fl.nl_u.ip4_u.daddr = iph->daddr;
if (ip_route_output_key( &init_net, &rt, &fl) != 0) {
dbg_err( "ip_route_output_key call fail.\n" );
goto _out;
}
trace( "rt_dst="NIPQUAD_FMT " rt_gw=" NIPQUAD_FMT "\n",
NIPQUAD( rt->rt_dst ),
NIPQUAD( rt->rt_gateway )
);
trace( "route output dev=%s\n", rt->u.dst.dev->name );
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
skb_dst_set(skb, &rt->u.dst);
#else
//skb->dst = &rt->u.dst;
skb->rtable = rt;
#endif
err = 0;|Archiver|手机版|小黑屋|软路由 ( 渝ICP备15001194号-1|渝公网安备 50011602500124号 )
GMT+8, 2024-5-6 21:56 , Processed in 0.149937 second(s), 6 queries , Gzip On, Redis On.
Powered by Discuz! X3.5 Licensed
© 2001-2023 Discuz! Team.