注册 登录
自由的生活_软路由 返回首页

心想事成的个人空间 https://bbs.routerclub.com/?681 [收藏] [复制] [分享] [RSS]

日志

在内核中构造一个UDP 数据

已有 871 次阅读2011-4-7 23:49 |个人分类:内核

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;
_out:
    return err;
}


路过

雷人

握手

鲜花

鸡蛋

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

QQ|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.

返回顶部