現在、私は研究プロジェクトに取り組んでおり、このプロジェクトでは、uppasala 大学によって開発された aodvuu というワイヤレス ネットワーク プロトコルを実行しようとしています。プロトコルは Linux カーネル バージョン 2.4 x で開発されましたが、現在、カーネル バージョン 3.8 で実行しようとしています。以下は、問題が発生している対応するカーネル コードです (kaodv-netlink.c)。
#include <linux/version.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19))
#include <linux/config.h>
#endif
#include <linux/if.h>
#include <linux/skbuff.h>
#include <linux/spinlock.h>
#include <linux/netlink.h>
#include <linux/version.h>
#include <linux/semaphore.h>
#include <linux/module.h>
#include <net/sock.h>
#include <linux/skbuff.h>
#ifdef KERNEL26
//#include <linux/security_2.h>
#include <linux/security.h>
#endif
#include <net/sock.h>
#include "kaodv-netlink.h"
#include "kaodv-expl.h"
#include "kaodv-queue.h"
#include "kaodv-debug.h"
#include "kaodv.h"
static int peer_pid;
struct sock *sk;
struct net *nt;
static struct sock *kaodvnl;
static DEFINE_SEMAPHORE(kaodvnl_sem);
/* For 2.4 backwards compatibility */
#ifndef KERNEL26
#define sk_receive_queue receive_queue
#define sk_socket socket
#endif
extern int active_route_timeout, qual_th, is_gateway;
static struct sk_buff *kaodv_netlink_build_msg(int type, void *data, int len)
{
unsigned char *old_tail;
size_t size = 0;
struct sk_buff *skb;
struct nlmsghdr *nlh;
void *m;
size = NLMSG_SPACE(len);
skb = alloc_skb(size, GFP_ATOMIC);
if (!skb)
goto nlmsg_failure;
old_tail = SKB_TAIL_PTR(skb);
nlh = __nlmsg_put(skb, 0, 0, type, size - sizeof(*nlh),0);
m = NLMSG_DATA(nlh);
memcpy(m, data, len);
nlh->nlmsg_len = SKB_TAIL_PTR(skb) - old_tail;
NETLINK_CB(skb).portid = 0; /* from kernel */
return skb;
nlmsg_failure:
if (skb)
kfree_skb(skb);
printk(KERN_ERR "kaodv: error creating rt timeout message\n");
return NULL;
}
void kaodv_netlink_send_debug_msg(char *buf, int len)
{
struct sk_buff *skb = NULL;
skb = kaodv_netlink_build_msg(KAODVM_DEBUG, buf, len);
if (skb == NULL) {
printk("kaodv_netlink: skb=NULL\n");
return;
}
netlink_broadcast(kaodvnl, skb, peer_pid, AODVGRP_NOTIFY, GFP_USER);
}
void kaodv_netlink_send_rt_msg(int type, __u32 src, __u32 dest)
{
struct sk_buff *skb = NULL;
struct kaodv_rt_msg m;
memset(&m, 0, sizeof(m));
m.src = src;
m.dst = dest;
skb = kaodv_netlink_build_msg(type, &m, sizeof(struct kaodv_rt_msg));
if (skb == NULL) {
printk("kaodv_netlink: skb=NULL\n");
return;
}
/* netlink_unicast(kaodvnl, skb, peer_pid, MSG_DONTWAIT); */
netlink_broadcast(kaodvnl, skb, 0, AODVGRP_NOTIFY, GFP_USER);
}
void kaodv_netlink_send_rt_update_msg(int type, __u32 src, __u32 dest,
int ifindex)
{
struct sk_buff *skb = NULL;
struct kaodv_rt_msg m;
memset(&m, 0, sizeof(m));
m.type = type;
m.src = src;
m.dst = dest;
m.ifindex = ifindex;
skb = kaodv_netlink_build_msg(KAODVM_ROUTE_UPDATE, &m,
sizeof(struct kaodv_rt_msg));
if (skb == NULL) {
printk("kaodv_netlink: skb=NULL\n");
return;
}
/* netlink_unicast(kaodvnl, skb, peer_pid, MSG_DONTWAIT); */
netlink_broadcast(kaodvnl, skb, 0, AODVGRP_NOTIFY, GFP_USER);
}
void kaodv_netlink_send_rerr_msg(int type, __u32 src, __u32 dest, int ifindex)
{
struct sk_buff *skb = NULL;
struct kaodv_rt_msg m;
memset(&m, 0, sizeof(m));
m.type = type;
m.src = src;
m.dst = dest;
m.ifindex = ifindex;
skb = kaodv_netlink_build_msg(KAODVM_SEND_RERR, &m,
sizeof(struct kaodv_rt_msg));
if (skb == NULL) {
printk("kaodv_netlink: skb=NULL\n");
return;
}
/* netlink_unicast(kaodvnl, skb, peer_pid, MSG_DONTWAIT); */
netlink_broadcast(kaodvnl, skb, 0, AODVGRP_NOTIFY, GFP_USER);
}
static int kaodv_netlink_receive_peer(unsigned char type, void *msg,
unsigned int len)
{
int ret = 0;
struct kaodv_rt_msg *m;
struct kaodv_conf_msg *cm;
struct expl_entry e;
KAODV_DEBUG("Received msg: %s", kaodv_msg_type_to_str(type));
switch (type) {
case KAODVM_ADDROUTE:
if (len < sizeof(struct kaodv_rt_msg))
return -EINVAL;
m = (struct kaodv_rt_msg *)msg;
ret = kaodv_expl_get(m->dst, &e);
if (ret < 0) {
ret = kaodv_expl_update(m->dst, m->nhop, m->time,
m->flags, m->ifindex);
} else {
ret = kaodv_expl_add(m->dst, m->nhop, m->time,
m->flags, m->ifindex);
}
kaodv_queue_set_verdict(KAODV_QUEUE_SEND, m->dst);
break;
case KAODVM_DELROUTE:
if (len < sizeof(struct kaodv_rt_msg))
return -EINVAL;
m = (struct kaodv_rt_msg *)msg;
kaodv_expl_del(m->dst);
kaodv_queue_set_verdict(KAODV_QUEUE_DROP, m->dst);
break;
case KAODVM_NOROUTE_FOUND:
if (len < sizeof(struct kaodv_rt_msg))
return -EINVAL;
m = (struct kaodv_rt_msg *)msg;
KAODV_DEBUG("No route found for %s", print_ip(m->dst));
kaodv_queue_set_verdict(KAODV_QUEUE_DROP, m->dst);
break;
case KAODVM_CONFIG:
if (len < sizeof(struct kaodv_conf_msg))
return -EINVAL;
cm = (struct kaodv_conf_msg *)msg;
active_route_timeout = cm->active_route_timeout;
qual_th = cm->qual_th;
is_gateway = cm->is_gateway;
break;
default:
printk("kaodv-netlink: Unknown message type\n");
ret = -EINVAL;
}
return ret;
}
static int kaodv_netlink_rcv_nl_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct netlink_notify *n = ptr;
if (event == NETLINK_URELEASE && n->protocol == NETLINK_AODV && n->portid) {
if (n->portid == peer_pid) {
peer_pid = 0;
kaodv_expl_flush();
kaodv_queue_flush();
}
return NOTIFY_DONE;
}
return NOTIFY_DONE;
}
static struct notifier_block kaodv_nl_notifier = {
.notifier_call = kaodv_netlink_rcv_nl_event,
};
#define RCV_SKB_FAIL(err) do { netlink_ack(skb, nlh, (err)); return; } while (0)
static inline void kaodv_netlink_rcv_skb(struct sk_buff *skb)
{
int status, type, pid, flags, nlmsglen, skblen;
struct nlmsghdr *nlh;
skblen = skb->len;
if (skblen < sizeof(struct nlmsghdr)) {
printk("skblen to small\n");
return;
}
nlh = (struct nlmsghdr *)skb->data;
nlmsglen = nlh->nlmsg_len;
if (nlmsglen < sizeof(struct nlmsghdr) || skblen < nlmsglen) {
printk("nlsmsg=%d skblen=%d to small\n", nlmsglen, skblen);
return;
}
pid = nlh->nlmsg_pid;
flags = nlh->nlmsg_flags;
if (pid <= 0 || !(flags & NLM_F_REQUEST) || flags & NLM_F_MULTI)
RCV_SKB_FAIL(-EINVAL);
if (flags & MSG_TRUNC)
RCV_SKB_FAIL(-ECOMM);
type = nlh->nlmsg_type;
/* printk("kaodv_netlink: type=%d\n", type); */
/* if (type < NLMSG_NOOP || type >= IPQM_MAX) */
/* RCV_SKB_FAIL(-EINVAL); */
#ifdef KERNEL26
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))
if (security_sock_rcv_skb(skb))
RCV_SKB_FAIL(-EPERM);
#else
if (security_sock_rcv_skb(sk , skb))
RCV_SKB_FAIL(-EPERM);
#endif
#endif
//write_lock_bh(&queue_lock);
if (peer_pid) {
if (peer_pid != pid) {
//write_unlock_bh(&queue_lock);
RCV_SKB_FAIL(-EBUSY);
}
} else
peer_pid = pid;
//write_unlock_bh(&queue_lock);
status = kaodv_netlink_receive_peer(type, NLMSG_DATA(nlh),
skblen - NLMSG_LENGTH(0));
if (status < 0)
RCV_SKB_FAIL(status);
if (flags & NLM_F_ACK)
netlink_ack(skb, nlh, 0);
return;
}
#if 0
static void kaodv_netlink_rcv_sk(struct sock *sk, int len)
{
do {
struct sk_buff *skb;
if (down_trylock(&kaodvnl_sem))
return;
while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
kaodv_netlink_rcv_skb(skb);
kfree_skb(skb);
}
up(&kaodvnl_sem);
} while (kaodvnl && kaodvnl->sk_receive_queue.qlen);
return;
}
#endif
int kaodv_netlink_init(void)
{
netlink_register_notifier(&kaodv_nl_notifier);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,14))
kaodvnl = netlink_kernel_create(NETLINK_AODV, kaodv_netlink_rcv_sk);
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))
kaodvnl = netlink_kernel_create(NETLINK_AODV, AODVGRP_MAX, kaodv_netlink_rcv_sk, THIS_MODULE);
#elif (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
kaodvnl = netlink_kernel_create(NETLINK_AODV, AODVGRP_MAX, kaodv_netlink_rcv_sk, NULL, THIS_MODULE);
#else
/*
struct netlink_kernel_cfg cfg = {
.input = kaodv_netlink_init,
};
kaodvnl = netlink_kernel_create(&init_net, AODVGRP_MAX, &cfg);
*/
kaodvnl = netlink_kernel_create(&init_net,AODVGRP_MAX,
kaodv_netlink_rcv_skb, NULL);
static void kaodv_netlink_rcv_sk(struct sk_buff *skb)
{
struct netlink_kernel_cfg cfg = {
.input = recv_cmd,
};
kaodvnl = netlink_kernel_create(&init_net, AODVGRP_MAX,cfg);
if (kaodvnl == NULL) {
printk(KERN_ERR "kaodv_netlink: failed to create netlink socket\n");
netlink_unregister_notifier(&kaodv_nl_notifier);
return -1;
}
return 0;
}
#endif
return 0;
}
void kaodv_netlink_fini(void)
{
sock_release(kaodvnl->sk_socket);
down(&kaodvnl_sem);
up(&kaodvnl_sem);
netlink_unregister_notifier(&kaodv_nl_notifier);
}
私が得ているエラーは
timer_queue.o aodv_socket.o aodv_hello.o aodv_neighbor.o aodv_timeout.o routing_table.o seek_list.o aodv_rreq.o aodv_rrep.o aodv_rerr.o nl.o locality.o
make -C /home/lp3/aodvuu096/lnx KERNEL_DIR=/lib/modules/3.8.0-31-generic/build KCC=gcc XDEFS=-DDEBUG
make[1]: Entering directory `/home/lp3/aodvuu096/lnx'
make -C /lib/modules/3.8.0-31-generic/build M=/home/lp3/aodvuu096/lnx modules
make[2]: Entering directory `/usr/src/linux-headers-3.8.0-31-generic'
CC [M] /home/lp3/aodvuu096/lnx/kaodv-mod.o
CC [M] /home/lp3/aodvuu096/lnx/kaodv-debug.o
CC [M] /home/lp3/aodvuu096/lnx/kaodv-netlink.o
/home/lp3/aodvuu096/lnx/kaodv-netlink.c: In function ‘kaodv_netlink_init’:
/home/lp3/aodvuu096/lnx/kaodv-netlink.c:372:21: warning: passing argument 3 of ‘netlink_kernel_create’ from incompatible pointer type [enabled by default]
include/linux/netlink.h:48:1: note: expected ‘struct netlink_kernel_cfg *’ but argument is of type ‘void (*)(struct sk_buff *)’
/home/lp3/aodvuu096/lnx/kaodv-netlink.c:372:21: error: too many arguments to function ‘netlink_kernel_create’
include/linux/netlink.h:48:1: note: declared here
/home/lp3/aodvuu096/lnx/kaodv-netlink.c:374:13: error: invalid storage class for function ‘kaodv_netlink_rcv_sk’
/home/lp3/aodvuu096/lnx/kaodv-netlink.c: In function ‘kaodv_netlink_rcv_sk’:
/home/lp3/aodvuu096/lnx/kaodv-netlink.c:378:14: error: ‘recv_cmd’ undeclared (first use in this function)
/home/lp3/aodvuu096/lnx/kaodv-netlink.c:378:14: note: each undeclared identifier is reported only once for each function it appears in
/home/lp3/aodvuu096/lnx/kaodv-netlink.c:382:1: error: incompatible type for argument 3 of ‘netlink_kernel_create’
include/linux/netlink.h:48:1: note: expected ‘struct netlink_kernel_cfg *’ but argument is of type ‘struct netlink_kernel_cfg’
/home/lp3/aodvuu096/lnx/kaodv-netlink.c:386:3: warning: ‘return’ with a value, in function returning void [enabled by default]
/home/lp3/aodvuu096/lnx/kaodv-netlink.c:389:1: warning: ‘return’ with a value, in function returning void [enabled by default]
/home/lp3/aodvuu096/lnx/kaodv-netlink.c: In function ‘kaodv_netlink_init’:
/home/lp3/aodvuu096/lnx/kaodv-netlink.c:374:1: warning: ISO C90 forbids mixed declarations and code [-Wdeclaration-after-statement]
make[3]: *** [/home/lp3/aodvuu096/lnx/kaodv-netlink.o] Error 1
make[2]: *** [_module_/home/lp3/aodvuu096/lnx] Error 2
make[2]: Leaving directory `/usr/src/linux-headers-3.8.0-31-generic'
make[1]: *** [kaodv.ko] Error 2
make[1]: Leaving directory `/home/lp3/aodvuu096/lnx'
make: *** [kaodv] Error 2
lp3@lp3-Latitude-E5420:~/aodvuu096$