⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 kaodv-queue.c

📁 aodv-0.9.5 fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff
💻 C
字号:
/***************************************************************************** * * Copyright (C) 2001 Uppsala University and Ericsson AB. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * Author: Erik Nordström, <erik.nordstrom@it.uu.se> *  *****************************************************************************/#include <linux/version.h>#include <linux/module.h>#include <linux/skbuff.h>#include <linux/init.h>#include <linux/ip.h>#include <linux/notifier.h>#include <linux/netdevice.h>#include <linux/netfilter_ipv4.h>#include <linux/spinlock.h>#include <linux/sysctl.h>#include <linux/proc_fs.h>#include <net/sock.h>#include <net/route.h>#include <net/icmp.h>#include "kaodv-queue.h"#include "kaodv-expl.h"#include "kaodv-netlink.h"#include "kaodv-ipenc.h"/* * This is basically a shameless rippoff of the linux kernel's ip_queue module. */#define KAODV_QUEUE_QMAX_DEFAULT 1024#define KAODV_QUEUE_PROC_FS_NAME "kaodv_queue"#define NET_KAODV_QUEUE_QMAX 2088#define NET_KAODV_QUEUE_QMAX_NAME "kaodv_queue_maxlen"struct kaodv_rt_info {	__u8 tos;	__u32 daddr;	__u32 saddr;};struct kaodv_queue_entry {	struct list_head list;	struct sk_buff *skb;	int (*okfn) (struct sk_buff *);	struct kaodv_rt_info rt_info;};typedef int (*kaodv_queue_cmpfn) (struct kaodv_queue_entry *, unsigned long);static unsigned int queue_maxlen = KAODV_QUEUE_QMAX_DEFAULT;static rwlock_t queue_lock = RW_LOCK_UNLOCKED;static unsigned int queue_total;static LIST_HEAD(queue_list);static inline int __kaodv_queue_enqueue_entry(struct kaodv_queue_entry *entry){	if (queue_total >= queue_maxlen) {		if (net_ratelimit())			printk(KERN_WARNING "kaodv-queue: full at %d entries, "			       "dropping packet(s).\n", queue_total);		return -ENOSPC;	}	list_add(&entry->list, &queue_list);	queue_total++;	return 0;}/* * Find and return a queued entry matched by cmpfn, or return the last * entry if cmpfn is NULL. */static inline struct kaodv_queue_entry*__kaodv_queue_find_entry(kaodv_queue_cmpfn cmpfn, unsigned long data){	struct list_head *p;	list_for_each_prev(p, &queue_list) {		struct kaodv_queue_entry *entry = (struct kaodv_queue_entry *)p;		if (!cmpfn || cmpfn(entry, data))			return entry;	}	return NULL;}static inline struct kaodv_queue_entry*__kaodv_queue_find_dequeue_entry(kaodv_queue_cmpfn cmpfn, unsigned long data){	struct kaodv_queue_entry *entry;	entry = __kaodv_queue_find_entry(cmpfn, data);	if (entry == NULL)		return NULL;	list_del(&entry->list);	queue_total--;	return entry;}static inline void __kaodv_queue_flush(void){	struct kaodv_queue_entry *entry;	while ((entry = __kaodv_queue_find_dequeue_entry(NULL, 0))) {		kfree_skb(entry->skb);		kfree(entry);	}}static inline void __kaodv_queue_reset(void){	__kaodv_queue_flush();}static struct kaodv_queue_entry*kaodv_queue_find_dequeue_entry(kaodv_queue_cmpfn cmpfn, unsigned long data){	struct kaodv_queue_entry *entry;	write_lock_bh(&queue_lock);	entry = __kaodv_queue_find_dequeue_entry(cmpfn, data);	write_unlock_bh(&queue_lock);	return entry;}void kaodv_queue_flush(void){	write_lock_bh(&queue_lock);	__kaodv_queue_flush();	write_unlock_bh(&queue_lock);}intkaodv_queue_enqueue_packet(struct sk_buff *skb, int (*okfn) (struct sk_buff *)){	int status = -EINVAL;	struct kaodv_queue_entry *entry;#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22))	struct iphdr *iph = skb->nh.iph;#else	struct iphdr *iph = (struct iphdr *)skb->network_header;#endif	entry = kmalloc(sizeof(*entry), GFP_ATOMIC);	if (entry == NULL) {		printk(KERN_ERR		       "kaodv_queue: OOM in kaodv_queue_enqueue_packet()\n");		return -ENOMEM;	}	/* printk("enquing packet queue_len=%d\n", queue_total); */	entry->okfn = okfn;	entry->skb = skb;	entry->rt_info.tos = iph->tos;	entry->rt_info.daddr = iph->daddr;	entry->rt_info.saddr = iph->saddr;	write_lock_bh(&queue_lock);	status = __kaodv_queue_enqueue_entry(entry);	if (status < 0)		goto err_out_unlock;	write_unlock_bh(&queue_lock);	return status;      err_out_unlock:	write_unlock_bh(&queue_lock);	kfree(entry);	return status;}static inline int dest_cmp(struct kaodv_queue_entry *e, unsigned long daddr){	return (daddr == e->rt_info.daddr);}int kaodv_queue_find(__u32 daddr){	struct kaodv_queue_entry *entry;	int res = 0;	read_lock_bh(&queue_lock);	entry = __kaodv_queue_find_entry(dest_cmp, daddr);	if (entry != NULL)		res = 1;	read_unlock_bh(&queue_lock);	return res;}int kaodv_queue_set_verdict(int verdict, __u32 daddr){	struct kaodv_queue_entry *entry;	int pkts = 0;	if (verdict == KAODV_QUEUE_DROP) {		while (1) {			entry = kaodv_queue_find_dequeue_entry(dest_cmp, daddr);			if (entry == NULL)				return pkts;			/* Send an ICMP message informing the application that the			 * destination was unreachable. */			if (pkts == 0)				icmp_send(entry->skb, ICMP_DEST_UNREACH,					  ICMP_HOST_UNREACH, 0);			kfree_skb(entry->skb);			kfree(entry);			pkts++;		}	} else if (verdict == KAODV_QUEUE_SEND) {		struct expl_entry e;		while (1) {			entry = kaodv_queue_find_dequeue_entry(dest_cmp, daddr);			if (entry == NULL)				return pkts;			if (!kaodv_expl_get(daddr, &e)) {				kfree_skb(entry->skb);				goto next;			}			if (e.flags & KAODV_RT_GW_ENCAP) {				entry->skb = ip_pkt_encapsulate(entry->skb, e.nhop);				if (!entry->skb)					goto next;			}#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,18))			ip_route_me_harder(&entry->skb);#else			ip_route_me_harder(&entry->skb, RTN_LOCAL);#endif			pkts++;			/* Inject packet */			entry->okfn(entry->skb);		next:			kfree(entry);		}	}	return 0;}static int kaodv_queue_get_info(char *buffer, char **start, off_t offset, int length){	int len;	read_lock_bh(&queue_lock);	len = sprintf(buffer,		      "Queue length      : %u\n"		      "Queue max. length : %u\n", queue_total, queue_maxlen);	read_unlock_bh(&queue_lock);	*start = buffer + offset;	len -= offset;	if (len > length)		len = length;	else if (len < 0)		len = 0;	return len;}static int init_or_cleanup(int init){	int status = -ENOMEM;	struct proc_dir_entry *proc;	if (!init)		goto cleanup;	queue_total = 0;	proc =	    proc_net_create(KAODV_QUEUE_PROC_FS_NAME, 0, kaodv_queue_get_info);	if (proc)		proc->owner = THIS_MODULE;	else {		printk(KERN_ERR "kaodv_queue: failed to create proc entry\n");		return -1;	}	return 1;      cleanup:#ifdef KERNEL26	synchronize_net();#endif	kaodv_queue_flush();	proc_net_remove(KAODV_QUEUE_PROC_FS_NAME);	return status;}int kaodv_queue_init(void){	return init_or_cleanup(1);}void kaodv_queue_fini(void){	init_or_cleanup(0);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -