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

📄 af_ax25.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
		goto out;	newsk		 = skb->sk;	newsk->sk_socket = newsock;	newsk->sk_sleep	 = &newsock->wait;	/* Now attach up the new socket */	kfree_skb(skb);	sk->sk_ack_backlog--;	newsock->sk    = newsk;	newsock->state = SS_CONNECTED;out:	release_sock(sk);	return err;}static int ax25_getname(struct socket *sock, struct sockaddr *uaddr,	int *uaddr_len, int peer){	struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;	struct sock *sk = sock->sk;	unsigned char ndigi, i;	ax25_cb *ax25;	int err = 0;	lock_sock(sk);	ax25 = ax25_sk(sk);	if (peer != 0) {		if (sk->sk_state != TCP_ESTABLISHED) {			err = -ENOTCONN;			goto out;		}		fsa->fsa_ax25.sax25_family = AF_AX25;		fsa->fsa_ax25.sax25_call   = ax25->dest_addr;		fsa->fsa_ax25.sax25_ndigis = 0;		if (ax25->digipeat != NULL) {			ndigi = ax25->digipeat->ndigi;			fsa->fsa_ax25.sax25_ndigis = ndigi;			for (i = 0; i < ndigi; i++)				fsa->fsa_digipeater[i] =						ax25->digipeat->calls[i];		}	} else {		fsa->fsa_ax25.sax25_family = AF_AX25;		fsa->fsa_ax25.sax25_call   = ax25->source_addr;		fsa->fsa_ax25.sax25_ndigis = 1;		if (ax25->ax25_dev != NULL) {			memcpy(&fsa->fsa_digipeater[0],			       ax25->ax25_dev->dev->dev_addr, AX25_ADDR_LEN);		} else {			fsa->fsa_digipeater[0] = null_ax25_address;		}	}	*uaddr_len = sizeof (struct full_sockaddr_ax25);out:	release_sock(sk);	return err;}static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,			struct msghdr *msg, size_t len){	struct sockaddr_ax25 *usax = (struct sockaddr_ax25 *)msg->msg_name;	struct sock *sk = sock->sk;	struct sockaddr_ax25 sax;	struct sk_buff *skb;	ax25_digi dtmp, *dp;	ax25_cb *ax25;	size_t size;	int lv, err, addr_len = msg->msg_namelen;	if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT))		return -EINVAL;	lock_sock(sk);	ax25 = ax25_sk(sk);	if (sock_flag(sk, SOCK_ZAPPED)) {		err = -EADDRNOTAVAIL;		goto out;	}	if (sk->sk_shutdown & SEND_SHUTDOWN) {		send_sig(SIGPIPE, current, 0);		err = -EPIPE;		goto out;	}	if (ax25->ax25_dev == NULL) {		err = -ENETUNREACH;		goto out;	}	if (len > ax25->ax25_dev->dev->mtu) {		err = -EMSGSIZE;		goto out;	}	if (usax != NULL) {		if (usax->sax25_family != AF_AX25) {			err = -EINVAL;			goto out;		}		if (addr_len == sizeof(struct sockaddr_ax25))			/* ax25_sendmsg(): uses obsolete socket structure */			;		else if (addr_len != sizeof(struct full_sockaddr_ax25))			/* support for old structure may go away some time			 * ax25_sendmsg(): uses old (6 digipeater)			 * socket structure.			 */			if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||			    (addr_len > sizeof(struct full_sockaddr_ax25))) {				err = -EINVAL;				goto out;			}		if (addr_len > sizeof(struct sockaddr_ax25) && usax->sax25_ndigis != 0) {			int ct           = 0;			struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)usax;			/* Valid number of digipeaters ? */			if (usax->sax25_ndigis < 1 || usax->sax25_ndigis > AX25_MAX_DIGIS) {				err = -EINVAL;				goto out;			}			dtmp.ndigi      = usax->sax25_ndigis;			while (ct < usax->sax25_ndigis) {				dtmp.repeated[ct] = 0;				dtmp.calls[ct]    = fsa->fsa_digipeater[ct];				ct++;			}			dtmp.lastrepeat = 0;		}		sax = *usax;		if (sk->sk_type == SOCK_SEQPACKET &&		    ax25cmp(&ax25->dest_addr, &sax.sax25_call)) {			err = -EISCONN;			goto out;		}		if (usax->sax25_ndigis == 0)			dp = NULL;		else			dp = &dtmp;	} else {		/*		 *	FIXME: 1003.1g - if the socket is like this because		 *	it has become closed (not started closed) and is VC		 *	we ought to SIGPIPE, EPIPE		 */		if (sk->sk_state != TCP_ESTABLISHED) {			err = -ENOTCONN;			goto out;		}		sax.sax25_family = AF_AX25;		sax.sax25_call   = ax25->dest_addr;		dp = ax25->digipeat;	}	SOCK_DEBUG(sk, "AX.25: sendto: Addresses built.\n");	/* Build a packet */	SOCK_DEBUG(sk, "AX.25: sendto: building packet.\n");	/* Assume the worst case */	size = len + ax25->ax25_dev->dev->hard_header_len;	skb = sock_alloc_send_skb(sk, size, msg->msg_flags&MSG_DONTWAIT, &err);	if (skb == NULL)		goto out;	skb_reserve(skb, size - len);	SOCK_DEBUG(sk, "AX.25: Appending user data\n");	/* User data follows immediately after the AX.25 data */	if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {		err = -EFAULT;		kfree_skb(skb);		goto out;	}	skb_reset_network_header(skb);	/* Add the PID if one is not supplied by the user in the skb */	if (!ax25->pidincl)		*skb_push(skb, 1) = sk->sk_protocol;	SOCK_DEBUG(sk, "AX.25: Transmitting buffer\n");	if (sk->sk_type == SOCK_SEQPACKET) {		/* Connected mode sockets go via the LAPB machine */		if (sk->sk_state != TCP_ESTABLISHED) {			kfree_skb(skb);			err = -ENOTCONN;			goto out;		}		/* Shove it onto the queue and kick */		ax25_output(ax25, ax25->paclen, skb);		err = len;		goto out;	}	skb_push(skb, 1 + ax25_addr_size(dp));	SOCK_DEBUG(sk, "Building AX.25 Header (dp=%p).\n", dp);	if (dp != NULL)		SOCK_DEBUG(sk, "Num digipeaters=%d\n", dp->ndigi);	/* Build an AX.25 header */	lv = ax25_addr_build(skb->data, &ax25->source_addr, &sax.sax25_call,			     dp, AX25_COMMAND, AX25_MODULUS);	SOCK_DEBUG(sk, "Built header (%d bytes)\n",lv);	skb_set_transport_header(skb, lv);	SOCK_DEBUG(sk, "base=%p pos=%p\n",		   skb->data, skb_transport_header(skb));	*skb_transport_header(skb) = AX25_UI;	/* Datagram frames go straight out of the door as UI */	ax25_queue_xmit(skb, ax25->ax25_dev->dev);	err = len;out:	release_sock(sk);	return err;}static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock,	struct msghdr *msg, size_t size, int flags){	struct sock *sk = sock->sk;	struct sk_buff *skb;	int copied;	int err = 0;	lock_sock(sk);	/*	 * 	This works for seqpacket too. The receiver has ordered the	 *	queue for us! We do one quick check first though	 */	if (sk->sk_type == SOCK_SEQPACKET && sk->sk_state != TCP_ESTABLISHED) {		err =  -ENOTCONN;		goto out;	}	/* Now we can treat all alike */	skb = skb_recv_datagram(sk, flags & ~MSG_DONTWAIT,				flags & MSG_DONTWAIT, &err);	if (skb == NULL)		goto out;	if (!ax25_sk(sk)->pidincl)		skb_pull(skb, 1);		/* Remove PID */	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 (msg->msg_namelen != 0) {		struct sockaddr_ax25 *sax = (struct sockaddr_ax25 *)msg->msg_name;		ax25_digi digi;		ax25_address src;		const unsigned char *mac = skb_mac_header(skb);		ax25_addr_parse(mac + 1, skb->data - mac - 1, &src, NULL,				&digi, NULL, NULL);		sax->sax25_family = AF_AX25;		/* We set this correctly, even though we may not let the		   application know the digi calls further down (because it		   did NOT ask to know them).  This could get political... **/		sax->sax25_ndigis = digi.ndigi;		sax->sax25_call   = src;		if (sax->sax25_ndigis != 0) {			int ct;			struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)sax;			for (ct = 0; ct < digi.ndigi; ct++)				fsa->fsa_digipeater[ct] = digi.calls[ct];		}		msg->msg_namelen = sizeof(struct full_sockaddr_ax25);	}	skb_free_datagram(sk, skb);	err = copied;out:	release_sock(sk);	return err;}static int ax25_shutdown(struct socket *sk, int how){	/* FIXME - generate DM and RNR states */	return -EOPNOTSUPP;}static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){	struct sock *sk = sock->sk;	void __user *argp = (void __user *)arg;	int res = 0;	lock_sock(sk);	switch (cmd) {	case TIOCOUTQ: {		long amount;		amount = sk->sk_sndbuf - atomic_read(&sk->sk_wmem_alloc);		if (amount < 0)			amount = 0;		res = put_user(amount, (int __user *)argp);		break;	}	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;		res = put_user(amount, (int __user *) argp);		break;	}	case SIOCGSTAMP:		res = sock_get_timestamp(sk, argp);		break;	case SIOCGSTAMPNS:		res = sock_get_timestampns(sk, argp);		break;	case SIOCAX25ADDUID:	/* Add a uid to the uid/call map table */	case SIOCAX25DELUID:	/* Delete a uid from the uid/call map table */	case SIOCAX25GETUID: {		struct sockaddr_ax25 sax25;		if (copy_from_user(&sax25, argp, sizeof(sax25))) {			res = -EFAULT;			break;		}		res = ax25_uid_ioctl(cmd, &sax25);		break;	}	case SIOCAX25NOUID: {	/* Set the default policy (default/bar) */		long amount;		if (!capable(CAP_NET_ADMIN)) {			res = -EPERM;			break;		}		if (get_user(amount, (long __user *)argp)) {			res = -EFAULT;			break;		}		if (amount > AX25_NOUID_BLOCK) {			res = -EINVAL;			break;		}		ax25_uid_policy = amount;		res = 0;		break;	}	case SIOCADDRT:	case SIOCDELRT:	case SIOCAX25OPTRT:		if (!capable(CAP_NET_ADMIN)) {			res = -EPERM;			break;		}		res = ax25_rt_ioctl(cmd, argp);		break;	case SIOCAX25CTLCON:		if (!capable(CAP_NET_ADMIN)) {			res = -EPERM;			break;		}		res = ax25_ctl_ioctl(cmd, argp);		break;	case SIOCAX25GETINFO:	case SIOCAX25GETINFOOLD: {		ax25_cb *ax25 = ax25_sk(sk);		struct ax25_info_struct ax25_info;		ax25_info.t1        = ax25->t1   / HZ;		ax25_info.t2        = ax25->t2   / HZ;		ax25_info.t3        = ax25->t3   / HZ;		ax25_info.idle      = ax25->idle / (60 * HZ);		ax25_info.n2        = ax25->n2;		ax25_info.t1timer   = ax25_display_timer(&ax25->t1timer)   / HZ;		ax25_info.t2timer   = ax25_display_timer(&ax25->t2timer)   / HZ;		ax25_info.t3timer   = ax25_display_timer(&ax25->t3timer)   / HZ;		ax25_info.idletimer = ax25_display_timer(&ax25->idletimer) / (60 * HZ);		ax25_info.n2count   = ax25->n2count;		ax25_info.state     = ax25->state;		ax25_info.rcv_q     = atomic_read(&sk->sk_rmem_alloc);		ax25_info.snd_q     = atomic_read(&sk->sk_wmem_alloc);		ax25_info.vs        = ax25->vs;		ax25_info.vr        = ax25->vr;		ax25_info.va        = ax25->va;		ax25_info.vs_max    = ax25->vs; /* reserved */		ax25_info.paclen    = ax25->paclen;		ax25_info.window    = ax25->window;		/* old structure? */		if (cmd == SIOCAX25GETINFOOLD) {			static int warned = 0;			if (!warned) {				printk(KERN_INFO "%s uses old SIOCAX25GETINFO\n",					current->comm);				warned=1;			}			if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct_deprecated))) {				res = -EFAULT;				break;			}		} else {			if (copy_to_user(argp, &ax25_info, sizeof(struct ax25_info_struct))) {				res = -EINVAL;				break;			}		}		res = 0;		break;	}	case SIOCAX25ADDFWD:	case SIOCAX25DELFWD: {		struct ax25_fwd_struct ax25_fwd;		if (!capable(CAP_NET_ADMIN)) {			res = -EPERM;			break;		}		if (copy_from_user(&ax25_fwd, argp, sizeof(ax25_fwd))) {			res = -EFAULT;			break;		}		res = ax25_fwd_ioctl(cmd, &ax25_fwd);		break;	}	case SIOCGIFADDR:	case SIOCSIFADDR:	case SIOCGIFDSTADDR:	case SIOCSIFDSTADDR:	case SIOCGIFBRDADDR:	case SIOCSIFBRDADDR:	case SIOCGIFNETMASK:	case SIOCSIFNETMASK:	case SIOCGIFMETRIC:	case SIOCSIFMETRIC:		res = -EINVAL;		break;	default:		res = -ENOIOCTLCMD;		break;	}	release_sock(sk);	return res;}#ifdef CONFIG_PROC_FSstatic void *ax25_info_start(struct seq_file *seq, loff_t *pos){	struct ax25_cb *ax25;	struct hlist_node *node;	int i = 0;	spin_lock_bh(&ax25_list_lock);	ax25_for_each(ax25, node, &ax25_list) {		if (i == *pos)			return ax25;		++i;	}	return NULL;}static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos){	++*pos;	return hlist_entry( ((struct ax25_cb *)v)->ax25_node.next,			    struct ax25_cb, ax25_node);}static void ax25_info_stop(struct seq_file *seq, void *v){	spin_unlock_bh(&ax25_list_lock);}static int ax25_info_show(struct seq_file *seq, void *v){	ax25_cb *ax25 = v;	char buf[11];	int k;	/*	 * New format:	 * magic dev src_addr dest_addr,digi1,digi2,.. st vs vr va t1 t1 t2 t2 t3 t3 idle idle n2 n2 rtt window paclen Snd-Q Rcv-Q inode	 */	seq_printf(seq, "%8.8lx %s %s%s ",		   (long) ax25,		   ax25->ax25_dev == NULL? "???" : ax25->ax25_dev->dev->name,		   ax2asc(buf, &ax25->source_addr),		   ax25->iamdigi? "*":"");	seq_printf(seq, "%s", ax2asc(buf, &ax25->dest_addr));	for (k=0; (ax25->digipeat != NULL) && (k < ax25->digipeat->ndigi); k++) {		seq_printf(seq, ",%s%s",			   ax2asc(buf, &ax25->digipeat->calls[k]),			   ax25->digipeat->repeated[k]? "*":"");	}	seq_printf(seq, " %d %d %d %d %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %d %d",		   ax25->state,		   ax25->vs, ax25->vr, ax25->va,		   ax25_display_timer(&ax25->t1timer) / HZ, ax25->t1 / HZ,		   ax25_display_timer(&ax25->t2timer) / HZ, ax25->t2 / HZ,		   ax25_display_timer(&ax25->t3timer) / HZ, ax25->t3 / HZ,		   ax25_display_timer(&ax25->idletimer) / (60 * HZ),		   ax25->idle / (60 * HZ),		   ax25->n2count, ax25->n2,		   ax25->rtt / HZ,		   ax25->window,		   ax25->paclen);	if (ax25->sk != NULL) {		bh_lock_sock(ax25->sk);		seq_printf(seq," %d %d %ld\n",			   atomic_read(&ax25->sk->sk_wmem_alloc),			   atomic_read(&ax25->sk->sk_rmem_alloc),			   ax25->sk->sk_socket != NULL ? SOCK_INODE(ax25->sk->sk_socket)->i_ino : 0L);		bh_unlock_sock(ax25->sk);	} else {		seq_puts(seq, " * * *\n");	}	return 0;}static const struct seq_operations ax25_info_seqops = {	.start = ax25_info_start,	.next = ax25_info_next,	.stop = ax25_info_stop,	.show = ax25_info_show,};static int ax25_info_open(struct inode *inode, struct file *file){	return seq_open(file, &ax25_info_seqops);}static const struct file_operations ax25_info_fops = {	.owner = THIS_MODULE,	.open = ax25_info_open,	.read = seq_read,	.llseek = seq_lseek,	.release = seq_release,};#endifstatic struct net_proto_family ax25_family_ops = {	.family =	PF_AX25,	.create =	ax25_create,	.owner	=	THIS_MODULE,};static const struct proto_ops ax25_proto_ops = {	.family		= PF_AX25,	.owner		= THIS_MODULE,	.release	= ax25_release,	.bind		= ax25_bind,	.connect	= ax25_connect,	.socketpair	= sock_no_socketpair,	.accept		= ax25_accept,	.getname	= ax25_getname,	.poll		= datagram_poll,	.ioctl		= ax25_ioctl,	.listen		= ax25_listen,	.shutdown	= ax25_shutdown,	.setsockopt	= ax25_setsockopt,	.getsockopt	= ax25_getsockopt,	.sendmsg	= ax25_sendmsg,	.recvmsg	= ax25_recvmsg,	.mmap		= sock_no_mmap,	.sendpage	= sock_no_sendpage,};/* *	Called by socket.c on kernel start up */static struct packet_type ax25_packet_type = {	.type	=	__constant_htons(ETH_P_AX25),	.dev	=	NULL,				/* All devices */	.func	=	ax25_kiss_rcv,};static struct notifier_block ax25_dev_notifier = {	.notifier_call =ax25_device_event,};static int __init ax25_init(void){	int rc = proto_register(&ax25_proto, 0);	if (rc != 0)		goto out;	sock_register(&ax25_family_ops);	dev_add_pack(&ax25_packet_type);	register_netdevice_notifier(&ax25_dev_notifier);	ax25_register_sysctl();	proc_net_fops_create(&init_net, "ax25_route", S_IRUGO, &ax25_route_fops);	proc_net_fops_create(&init_net, "ax25", S_IRUGO, &ax25_info_fops);	proc_net_fops_create(&init_net, "ax25_calls", S_IRUGO, &ax25_uid_fops);out:	return rc;}module_init(ax25_init);MODULE_AUTHOR("Jonathan Naylor G4KLX <g4klx@g4klx.demon.co.uk>");MODULE_DESCRIPTION("The amateur radio AX.25 link layer protocol");MODULE_LICENSE("GPL");MODULE_ALIAS_NETPROTO(PF_AX25);static void __exit ax25_exit(void){	proc_net_remove(&init_net, "ax25_route");	proc_net_remove(&init_net, "ax25");	proc_net_remove(&init_net, "ax25_calls");	ax25_rt_free();	ax25_uid_free();	ax25_dev_free();	ax25_unregister_sysctl();	unregister_netdevice_notifier(&ax25_dev_notifier);	dev_remove_pack(&ax25_packet_type);	sock_unregister(PF_AX25);	proto_unregister(&ax25_proto);}module_exit(ax25_exit);

⌨️ 快捷键说明

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