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

📄 af_rose.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (sk->zapped)		return -EADDRNOTAVAIL;	if (sk->shutdown & SEND_SHUTDOWN) {		send_sig(SIGPIPE, current, 0);		return -EPIPE;	}	if (sk->protinfo.rose->neighbour == NULL || sk->protinfo.rose->device == NULL)		return -ENETUNREACH;	if (usrose != NULL) {		if (msg->msg_namelen != sizeof(struct sockaddr_rose) && msg->msg_namelen != sizeof(struct full_sockaddr_rose))			return -EINVAL;		memset(&srose, 0, sizeof(struct full_sockaddr_rose));		memcpy(&srose, usrose, msg->msg_namelen);		if (rosecmp(&sk->protinfo.rose->dest_addr, &srose.srose_addr) != 0 ||		    ax25cmp(&sk->protinfo.rose->dest_call, &srose.srose_call) != 0)			return -EISCONN;		if (srose.srose_ndigis != sk->protinfo.rose->dest_ndigis)			return -EISCONN;		if (srose.srose_ndigis == sk->protinfo.rose->dest_ndigis) {			for (n = 0 ; n < srose.srose_ndigis ; n++)				if (ax25cmp(&sk->protinfo.rose->dest_digis[n], &srose.srose_digis[n]) != 0)					return -EISCONN;		}		if (srose.srose_family != AF_ROSE)			return -EINVAL;	} else {		if (sk->state != TCP_ESTABLISHED)			return -ENOTCONN;		srose.srose_family = AF_ROSE;		srose.srose_addr   = sk->protinfo.rose->dest_addr;		srose.srose_call   = sk->protinfo.rose->dest_call;		srose.srose_ndigis = sk->protinfo.rose->dest_ndigis;		for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++)			srose.srose_digis[n] = sk->protinfo.rose->dest_digis[n];	}	SOCK_DEBUG(sk, "ROSE: sendto: Addresses built.\n");	/* Build a packet */	SOCK_DEBUG(sk, "ROSE: sendto: building packet.\n");	size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;	if ((skb = sock_alloc_send_skb(sk, size, 0, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL)		return err;	skb_reserve(skb, AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN);	/*	 *	Put the data on the end	 */	SOCK_DEBUG(sk, "ROSE: Appending user data\n");	asmptr = skb->h.raw = skb_put(skb, len);	memcpy_fromiovec(asmptr, msg->msg_iov, len);	/*	 *	If the Q BIT Include socket option is in force, the first	 *	byte of the user data is the logical value of the Q Bit.	 */	if (sk->protinfo.rose->qbitincl) {		qbit = skb->data[0];		skb_pull(skb, 1);	}	/*	 *	Push down the ROSE header	 */	asmptr = skb_push(skb, ROSE_MIN_LEN);	SOCK_DEBUG(sk, "ROSE: Building Network Header.\n");	/* Build a ROSE Network header */	asmptr[0] = ((sk->protinfo.rose->lci >> 8) & 0x0F) | ROSE_GFI;	asmptr[1] = (sk->protinfo.rose->lci >> 0) & 0xFF;	asmptr[2] = ROSE_DATA;	if (qbit)		asmptr[0] |= ROSE_Q_BIT;	SOCK_DEBUG(sk, "ROSE: Built header.\n");	SOCK_DEBUG(sk, "ROSE: Transmitting buffer\n");		if (sk->state != TCP_ESTABLISHED) {		kfree_skb(skb);		return -ENOTCONN;	}#ifdef M_BIT#define ROSE_PACLEN (256-ROSE_MIN_LEN)	if (skb->len - ROSE_MIN_LEN > ROSE_PACLEN) {		unsigned char header[ROSE_MIN_LEN];		struct sk_buff *skbn;		int frontlen;		int lg;				/* Save a copy of the Header */		memcpy(header, skb->data, ROSE_MIN_LEN);		skb_pull(skb, ROSE_MIN_LEN);		frontlen = skb_headroom(skb);		while (skb->len > 0) {			if ((skbn = sock_alloc_send_skb(sk, frontlen + ROSE_PACLEN, 0, 0, &err)) == NULL)				return err;			skbn->sk   = sk;			skbn->free = 1;			skbn->arp  = 1;			skb_reserve(skbn, frontlen);			lg = (ROSE_PACLEN > skb->len) ? skb->len : ROSE_PACLEN;			/* Copy the user data */			memcpy(skb_put(skbn, lg), skb->data, lg);			skb_pull(skb, lg);			/* Duplicate the Header */			skb_push(skbn, ROSE_MIN_LEN);			memcpy(skbn->data, header, ROSE_MIN_LEN);			if (skb->len > 0)				skbn->data[2] |= M_BIT;					skb_queue_tail(&sk->write_queue, skbn); /* Throw it on the queue */		}				skb->free = 1;		kfree_skb(skb, FREE_WRITE);	} else {		skb_queue_tail(&sk->write_queue, skb);		/* Throw it on the queue */	}#else	skb_queue_tail(&sk->write_queue, skb);	/* Shove it onto the queue */#endif	rose_kick(sk);	return len;}static int rose_recvmsg(struct socket *sock, struct msghdr *msg, int size, 		   int flags, struct scm_cookie *scm){	struct sock *sk = sock->sk;	struct sockaddr_rose *srose = (struct sockaddr_rose *)msg->msg_name;	int copied, qbit;	unsigned char *asmptr;	struct sk_buff *skb;	int n, er;	/*	 * This works for seqpacket too. The receiver has ordered the queue for	 * us! We do one quick check first though	 */	if (sk->state != TCP_ESTABLISHED)		return -ENOTCONN;	/* Now we can treat all alike */	if ((skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT, flags & MSG_DONTWAIT, &er)) == NULL)		return er;	qbit = (skb->data[0] & ROSE_Q_BIT) == ROSE_Q_BIT;	skb_pull(skb, ROSE_MIN_LEN);	if (sk->protinfo.rose->qbitincl) {		asmptr  = skb_push(skb, 1);		*asmptr = qbit;	}	skb->h.raw = skb->data;	copied     = skb->len;	if (copied > size) {		copied = size;		msg->msg_flags |= MSG_TRUNC;	}	skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);	if (srose != NULL) {		srose->srose_family = AF_ROSE;		srose->srose_addr   = sk->protinfo.rose->dest_addr;		srose->srose_call   = sk->protinfo.rose->dest_call;		srose->srose_ndigis = sk->protinfo.rose->dest_ndigis;		if (msg->msg_namelen >= sizeof(struct full_sockaddr_rose)) {			struct full_sockaddr_rose *full_srose = (struct full_sockaddr_rose *)msg->msg_name;			for (n = 0 ; n < sk->protinfo.rose->dest_ndigis ; n++)				full_srose->srose_digis[n] = sk->protinfo.rose->dest_digis[n];			msg->msg_namelen = sizeof(struct full_sockaddr_rose);		} else {			if (sk->protinfo.rose->dest_ndigis >= 1) {				srose->srose_ndigis = 1;				srose->srose_digi = sk->protinfo.rose->dest_digis[0];			}			msg->msg_namelen = sizeof(struct sockaddr_rose);		}	}	skb_free_datagram(sk, skb);	return copied;}static int rose_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct sock *sk = sock->sk;	switch (cmd) {		case TIOCOUTQ: {			long amount;			amount = sk->sndbuf - atomic_read(&sk->wmem_alloc);			if (amount < 0)				amount = 0;			return put_user(amount, (unsigned int *)arg);		}		case TIOCINQ: {			struct sk_buff *skb;			long amount = 0L;			/* These two are safe on a single CPU system as only user tasks fiddle here */			if ((skb = skb_peek(&sk->receive_queue)) != NULL)				amount = skb->len;			return put_user(amount, (unsigned int *)arg);		}		case SIOCGSTAMP:			if (sk != NULL) {				if (sk->stamp.tv_sec == 0)					return -ENOENT;				return copy_to_user((void *)arg, &sk->stamp, sizeof(struct timeval)) ? -EFAULT : 0;			}			return -EINVAL;		case SIOCGIFADDR:		case SIOCSIFADDR:		case SIOCGIFDSTADDR:		case SIOCSIFDSTADDR:		case SIOCGIFBRDADDR:		case SIOCSIFBRDADDR:		case SIOCGIFNETMASK:		case SIOCSIFNETMASK:		case SIOCGIFMETRIC:		case SIOCSIFMETRIC:			return -EINVAL;		case SIOCADDRT:		case SIOCDELRT:		case SIOCRSCLRRT:			if (!capable(CAP_NET_ADMIN)) return -EPERM;			return rose_rt_ioctl(cmd, (void *)arg);		case SIOCRSGCAUSE: {			struct rose_cause_struct rose_cause;			rose_cause.cause      = sk->protinfo.rose->cause;			rose_cause.diagnostic = sk->protinfo.rose->diagnostic;			return copy_to_user((void *)arg, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0;		}		case SIOCRSSCAUSE: {			struct rose_cause_struct rose_cause;			if (copy_from_user(&rose_cause, (void *)arg, sizeof(struct rose_cause_struct)))				return -EFAULT;			sk->protinfo.rose->cause      = rose_cause.cause;			sk->protinfo.rose->diagnostic = rose_cause.diagnostic;			return 0;		}		case SIOCRSSL2CALL:			if (!capable(CAP_NET_ADMIN)) return -EPERM;			if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)				ax25_listen_release(&rose_callsign, NULL);			if (copy_from_user(&rose_callsign, (void *)arg, sizeof(ax25_address)))				return -EFAULT;			if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)				ax25_listen_register(&rose_callsign, NULL);			return 0;		case SIOCRSGL2CALL:			return copy_to_user((void *)arg, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0;		case SIOCRSACCEPT:			if (sk->protinfo.rose->state == ROSE_STATE_5) {				rose_write_internal(sk, ROSE_CALL_ACCEPTED);				rose_start_idletimer(sk);				sk->protinfo.rose->condition = 0x00;				sk->protinfo.rose->vs        = 0;				sk->protinfo.rose->va        = 0;				sk->protinfo.rose->vr        = 0;				sk->protinfo.rose->vl        = 0;				sk->protinfo.rose->state     = ROSE_STATE_3;			}			return 0;		default:			return dev_ioctl(cmd, (void *)arg);	}	/*NOTREACHED*/	return 0;}static int rose_get_info(char *buffer, char **start, off_t offset, int length){	struct sock *s;	struct net_device *dev;	const char *devname, *callsign;	int len = 0;	off_t pos = 0;	off_t begin = 0;	cli();	len += sprintf(buffer, "dest_addr  dest_call src_addr   src_call  dev   lci neigh st vs vr va   t  t1  t2  t3  hb    idle Snd-Q Rcv-Q inode\n");	for (s = rose_list; s != NULL; s = s->next) {		if ((dev = s->protinfo.rose->device) == NULL)			devname = "???";		else			devname = dev->name;		len += sprintf(buffer + len, "%-10s %-9s ",			rose2asc(&s->protinfo.rose->dest_addr),			ax2asc(&s->protinfo.rose->dest_call));		if (ax25cmp(&s->protinfo.rose->source_call, &null_ax25_address) == 0)			callsign = "??????-?";		else			callsign = ax2asc(&s->protinfo.rose->source_call);		len += sprintf(buffer + len, "%-10s %-9s %-5s %3.3X %05d  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",			rose2asc(&s->protinfo.rose->source_addr),			callsign,			devname, 			s->protinfo.rose->lci & 0x0FFF,			(s->protinfo.rose->neighbour) ? s->protinfo.rose->neighbour->number : 0,			s->protinfo.rose->state,			s->protinfo.rose->vs,			s->protinfo.rose->vr,			s->protinfo.rose->va,			ax25_display_timer(&s->protinfo.rose->timer) / HZ,			s->protinfo.rose->t1 / HZ,			s->protinfo.rose->t2 / HZ,			s->protinfo.rose->t3 / HZ,			s->protinfo.rose->hb / HZ,			ax25_display_timer(&s->protinfo.rose->idletimer) / (60 * HZ),			s->protinfo.rose->idle / (60 * HZ),			atomic_read(&s->wmem_alloc),			atomic_read(&s->rmem_alloc),			s->socket != NULL ? s->socket->inode->i_ino : 0L);		pos = begin + len;		if (pos < offset) {			len   = 0;			begin = pos;		}		if (pos > offset + length)			break;	}	sti();	*start = buffer + (offset - begin);	len   -= (offset - begin);	if (len > length) len = length;	return(len);} static struct net_proto_family rose_family_ops = {	PF_ROSE,	rose_create};static struct proto_ops SOCKOPS_WRAPPED(rose_proto_ops) = {	family:		PF_ROSE,	release:	rose_release,	bind:		rose_bind,	connect:	rose_connect,	socketpair:	sock_no_socketpair,	accept:		rose_accept,	getname:	rose_getname,	poll:		datagram_poll,	ioctl:		rose_ioctl,	listen:		rose_listen,	shutdown:	sock_no_shutdown,	setsockopt:	rose_setsockopt,	getsockopt:	rose_getsockopt,	sendmsg:	rose_sendmsg,	recvmsg:	rose_recvmsg,	mmap:		sock_no_mmap,};#include <linux/smp_lock.h>SOCKOPS_WRAP(rose_proto, PF_ROSE);static struct notifier_block rose_dev_notifier = {	rose_device_event,	0};static struct net_device *dev_rose;static int __init rose_proto_init(void){	int i;	rose_callsign = null_ax25_address;	if ((dev_rose = kmalloc(rose_ndevs * sizeof(struct net_device), GFP_KERNEL)) == NULL) {		printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate device structure\n");		return -1;	}	memset(dev_rose, 0x00, rose_ndevs * sizeof(struct net_device));	for (i = 0; i < rose_ndevs; i++) {		sprintf(dev_rose[i].name, "rose%d", i);		dev_rose[i].init = rose_init;		register_netdev(&dev_rose[i]);	}	sock_register(&rose_family_ops);	register_netdevice_notifier(&rose_dev_notifier);	printk(KERN_INFO "F6FBB/G4KLX ROSE for Linux. Version 0.62 for AX25.037 Linux 2.4\n");	ax25_protocol_register(AX25_P_ROSE, rose_route_frame);	ax25_linkfail_register(rose_link_failed);#ifdef CONFIG_SYSCTL	rose_register_sysctl();#endif	rose_loopback_init();	rose_add_loopback_neigh();	proc_net_create("rose", 0, rose_get_info);	proc_net_create("rose_neigh", 0, rose_neigh_get_info);	proc_net_create("rose_nodes", 0, rose_nodes_get_info);	proc_net_create("rose_routes", 0, rose_routes_get_info);	return 0;}module_init(rose_proto_init);EXPORT_NO_SYMBOLS;MODULE_PARM(rose_ndevs, "i");MODULE_PARM_DESC(rose_ndevs, "number of ROSE devices");MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");MODULE_DESCRIPTION("The amateur radio ROSE network layer protocol");static void __exit rose_exit(void){	int i;	proc_net_remove("rose");	proc_net_remove("rose_neigh");	proc_net_remove("rose_nodes");	proc_net_remove("rose_routes");	rose_loopback_clear();	rose_rt_free();	ax25_protocol_release(AX25_P_ROSE);	ax25_linkfail_release(rose_link_failed);	if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)		ax25_listen_release(&rose_callsign, NULL);#ifdef CONFIG_SYSCTL	rose_unregister_sysctl();#endif	unregister_netdevice_notifier(&rose_dev_notifier);	sock_unregister(PF_ROSE);	for (i = 0; i < rose_ndevs; i++) {		if (dev_rose[i].priv != NULL) {			kfree(dev_rose[i].priv);			dev_rose[i].priv = NULL;			unregister_netdev(&dev_rose[i]);		}		kfree(dev_rose[i].name);	}	kfree(dev_rose);}module_exit(rose_exit);

⌨️ 快捷键说明

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