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

📄 af_rose.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN;	if ((skb = sock_alloc_send_skb(sk, size, 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");	skb_reset_transport_header(skb);	skb_put(skb, len);	err = memcpy_fromiovec(skb_transport_header(skb), msg->msg_iov, len);	if (err) {		kfree_skb(skb);		return err;	}	/*	 *	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 (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] = ((rose->lci >> 8) & 0x0F) | ROSE_GFI;	asmptr[1] = (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->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 */		skb_copy_from_linear_data(skb, header, 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, &err)) == NULL) {				kfree_skb(skb);				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 */			skb_copy_from_linear_data(skb, skb_put(skbn, lg), lg);			skb_pull(skb, lg);			/* Duplicate the Header */			skb_push(skbn, ROSE_MIN_LEN);			skb_copy_to_linear_data(skbn, header, ROSE_MIN_LEN);			if (skb->len > 0)				skbn->data[2] |= M_BIT;			skb_queue_tail(&sk->sk_write_queue, skbn); /* Throw it on the queue */		}		skb->free = 1;		kfree_skb(skb);	} else {		skb_queue_tail(&sk->sk_write_queue, skb);		/* Throw it on the queue */	}#else	skb_queue_tail(&sk->sk_write_queue, skb);	/* Shove it onto the queue */#endif	rose_kick(sk);	return len;}static int rose_recvmsg(struct kiocb *iocb, struct socket *sock,			struct msghdr *msg, size_t size, int flags){	struct sock *sk = sock->sk;	struct rose_sock *rose = rose_sk(sk);	struct sockaddr_rose *srose = (struct sockaddr_rose *)msg->msg_name;	size_t copied;	unsigned char *asmptr;	struct sk_buff *skb;	int n, er, qbit;	/*	 * This works for seqpacket too. The receiver has ordered the queue for	 * us! We do one quick check first though	 */	if (sk->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 (rose->qbitincl) {		asmptr  = skb_push(skb, 1);		*asmptr = qbit;	}	skb_reset_transport_header(skb);	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   = rose->dest_addr;		srose->srose_call   = rose->dest_call;		srose->srose_ndigis = 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 < rose->dest_ndigis ; n++)				full_srose->srose_digis[n] = rose->dest_digis[n];			msg->msg_namelen = sizeof(struct full_sockaddr_rose);		} else {			if (rose->dest_ndigis >= 1) {				srose->srose_ndigis = 1;				srose->srose_digi = 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;	struct rose_sock *rose = rose_sk(sk);	void __user *argp = (void __user *)arg;	switch (cmd) {	case TIOCOUTQ: {		long amount;		amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);		if (amount < 0)			amount = 0;		return put_user(amount, (unsigned int __user *) argp);	}	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->sk_receive_queue)) != NULL)			amount = skb->len;		return put_user(amount, (unsigned int __user *) argp);	}	case SIOCGSTAMP:		return sock_get_timestamp(sk, (struct timeval __user *) argp);	case SIOCGSTAMPNS:		return sock_get_timestampns(sk, (struct timespec __user *) argp);	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, argp);	case SIOCRSGCAUSE: {		struct rose_cause_struct rose_cause;		rose_cause.cause      = rose->cause;		rose_cause.diagnostic = rose->diagnostic;		return copy_to_user(argp, &rose_cause, sizeof(struct rose_cause_struct)) ? -EFAULT : 0;	}	case SIOCRSSCAUSE: {		struct rose_cause_struct rose_cause;		if (copy_from_user(&rose_cause, argp, sizeof(struct rose_cause_struct)))			return -EFAULT;		rose->cause      = rose_cause.cause;		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, argp, sizeof(ax25_address)))			return -EFAULT;		if (ax25cmp(&rose_callsign, &null_ax25_address) != 0)			return ax25_listen_register(&rose_callsign, NULL);		return 0;	case SIOCRSGL2CALL:		return copy_to_user(argp, &rose_callsign, sizeof(ax25_address)) ? -EFAULT : 0;	case SIOCRSACCEPT:		if (rose->state == ROSE_STATE_5) {			rose_write_internal(sk, ROSE_CALL_ACCEPTED);			rose_start_idletimer(sk);			rose->condition = 0x00;			rose->vs        = 0;			rose->va        = 0;			rose->vr        = 0;			rose->vl        = 0;			rose->state     = ROSE_STATE_3;		}		return 0;	default:		return -ENOIOCTLCMD;	}	return 0;}#ifdef CONFIG_PROC_FSstatic void *rose_info_start(struct seq_file *seq, loff_t *pos){	int i;	struct sock *s;	struct hlist_node *node;	spin_lock_bh(&rose_list_lock);	if (*pos == 0)		return SEQ_START_TOKEN;	i = 1;	sk_for_each(s, node, &rose_list) {		if (i == *pos)			return s;		++i;	}	return NULL;}static void *rose_info_next(struct seq_file *seq, void *v, loff_t *pos){	++*pos;	return (v == SEQ_START_TOKEN) ? sk_head(&rose_list)		: sk_next((struct sock *)v);}static void rose_info_stop(struct seq_file *seq, void *v){	spin_unlock_bh(&rose_list_lock);}static int rose_info_show(struct seq_file *seq, void *v){	char buf[11];	if (v == SEQ_START_TOKEN)		seq_puts(seq,			 "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");	else {		struct sock *s = v;		struct rose_sock *rose = rose_sk(s);		const char *devname, *callsign;		const struct net_device *dev = rose->device;		if (!dev)			devname = "???";		else			devname = dev->name;		seq_printf(seq, "%-10s %-9s ",			rose2asc(&rose->dest_addr),			ax2asc(buf, &rose->dest_call));		if (ax25cmp(&rose->source_call, &null_ax25_address) == 0)			callsign = "??????-?";		else			callsign = ax2asc(buf, &rose->source_call);		seq_printf(seq,			   "%-10s %-9s %-5s %3.3X %05d  %d  %d  %d  %d %3lu %3lu %3lu %3lu %3lu %3lu/%03lu %5d %5d %ld\n",			rose2asc(&rose->source_addr),			callsign,			devname,			rose->lci & 0x0FFF,			(rose->neighbour) ? rose->neighbour->number : 0,			rose->state,			rose->vs,			rose->vr,			rose->va,			ax25_display_timer(&rose->timer) / HZ,			rose->t1 / HZ,			rose->t2 / HZ,			rose->t3 / HZ,			rose->hb / HZ,			ax25_display_timer(&rose->idletimer) / (60 * HZ),			rose->idle / (60 * HZ),			atomic_read(&s->sk_wmem_alloc),			atomic_read(&s->sk_rmem_alloc),			s->sk_socket ? SOCK_INODE(s->sk_socket)->i_ino : 0L);	}	return 0;}static const struct seq_operations rose_info_seqops = {	.start = rose_info_start,	.next = rose_info_next,	.stop = rose_info_stop,	.show = rose_info_show,};static int rose_info_open(struct inode *inode, struct file *file){	return seq_open(file, &rose_info_seqops);}static const struct file_operations rose_info_fops = {	.owner = THIS_MODULE,	.open = rose_info_open,	.read = seq_read,	.llseek = seq_lseek,	.release = seq_release,};#endif	/* CONFIG_PROC_FS */static struct net_proto_family rose_family_ops = {	.family		=	PF_ROSE,	.create		=	rose_create,	.owner		=	THIS_MODULE,};static struct proto_ops rose_proto_ops = {	.family		=	PF_ROSE,	.owner		=	THIS_MODULE,	.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,	.sendpage	=	sock_no_sendpage,};static struct notifier_block rose_dev_notifier = {	.notifier_call	=	rose_device_event,};static struct net_device **dev_rose;static struct ax25_protocol rose_pid = {	.pid	= AX25_P_ROSE,	.func	= rose_route_frame};static struct ax25_linkfail rose_linkfail_notifier = {	.func	= rose_link_failed};static int __init rose_proto_init(void){	int i;	int rc;	if (rose_ndevs > 0x7FFFFFFF/sizeof(struct net_device *)) {		printk(KERN_ERR "ROSE: rose_proto_init - rose_ndevs parameter to large\n");		rc = -EINVAL;		goto out;	}	rc = proto_register(&rose_proto, 0);	if (rc != 0)		goto out;	rose_callsign = null_ax25_address;	dev_rose = kzalloc(rose_ndevs * sizeof(struct net_device *), GFP_KERNEL);	if (dev_rose == NULL) {		printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate device structure\n");		rc = -ENOMEM;		goto out_proto_unregister;	}	for (i = 0; i < rose_ndevs; i++) {		struct net_device *dev;		char name[IFNAMSIZ];		sprintf(name, "rose%d", i);		dev = alloc_netdev(sizeof(struct net_device_stats),				   name, rose_setup);		if (!dev) {			printk(KERN_ERR "ROSE: rose_proto_init - unable to allocate memory\n");			rc = -ENOMEM;			goto fail;		}		rc = register_netdev(dev);		if (rc) {			printk(KERN_ERR "ROSE: netdevice registration failed\n");			free_netdev(dev);			goto fail;		}		lockdep_set_class(&dev->_xmit_lock, &rose_netdev_xmit_lock_key);		dev_rose[i] = dev;	}	sock_register(&rose_family_ops);	register_netdevice_notifier(&rose_dev_notifier);	ax25_register_pid(&rose_pid);	ax25_linkfail_register(&rose_linkfail_notifier);#ifdef CONFIG_SYSCTL	rose_register_sysctl();#endif	rose_loopback_init();	rose_add_loopback_neigh();	proc_net_fops_create(&init_net, "rose", S_IRUGO, &rose_info_fops);	proc_net_fops_create(&init_net, "rose_neigh", S_IRUGO, &rose_neigh_fops);	proc_net_fops_create(&init_net, "rose_nodes", S_IRUGO, &rose_nodes_fops);	proc_net_fops_create(&init_net, "rose_routes", S_IRUGO, &rose_routes_fops);out:	return rc;fail:	while (--i >= 0) {		unregister_netdev(dev_rose[i]);		free_netdev(dev_rose[i]);	}	kfree(dev_rose);out_proto_unregister:	proto_unregister(&rose_proto);	goto out;}module_init(rose_proto_init);module_param(rose_ndevs, int, 0);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");MODULE_LICENSE("GPL");MODULE_ALIAS_NETPROTO(PF_ROSE);static void __exit rose_exit(void){	int i;	proc_net_remove(&init_net, "rose");	proc_net_remove(&init_net, "rose_neigh");	proc_net_remove(&init_net, "rose_nodes");	proc_net_remove(&init_net, "rose_routes");	rose_loopback_clear();	rose_rt_free();	ax25_protocol_release(AX25_P_ROSE);	ax25_linkfail_release(&rose_linkfail_notifier);	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++) {		struct net_device *dev = dev_rose[i];		if (dev) {			unregister_netdev(dev);			free_netdev(dev);		}	}	kfree(dev_rose);	proto_unregister(&rose_proto);}module_exit(rose_exit);

⌨️ 快捷键说明

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