在内核中构造一个UDP 数据

send_udp构造一个udp数据包并根据网络设备发送

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 ); //skb->dst = &rt->u.dst; skb->rtable = rt; err = 0; _out: return err; }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值