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

📄 af_rose.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *	ROSE release 003 * *	This code REQUIRES 2.1.15 or higher/ NET3.038 * *	This module: *		This module 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. * *	History *	ROSE 001	Jonathan(G4KLX)	Cloned from af_netrom.c. *			Alan(GW4PTS)	Hacked up for newer API stuff *			Terry (VK2KTJ)	Added support for variable length * 					address masks. *	ROSE 002	Jonathan(G4KLX)	Changed hdrincl to qbitincl. *					Added random number facilities entry. *					Variable number of ROSE devices. *	ROSE 003	Jonathan(G4KLX)	New timer architecture. *					Implemented idle timer. *					Added use count to neighbour. *                      Tomi(OH2BNS)    Fixed rose_getname(). *                      Arnaldo C. Melo s/suser/capable/ + micro cleanups */#include <linux/config.h>#include <linux/module.h>#include <linux/init.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/socket.h>#include <linux/in.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/timer.h>#include <linux/string.h>#include <linux/sockios.h>#include <linux/net.h>#include <linux/stat.h>#include <net/ax25.h>#include <linux/inet.h>#include <linux/netdevice.h>#include <linux/if_arp.h>#include <linux/skbuff.h>#include <net/sock.h>#include <asm/segment.h>#include <asm/system.h>#include <asm/uaccess.h>#include <linux/fcntl.h>#include <linux/termios.h>	/* For TIOCINQ/OUTQ */#include <linux/mm.h>#include <linux/interrupt.h>#include <linux/notifier.h>#include <net/rose.h>#include <linux/proc_fs.h>#include <net/ip.h>#include <net/arp.h>int rose_ndevs = 10;int sysctl_rose_restart_request_timeout = ROSE_DEFAULT_T0;int sysctl_rose_call_request_timeout    = ROSE_DEFAULT_T1;int sysctl_rose_reset_request_timeout   = ROSE_DEFAULT_T2;int sysctl_rose_clear_request_timeout   = ROSE_DEFAULT_T3;int sysctl_rose_no_activity_timeout     = ROSE_DEFAULT_IDLE;int sysctl_rose_ack_hold_back_timeout   = ROSE_DEFAULT_HB;int sysctl_rose_routing_control         = ROSE_DEFAULT_ROUTING;int sysctl_rose_link_fail_timeout       = ROSE_DEFAULT_FAIL_TIMEOUT;int sysctl_rose_maximum_vcs             = ROSE_DEFAULT_MAXVC;int sysctl_rose_window_size             = ROSE_DEFAULT_WINDOW_SIZE;static struct sock *volatile rose_list = NULL;static struct proto_ops rose_proto_ops;ax25_address rose_callsign;/* *	Convert a ROSE address into text. */char *rose2asc(rose_address *addr){	static char buffer[11];	if (addr->rose_addr[0] == 0x00 && addr->rose_addr[1] == 0x00 &&	    addr->rose_addr[2] == 0x00 && addr->rose_addr[3] == 0x00 &&	    addr->rose_addr[4] == 0x00) {		strcpy(buffer, "*");	} else {		sprintf(buffer, "%02X%02X%02X%02X%02X", addr->rose_addr[0] & 0xFF,						addr->rose_addr[1] & 0xFF,						addr->rose_addr[2] & 0xFF,						addr->rose_addr[3] & 0xFF,						addr->rose_addr[4] & 0xFF);	}	return buffer;}/* *	Compare two ROSE addresses, 0 == equal. */int rosecmp(rose_address *addr1, rose_address *addr2){	int i;	for (i = 0; i < 5; i++)		if (addr1->rose_addr[i] != addr2->rose_addr[i])			return 1;	return 0;}/* *	Compare two ROSE addresses for only mask digits, 0 == equal. */int rosecmpm(rose_address *addr1, rose_address *addr2, unsigned short mask){	int i, j;	if (mask > 10)		return 1;	for (i = 0; i < mask; i++) {		j = i / 2;		if ((i % 2) != 0) {			if ((addr1->rose_addr[j] & 0x0F) != (addr2->rose_addr[j] & 0x0F))				return 1;		} else {			if ((addr1->rose_addr[j] & 0xF0) != (addr2->rose_addr[j] & 0xF0))				return 1;		}	}	return 0;}static void rose_free_sock(struct sock *sk){	sk_free(sk);	MOD_DEC_USE_COUNT;}static struct sock *rose_alloc_sock(void){	struct sock *sk;	rose_cb *rose;	if ((sk = sk_alloc(PF_ROSE, GFP_ATOMIC, 1)) == NULL)		return NULL;	if ((rose = kmalloc(sizeof(*rose), GFP_ATOMIC)) == NULL) {		sk_free(sk);		return NULL;	}	MOD_INC_USE_COUNT;	memset(rose, 0x00, sizeof(*rose));	sk->protinfo.rose = rose;	rose->sk          = sk;	return sk;}/* *	Socket removal during an interrupt is now safe. */static void rose_remove_socket(struct sock *sk){	struct sock *s;	unsigned long flags;	save_flags(flags); cli();	if ((s = rose_list) == sk) {		rose_list = s->next;		restore_flags(flags);		return;	}	while (s != NULL && s->next != NULL) {		if (s->next == sk) {			s->next = sk->next;			restore_flags(flags);			return;		}		s = s->next;	}	restore_flags(flags);}/* *	Kill all bound sockets on a broken link layer connection to a *	particular neighbour. */void rose_kill_by_neigh(struct rose_neigh *neigh){	struct sock *s;	for (s = rose_list; s != NULL; s = s->next) {		if (s->protinfo.rose->neighbour == neigh) {			rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);			s->protinfo.rose->neighbour->use--;			s->protinfo.rose->neighbour = NULL;		}	}}/* *	Kill all bound sockets on a dropped device. */static void rose_kill_by_device(struct net_device *dev){	struct sock *s;		for (s = rose_list; s != NULL; s = s->next) {		if (s->protinfo.rose->device == dev) {			rose_disconnect(s, ENETUNREACH, ROSE_OUT_OF_ORDER, 0);			s->protinfo.rose->neighbour->use--;			s->protinfo.rose->device = NULL;		}	}}/* *	Handle device status changes. */static int rose_device_event(struct notifier_block *this, unsigned long event, void *ptr){	struct net_device *dev = (struct net_device *)ptr;	if (event != NETDEV_DOWN)		return NOTIFY_DONE;	switch (dev->type) {		case ARPHRD_ROSE:			rose_kill_by_device(dev);			break;		case ARPHRD_AX25:			rose_link_device_down(dev);			rose_rt_device_down(dev);			break;	}	return NOTIFY_DONE;}/* *	Add a socket to the bound sockets list. */static void rose_insert_socket(struct sock *sk){	unsigned long flags;	save_flags(flags); cli();	sk->next  = rose_list;	rose_list = sk;	restore_flags(flags);}/* *	Find a socket that wants to accept the Call Request we just *	received. */static struct sock *rose_find_listener(rose_address *addr, ax25_address *call){	unsigned long flags;	struct sock *s;	save_flags(flags); cli();	for (s = rose_list; s != NULL; s = s->next) {		if (rosecmp(&s->protinfo.rose->source_addr, addr) == 0 && ax25cmp(&s->protinfo.rose->source_call, call) == 0 && s->protinfo.rose->source_ndigis == 0 && s->state == TCP_LISTEN) {			restore_flags(flags);			return s;		}	}	for (s = rose_list; s != NULL; s = s->next) {		if (rosecmp(&s->protinfo.rose->source_addr, addr) == 0 && ax25cmp(&s->protinfo.rose->source_call, &null_ax25_address) == 0 && s->state == TCP_LISTEN) {			restore_flags(flags);			return s;		}	}	restore_flags(flags);	return NULL;}/* *	Find a connected ROSE socket given my LCI and device. */struct sock *rose_find_socket(unsigned int lci, struct rose_neigh *neigh){	struct sock *s;	unsigned long flags;	save_flags(flags); cli();	for (s = rose_list; s != NULL; s = s->next) {		if (s->protinfo.rose->lci == lci && s->protinfo.rose->neighbour == neigh) {			restore_flags(flags);			return s;		}	}	restore_flags(flags);	return NULL;}/* *	Find a unique LCI for a given device. */unsigned int rose_new_lci(struct rose_neigh *neigh){	int lci;	if (neigh->dce_mode) {		for (lci = 1; lci <= sysctl_rose_maximum_vcs; lci++)			if (rose_find_socket(lci, neigh) == NULL && rose_route_free_lci(lci, neigh) == NULL)				return lci;	} else {		for (lci = sysctl_rose_maximum_vcs; lci > 0; lci--)			if (rose_find_socket(lci, neigh) == NULL && rose_route_free_lci(lci, neigh) == NULL)				return lci;	}	return 0;}/* *	Deferred destroy. */void rose_destroy_socket(struct sock *);/* *	Handler for deferred kills. */static void rose_destroy_timer(unsigned long data){	rose_destroy_socket((struct sock *)data);}/* *	This is called from user mode and the timers. Thus it protects itself against *	interrupt users but doesn't worry about being called during work. *	Once it is removed from the queue no interrupt or bottom half will *	touch it and we are (fairly 8-) ) safe. */void rose_destroy_socket(struct sock *sk)	/* Not static as it's used by the timer */{	struct sk_buff *skb;	unsigned long flags;	save_flags(flags); cli();	rose_stop_heartbeat(sk);	rose_stop_idletimer(sk);	rose_stop_timer(sk);	rose_remove_socket(sk);	rose_clear_queues(sk);		/* Flush the queues */	while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {		if (skb->sk != sk) {			/* A pending connection */			skb->sk->dead = 1;	/* Queue the unaccepted socket for death */			rose_start_heartbeat(skb->sk);			skb->sk->protinfo.rose->state = ROSE_STATE_0;		}		kfree_skb(skb);	}	if (atomic_read(&sk->wmem_alloc) != 0 || atomic_read(&sk->rmem_alloc) != 0) {		/* Defer: outstanding buffers */		init_timer(&sk->timer);		sk->timer.expires  = jiffies + 10 * HZ;		sk->timer.function = rose_destroy_timer;		sk->timer.data     = (unsigned long)sk;		add_timer(&sk->timer);	} else {		rose_free_sock(sk);	}	restore_flags(flags);}/* *	Handling for system calls applied via the various interfaces to a *	ROSE socket object. */static int rose_setsockopt(struct socket *sock, int level, int optname,	char *optval, int optlen){	struct sock *sk = sock->sk;	int opt;	if (level != SOL_ROSE)		return -ENOPROTOOPT;	if (optlen < sizeof(int))		return -EINVAL;	if (get_user(opt, (int *)optval))		return -EFAULT;	switch (optname) {		case ROSE_DEFER:			sk->protinfo.rose->defer = opt ? 1 : 0;			return 0;		case ROSE_T1:			if (opt < 1)				return -EINVAL;			sk->protinfo.rose->t1 = opt * HZ;			return 0;		case ROSE_T2:			if (opt < 1)				return -EINVAL;			sk->protinfo.rose->t2 = opt * HZ;			return 0;		case ROSE_T3:			if (opt < 1)				return -EINVAL;			sk->protinfo.rose->t3 = opt * HZ;			return 0;		case ROSE_HOLDBACK:			if (opt < 1)				return -EINVAL;			sk->protinfo.rose->hb = opt * HZ;			return 0;		case ROSE_IDLE:			if (opt < 0)				return -EINVAL;			sk->protinfo.rose->idle = opt * 60 * HZ;			return 0;		case ROSE_QBITINCL:			sk->protinfo.rose->qbitincl = opt ? 1 : 0;			return 0;		default:			return -ENOPROTOOPT;	}}static int rose_getsockopt(struct socket *sock, int level, int optname,	char *optval, int *optlen){	struct sock *sk = sock->sk;	int val = 0;	int len;	if (level != SOL_ROSE)		return -ENOPROTOOPT;			if (get_user(len, optlen))		return -EFAULT;		switch (optname) {		case ROSE_DEFER:			val = sk->protinfo.rose->defer;			break;		case ROSE_T1:			val = sk->protinfo.rose->t1 / HZ;			break;		case ROSE_T2:			val = sk->protinfo.rose->t2 / HZ;			break;		case ROSE_T3:			val = sk->protinfo.rose->t3 / HZ;			break;		case ROSE_HOLDBACK:			val = sk->protinfo.rose->hb / HZ;			break;		case ROSE_IDLE:			val = sk->protinfo.rose->idle / (60 * HZ);			break;		case ROSE_QBITINCL:			val = sk->protinfo.rose->qbitincl;			break;		default:			return -ENOPROTOOPT;	}

⌨️ 快捷键说明

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