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

📄 af_ax25.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
	if (get_user(maxlen, optlen))		return -EFAULT;	if (maxlen < 1)		return -EFAULT;	valptr = (void *) &val;	length = min_t(unsigned int, maxlen, sizeof(int));	lock_sock(sk);	ax25 = ax25_sk(sk);	switch (optname) {	case AX25_WINDOW:		val = ax25->window;		break;	case AX25_T1:		val = ax25->t1 / HZ;		break;	case AX25_T2:		val = ax25->t2 / HZ;		break;	case AX25_N2:		val = ax25->n2;		break;	case AX25_T3:		val = ax25->t3 / HZ;		break;	case AX25_IDLE:		val = ax25->idle / (60 * HZ);		break;	case AX25_BACKOFF:		val = ax25->backoff;		break;	case AX25_EXTSEQ:		val = (ax25->modulus == AX25_EMODULUS);		break;	case AX25_PIDINCL:		val = ax25->pidincl;		break;	case AX25_IAMDIGI:		val = ax25->iamdigi;		break;	case AX25_PACLEN:		val = ax25->paclen;		break;	case SO_BINDTODEVICE:		ax25_dev = ax25->ax25_dev;		if (ax25_dev != NULL && ax25_dev->dev != NULL) {			strlcpy(devname, ax25_dev->dev->name, sizeof(devname));			length = strlen(devname) + 1;		} else {			*devname = '\0';			length = 1;		}		valptr = (void *) devname;		break;	default:		release_sock(sk);		return -ENOPROTOOPT;	}	release_sock(sk);	if (put_user(length, optlen))		return -EFAULT;	return copy_to_user(optval, valptr, length) ? -EFAULT : 0;}static int ax25_listen(struct socket *sock, int backlog){	struct sock *sk = sock->sk;	int res = 0;	lock_sock(sk);	if (sk->sk_type == SOCK_SEQPACKET && sk->sk_state != TCP_LISTEN) {		sk->sk_max_ack_backlog = backlog;		sk->sk_state           = TCP_LISTEN;		goto out;	}	res = -EOPNOTSUPP;out:	release_sock(sk);	return res;}/* * XXX: when creating ax25_sock we should update the .obj_size setting * below. */static struct proto ax25_proto = {	.name	  = "AX25",	.owner	  = THIS_MODULE,	.obj_size = sizeof(struct sock),};static int ax25_create(struct net *net, struct socket *sock, int protocol){	struct sock *sk;	ax25_cb *ax25;	if (net != &init_net)		return -EAFNOSUPPORT;	switch (sock->type) {	case SOCK_DGRAM:		if (protocol == 0 || protocol == PF_AX25)			protocol = AX25_P_TEXT;		break;	case SOCK_SEQPACKET:		switch (protocol) {		case 0:		case PF_AX25:	/* For CLX */			protocol = AX25_P_TEXT;			break;		case AX25_P_SEGMENT:#ifdef CONFIG_INET		case AX25_P_ARP:		case AX25_P_IP:#endif#ifdef CONFIG_NETROM		case AX25_P_NETROM:#endif#ifdef CONFIG_ROSE		case AX25_P_ROSE:#endif			return -ESOCKTNOSUPPORT;#ifdef CONFIG_NETROM_MODULE		case AX25_P_NETROM:			if (ax25_protocol_is_registered(AX25_P_NETROM))				return -ESOCKTNOSUPPORT;#endif#ifdef CONFIG_ROSE_MODULE		case AX25_P_ROSE:			if (ax25_protocol_is_registered(AX25_P_ROSE))				return -ESOCKTNOSUPPORT;#endif		default:			break;		}		break;	case SOCK_RAW:		break;	default:		return -ESOCKTNOSUPPORT;	}	sk = sk_alloc(net, PF_AX25, GFP_ATOMIC, &ax25_proto);	if (sk == NULL)		return -ENOMEM;	ax25 = sk->sk_protinfo = ax25_create_cb();	if (!ax25) {		sk_free(sk);		return -ENOMEM;	}	sock_init_data(sock, sk);	sk->sk_destruct = ax25_free_sock;	sock->ops    = &ax25_proto_ops;	sk->sk_protocol = protocol;	ax25->sk    = sk;	return 0;}struct sock *ax25_make_new(struct sock *osk, struct ax25_dev *ax25_dev){	struct sock *sk;	ax25_cb *ax25, *oax25;	sk = sk_alloc(osk->sk_net, PF_AX25, GFP_ATOMIC,	osk->sk_prot);	if (sk == NULL)		return NULL;	if ((ax25 = ax25_create_cb()) == NULL) {		sk_free(sk);		return NULL;	}	switch (osk->sk_type) {	case SOCK_DGRAM:		break;	case SOCK_SEQPACKET:		break;	default:		sk_free(sk);		ax25_cb_put(ax25);		return NULL;	}	sock_init_data(NULL, sk);	sk->sk_destruct = ax25_free_sock;	sk->sk_type     = osk->sk_type;	sk->sk_socket   = osk->sk_socket;	sk->sk_priority = osk->sk_priority;	sk->sk_protocol = osk->sk_protocol;	sk->sk_rcvbuf   = osk->sk_rcvbuf;	sk->sk_sndbuf   = osk->sk_sndbuf;	sk->sk_state    = TCP_ESTABLISHED;	sk->sk_sleep    = osk->sk_sleep;	sock_copy_flags(sk, osk);	oax25 = ax25_sk(osk);	ax25->modulus = oax25->modulus;	ax25->backoff = oax25->backoff;	ax25->pidincl = oax25->pidincl;	ax25->iamdigi = oax25->iamdigi;	ax25->rtt     = oax25->rtt;	ax25->t1      = oax25->t1;	ax25->t2      = oax25->t2;	ax25->t3      = oax25->t3;	ax25->n2      = oax25->n2;	ax25->idle    = oax25->idle;	ax25->paclen  = oax25->paclen;	ax25->window  = oax25->window;	ax25->ax25_dev    = ax25_dev;	ax25->source_addr = oax25->source_addr;	if (oax25->digipeat != NULL) {		ax25->digipeat = kmemdup(oax25->digipeat, sizeof(ax25_digi),					 GFP_ATOMIC);		if (ax25->digipeat == NULL) {			sk_free(sk);			ax25_cb_put(ax25);			return NULL;		}	}	sk->sk_protinfo = ax25;	ax25->sk    = sk;	return sk;}static int ax25_release(struct socket *sock){	struct sock *sk = sock->sk;	ax25_cb *ax25;	if (sk == NULL)		return 0;	sock_hold(sk);	sock_orphan(sk);	lock_sock(sk);	ax25 = ax25_sk(sk);	if (sk->sk_type == SOCK_SEQPACKET) {		switch (ax25->state) {		case AX25_STATE_0:			release_sock(sk);			ax25_disconnect(ax25, 0);			lock_sock(sk);			ax25_destroy_socket(ax25);			break;		case AX25_STATE_1:		case AX25_STATE_2:			ax25_send_control(ax25, AX25_DISC, AX25_POLLON, AX25_COMMAND);			release_sock(sk);			ax25_disconnect(ax25, 0);			lock_sock(sk);			ax25_destroy_socket(ax25);			break;		case AX25_STATE_3:		case AX25_STATE_4:			ax25_clear_queues(ax25);			ax25->n2count = 0;			switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {			case AX25_PROTO_STD_SIMPLEX:			case AX25_PROTO_STD_DUPLEX:				ax25_send_control(ax25,						  AX25_DISC,						  AX25_POLLON,						  AX25_COMMAND);				ax25_stop_t2timer(ax25);				ax25_stop_t3timer(ax25);				ax25_stop_idletimer(ax25);				break;#ifdef CONFIG_AX25_DAMA_SLAVE			case AX25_PROTO_DAMA_SLAVE:				ax25_stop_t3timer(ax25);				ax25_stop_idletimer(ax25);				break;#endif			}			ax25_calculate_t1(ax25);			ax25_start_t1timer(ax25);			ax25->state = AX25_STATE_2;			sk->sk_state                = TCP_CLOSE;			sk->sk_shutdown            |= SEND_SHUTDOWN;			sk->sk_state_change(sk);			sock_set_flag(sk, SOCK_DESTROY);			break;		default:			break;		}	} else {		sk->sk_state     = TCP_CLOSE;		sk->sk_shutdown |= SEND_SHUTDOWN;		sk->sk_state_change(sk);		ax25_destroy_socket(ax25);	}	sock->sk   = NULL;	release_sock(sk);	sock_put(sk);	return 0;}/* *	We support a funny extension here so you can (as root) give any callsign *	digipeated via a local address as source. This hack is obsolete now *	that we've implemented support for SO_BINDTODEVICE. It is however small *	and trivially backward compatible. */static int ax25_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){	struct sock *sk = sock->sk;	struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;	ax25_dev *ax25_dev = NULL;	ax25_uid_assoc *user;	ax25_address call;	ax25_cb *ax25;	int err = 0;	if (addr_len != sizeof(struct sockaddr_ax25) &&	    addr_len != sizeof(struct full_sockaddr_ax25)) {		/* support for old structure may go away some time */		if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||		    (addr_len > sizeof(struct full_sockaddr_ax25))) {			return -EINVAL;	}		printk(KERN_WARNING "ax25_bind(): %s uses old (6 digipeater) socket structure.\n",			current->comm);	}	if (addr->fsa_ax25.sax25_family != AF_AX25)		return -EINVAL;	user = ax25_findbyuid(current->euid);	if (user) {		call = user->call;		ax25_uid_put(user);	} else {		if (ax25_uid_policy && !capable(CAP_NET_ADMIN))			return -EACCES;		call = addr->fsa_ax25.sax25_call;	}	lock_sock(sk);	ax25 = ax25_sk(sk);	if (!sock_flag(sk, SOCK_ZAPPED)) {		err = -EINVAL;		goto out;	}	ax25->source_addr = call;	/*	 * User already set interface with SO_BINDTODEVICE	 */	if (ax25->ax25_dev != NULL)		goto done;	if (addr_len > sizeof(struct sockaddr_ax25) && addr->fsa_ax25.sax25_ndigis == 1) {		if (ax25cmp(&addr->fsa_digipeater[0], &null_ax25_address) != 0 &&		    (ax25_dev = ax25_addr_ax25dev(&addr->fsa_digipeater[0])) == NULL) {			err = -EADDRNOTAVAIL;			goto out;		}	} else {		if ((ax25_dev = ax25_addr_ax25dev(&addr->fsa_ax25.sax25_call)) == NULL) {			err = -EADDRNOTAVAIL;			goto out;		}	}	if (ax25_dev != NULL)		ax25_fillin_cb(ax25, ax25_dev);done:	ax25_cb_add(ax25);	sock_reset_flag(sk, SOCK_ZAPPED);out:	release_sock(sk);	return 0;}/* *	FIXME: nonblock behaviour looks like it may have a bug. */static int __must_check ax25_connect(struct socket *sock,	struct sockaddr *uaddr, int addr_len, int flags){	struct sock *sk = sock->sk;	ax25_cb *ax25 = ax25_sk(sk), *ax25t;	struct full_sockaddr_ax25 *fsa = (struct full_sockaddr_ax25 *)uaddr;	ax25_digi *digi = NULL;	int ct = 0, err = 0;	/*	 * some sanity checks. code further down depends on this	 */	if (addr_len == sizeof(struct sockaddr_ax25))		/* support for this will go away in early 2.5.x		 * ax25_connect(): uses obsolete socket structure		 */		;	else if (addr_len != sizeof(struct full_sockaddr_ax25))		/* support for old structure may go away some time		 * ax25_connect(): uses old (6 digipeater) socket structure.		 */		if ((addr_len < sizeof(struct sockaddr_ax25) + sizeof(ax25_address) * 6) ||		    (addr_len > sizeof(struct full_sockaddr_ax25)))			return -EINVAL;	if (fsa->fsa_ax25.sax25_family != AF_AX25)		return -EINVAL;	lock_sock(sk);	/* deal with restarts */	if (sock->state == SS_CONNECTING) {		switch (sk->sk_state) {		case TCP_SYN_SENT: /* still trying */			err = -EINPROGRESS;			goto out_release;		case TCP_ESTABLISHED: /* connection established */			sock->state = SS_CONNECTED;			goto out_release;		case TCP_CLOSE: /* connection refused */			sock->state = SS_UNCONNECTED;			err = -ECONNREFUSED;			goto out_release;		}	}	if (sk->sk_state == TCP_ESTABLISHED && sk->sk_type == SOCK_SEQPACKET) {		err = -EISCONN;	/* No reconnect on a seqpacket socket */		goto out_release;	}	sk->sk_state   = TCP_CLOSE;	sock->state = SS_UNCONNECTED;	kfree(ax25->digipeat);	ax25->digipeat = NULL;	/*	 *	Handle digi-peaters to be used.	 */	if (addr_len > sizeof(struct sockaddr_ax25) &&	    fsa->fsa_ax25.sax25_ndigis != 0) {		/* Valid number of digipeaters ? */		if (fsa->fsa_ax25.sax25_ndigis < 1 || fsa->fsa_ax25.sax25_ndigis > AX25_MAX_DIGIS) {			err = -EINVAL;			goto out_release;		}		if ((digi = kmalloc(sizeof(ax25_digi), GFP_KERNEL)) == NULL) {			err = -ENOBUFS;			goto out_release;		}		digi->ndigi      = fsa->fsa_ax25.sax25_ndigis;		digi->lastrepeat = -1;		while (ct < fsa->fsa_ax25.sax25_ndigis) {			if ((fsa->fsa_digipeater[ct].ax25_call[6] &			     AX25_HBIT) && ax25->iamdigi) {				digi->repeated[ct] = 1;				digi->lastrepeat   = ct;			} else {				digi->repeated[ct] = 0;			}			digi->calls[ct] = fsa->fsa_digipeater[ct];			ct++;		}	}	/*	 *	Must bind first - autobinding in this may or may not work. If	 *	the socket is already bound, check to see if the device has	 *	been filled in, error if it hasn't.	 */	if (sock_flag(sk, SOCK_ZAPPED)) {		/* check if we can remove this feature. It is broken. */		printk(KERN_WARNING "ax25_connect(): %s uses autobind, please contact jreuter@yaina.de\n",			current->comm);		if ((err = ax25_rt_autobind(ax25, &fsa->fsa_ax25.sax25_call)) < 0) {			kfree(digi);			goto out_release;		}		ax25_fillin_cb(ax25, ax25->ax25_dev);		ax25_cb_add(ax25);	} else {		if (ax25->ax25_dev == NULL) {			kfree(digi);			err = -EHOSTUNREACH;			goto out_release;		}	}	if (sk->sk_type == SOCK_SEQPACKET &&	    (ax25t=ax25_find_cb(&ax25->source_addr, &fsa->fsa_ax25.sax25_call, digi,			 ax25->ax25_dev->dev))) {		kfree(digi);		err = -EADDRINUSE;		/* Already such a connection */		ax25_cb_put(ax25t);		goto out_release;	}	ax25->dest_addr = fsa->fsa_ax25.sax25_call;	ax25->digipeat  = digi;	/* First the easy one */	if (sk->sk_type != SOCK_SEQPACKET) {		sock->state = SS_CONNECTED;		sk->sk_state   = TCP_ESTABLISHED;		goto out_release;	}	/* Move to connecting socket, ax.25 lapb WAIT_UA.. */	sock->state        = SS_CONNECTING;	sk->sk_state          = TCP_SYN_SENT;	switch (ax25->ax25_dev->values[AX25_VALUES_PROTOCOL]) {	case AX25_PROTO_STD_SIMPLEX:	case AX25_PROTO_STD_DUPLEX:		ax25_std_establish_data_link(ax25);		break;#ifdef CONFIG_AX25_DAMA_SLAVE	case AX25_PROTO_DAMA_SLAVE:		ax25->modulus = AX25_MODULUS;		ax25->window  = ax25->ax25_dev->values[AX25_VALUES_WINDOW];		if (ax25->ax25_dev->dama.slave)			ax25_ds_establish_data_link(ax25);		else			ax25_std_establish_data_link(ax25);		break;#endif	}	ax25->state = AX25_STATE_1;	ax25_start_heartbeat(ax25);	/* Now the loop */	if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {		err = -EINPROGRESS;		goto out_release;	}	if (sk->sk_state == TCP_SYN_SENT) {		DEFINE_WAIT(wait);		for (;;) {			prepare_to_wait(sk->sk_sleep, &wait,					TASK_INTERRUPTIBLE);			if (sk->sk_state != TCP_SYN_SENT)				break;			if (!signal_pending(current)) {				release_sock(sk);				schedule();				lock_sock(sk);				continue;			}			err = -ERESTARTSYS;			break;		}		finish_wait(sk->sk_sleep, &wait);		if (err)			goto out_release;	}	if (sk->sk_state != TCP_ESTABLISHED) {		/* Not in ABM, not in WAIT_UA -> failed */		sock->state = SS_UNCONNECTED;		err = sock_error(sk);	/* Always set at this point */		goto out_release;	}	sock->state = SS_CONNECTED;	err = 0;out_release:	release_sock(sk);	return err;}static int ax25_accept(struct socket *sock, struct socket *newsock, int flags){	struct sk_buff *skb;	struct sock *newsk;	DEFINE_WAIT(wait);	struct sock *sk;	int err = 0;	if (sock->state != SS_UNCONNECTED)		return -EINVAL;	if ((sk = sock->sk) == NULL)		return -EINVAL;	lock_sock(sk);	if (sk->sk_type != SOCK_SEQPACKET) {		err = -EOPNOTSUPP;		goto out;	}	if (sk->sk_state != TCP_LISTEN) {		err = -EINVAL;		goto out;	}	/*	 *	The read queue this time is holding sockets ready to use	 *	hooked into the SABM we saved	 */	for (;;) {		prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);		skb = skb_dequeue(&sk->sk_receive_queue);		if (skb)			break;		if (flags & O_NONBLOCK) {			err = -EWOULDBLOCK;			break;		}		if (!signal_pending(current)) {			release_sock(sk);			schedule();			lock_sock(sk);			continue;		}		err = -ERESTARTSYS;		break;	}	finish_wait(sk->sk_sleep, &wait);	if (err)

⌨️ 快捷键说明

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