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

📄 af_netrom.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
static int nr_release(struct socket *sock){	struct sock *sk = sock->sk;	struct nr_sock *nr;	if (sk == NULL) return 0;	sock_hold(sk);	lock_sock(sk);	nr = nr_sk(sk);	switch (nr->state) {	case NR_STATE_0:	case NR_STATE_1:	case NR_STATE_2:		nr_disconnect(sk, 0);		nr_destroy_socket(sk);		break;	case NR_STATE_3:		nr_clear_queues(sk);		nr->n2count = 0;		nr_write_internal(sk, NR_DISCREQ);		nr_start_t1timer(sk);		nr_stop_t2timer(sk);		nr_stop_t4timer(sk);		nr_stop_idletimer(sk);		nr->state    = NR_STATE_2;		sk->sk_state    = TCP_CLOSE;		sk->sk_shutdown |= SEND_SHUTDOWN;		sk->sk_state_change(sk);		sock_orphan(sk);		sock_set_flag(sk, SOCK_DESTROY);		sk->sk_socket   = NULL;		break;	default:		sk->sk_socket = NULL;		break;	}	sock->sk   = NULL;	release_sock(sk);	sock_put(sk);	return 0;}static int nr_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len){	struct sock *sk = sock->sk;	struct nr_sock *nr = nr_sk(sk);	struct full_sockaddr_ax25 *addr = (struct full_sockaddr_ax25 *)uaddr;	struct net_device *dev;	ax25_uid_assoc *user;	ax25_address *source;	lock_sock(sk);	if (!sock_flag(sk, SOCK_ZAPPED)) {		release_sock(sk);		return -EINVAL;	}	if (addr_len < sizeof(struct sockaddr_ax25) || addr_len > sizeof(struct full_sockaddr_ax25)) {		release_sock(sk);		return -EINVAL;	}	if (addr_len < (addr->fsa_ax25.sax25_ndigis * sizeof(ax25_address) + sizeof(struct sockaddr_ax25))) {		release_sock(sk);		return -EINVAL;	}	if (addr->fsa_ax25.sax25_family != AF_NETROM) {		release_sock(sk);		return -EINVAL;	}	if ((dev = nr_dev_get(&addr->fsa_ax25.sax25_call)) == NULL) {		SOCK_DEBUG(sk, "NET/ROM: bind failed: invalid node callsign\n");		release_sock(sk);		return -EADDRNOTAVAIL;	}	/*	 * Only the super user can set an arbitrary user callsign.	 */	if (addr->fsa_ax25.sax25_ndigis == 1) {		if (!capable(CAP_NET_BIND_SERVICE)) {			dev_put(dev);			release_sock(sk);			return -EACCES;		}		nr->user_addr   = addr->fsa_digipeater[0];		nr->source_addr = addr->fsa_ax25.sax25_call;	} else {		source = &addr->fsa_ax25.sax25_call;		user = ax25_findbyuid(current->euid);		if (user) {			nr->user_addr   = user->call;			ax25_uid_put(user);		} else {			if (ax25_uid_policy && !capable(CAP_NET_BIND_SERVICE)) {				release_sock(sk);				dev_put(dev);				return -EPERM;			}			nr->user_addr   = *source;		}		nr->source_addr = *source;	}	nr->device = dev;	nr_insert_socket(sk);	sock_reset_flag(sk, SOCK_ZAPPED);	dev_put(dev);	release_sock(sk);	SOCK_DEBUG(sk, "NET/ROM: socket is bound\n");	return 0;}static int nr_connect(struct socket *sock, struct sockaddr *uaddr,	int addr_len, int flags){	struct sock *sk = sock->sk;	struct nr_sock *nr = nr_sk(sk);	struct sockaddr_ax25 *addr = (struct sockaddr_ax25 *)uaddr;	ax25_address *source = NULL;	ax25_uid_assoc *user;	struct net_device *dev;	int err = 0;	lock_sock(sk);	if (sk->sk_state == TCP_ESTABLISHED && sock->state == SS_CONNECTING) {		sock->state = SS_CONNECTED;		goto out_release;	/* Connect completed during a ERESTARTSYS event */	}	if (sk->sk_state == TCP_CLOSE && sock->state == SS_CONNECTING) {		sock->state = SS_UNCONNECTED;		err = -ECONNREFUSED;		goto out_release;	}	if (sk->sk_state == TCP_ESTABLISHED) {		err = -EISCONN;	/* No reconnect on a seqpacket socket */		goto out_release;	}	sk->sk_state   = TCP_CLOSE;	sock->state = SS_UNCONNECTED;	if (addr_len != sizeof(struct sockaddr_ax25) && addr_len != sizeof(struct full_sockaddr_ax25)) {		err = -EINVAL;		goto out_release;	}	if (addr->sax25_family != AF_NETROM) {		err = -EINVAL;		goto out_release;	}	if (sock_flag(sk, SOCK_ZAPPED)) {	/* Must bind first - autobinding in this may or may not work */		sock_reset_flag(sk, SOCK_ZAPPED);		if ((dev = nr_dev_first()) == NULL) {			err = -ENETUNREACH;			goto out_release;		}		source = (ax25_address *)dev->dev_addr;		user = ax25_findbyuid(current->euid);		if (user) {			nr->user_addr   = user->call;			ax25_uid_put(user);		} else {			if (ax25_uid_policy && !capable(CAP_NET_ADMIN)) {				dev_put(dev);				err = -EPERM;				goto out_release;			}			nr->user_addr   = *source;		}		nr->source_addr = *source;		nr->device      = dev;		dev_put(dev);		nr_insert_socket(sk);		/* Finish the bind */	}	nr->dest_addr = addr->sax25_call;	release_sock(sk);	circuit = nr_find_next_circuit();	lock_sock(sk);	nr->my_index = circuit / 256;	nr->my_id    = circuit % 256;	circuit++;	/* Move to connecting socket, start sending Connect Requests */	sock->state  = SS_CONNECTING;	sk->sk_state = TCP_SYN_SENT;	nr_establish_data_link(sk);	nr->state = NR_STATE_1;	nr_start_heartbeat(sk);	/* Now the loop */	if (sk->sk_state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) {		err = -EINPROGRESS;		goto out_release;	}	/*	 * A Connect Ack with Choke or timeout or failed routing will go to	 * closed.	 */	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) {		sock->state = SS_UNCONNECTED;		err = sock_error(sk);	/* Always set at this point */		goto out_release;	}	sock->state = SS_CONNECTED;out_release:	release_sock(sk);	return err;}static int nr_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 ((sk = sock->sk) == NULL)		return -EINVAL;	lock_sock(sk);	if (sk->sk_type != SOCK_SEQPACKET) {		err = -EOPNOTSUPP;		goto out_release;	}	if (sk->sk_state != TCP_LISTEN) {		err = -EINVAL;		goto out_release;	}	/*	 *	The write 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)		goto out_release;	newsk = skb->sk;	newsk->sk_socket = newsock;	newsk->sk_sleep = &newsock->wait;	/* Now attach up the new socket */	kfree_skb(skb);	sk_acceptq_removed(sk);	newsock->sk = newsk;out_release:	release_sock(sk);	return err;}static int nr_getname(struct socket *sock, struct sockaddr *uaddr,	int *uaddr_len, int peer){	struct full_sockaddr_ax25 *sax = (struct full_sockaddr_ax25 *)uaddr;	struct sock *sk = sock->sk;	struct nr_sock *nr = nr_sk(sk);	lock_sock(sk);	if (peer != 0) {		if (sk->sk_state != TCP_ESTABLISHED) {			release_sock(sk);			return -ENOTCONN;		}		sax->fsa_ax25.sax25_family = AF_NETROM;		sax->fsa_ax25.sax25_ndigis = 1;		sax->fsa_ax25.sax25_call   = nr->user_addr;		sax->fsa_digipeater[0]     = nr->dest_addr;		*uaddr_len = sizeof(struct full_sockaddr_ax25);	} else {		sax->fsa_ax25.sax25_family = AF_NETROM;		sax->fsa_ax25.sax25_ndigis = 0;		sax->fsa_ax25.sax25_call   = nr->source_addr;		*uaddr_len = sizeof(struct sockaddr_ax25);	}	release_sock(sk);	return 0;}int nr_rx_frame(struct sk_buff *skb, struct net_device *dev){	struct sock *sk;	struct sock *make;	struct nr_sock *nr_make;	ax25_address *src, *dest, *user;	unsigned short circuit_index, circuit_id;	unsigned short peer_circuit_index, peer_circuit_id;	unsigned short frametype, flags, window, timeout;	int ret;	skb->sk = NULL;		/* Initially we don't know who it's for */	/*	 *	skb->data points to the netrom frame start	 */	src  = (ax25_address *)(skb->data + 0);	dest = (ax25_address *)(skb->data + 7);	circuit_index      = skb->data[15];	circuit_id         = skb->data[16];	peer_circuit_index = skb->data[17];	peer_circuit_id    = skb->data[18];	frametype          = skb->data[19] & 0x0F;	flags              = skb->data[19] & 0xF0;	/*	 * Check for an incoming IP over NET/ROM frame.	 */	if (frametype == NR_PROTOEXT &&	    circuit_index == NR_PROTO_IP && circuit_id == NR_PROTO_IP) {		skb_pull(skb, NR_NETWORK_LEN + NR_TRANSPORT_LEN);		skb_reset_transport_header(skb);		return nr_rx_ip(skb, dev);	}	/*	 * Find an existing socket connection, based on circuit ID, if it's	 * a Connect Request base it on their circuit ID.	 *	 * Circuit ID 0/0 is not valid but it could still be a "reset" for a	 * circuit that no longer exists at the other end ...	 */	sk = NULL;	if (circuit_index == 0 && circuit_id == 0) {		if (frametype == NR_CONNACK && flags == NR_CHOKE_FLAG)			sk = nr_find_peer(peer_circuit_index, peer_circuit_id, src);	} else {		if (frametype == NR_CONNREQ)			sk = nr_find_peer(circuit_index, circuit_id, src);		else			sk = nr_find_socket(circuit_index, circuit_id);	}	if (sk != NULL) {		skb_reset_transport_header(skb);		if (frametype == NR_CONNACK && skb->len == 22)			nr_sk(sk)->bpqext = 1;		else			nr_sk(sk)->bpqext = 0;		ret = nr_process_rx_frame(sk, skb);		bh_unlock_sock(sk);		return ret;	}	/*	 * Now it should be a CONNREQ.	 */	if (frametype != NR_CONNREQ) {		/*		 * Here it would be nice to be able to send a reset but		 * NET/ROM doesn't have one.  We've tried to extend the protocol		 * by sending NR_CONNACK | NR_CHOKE_FLAGS replies but that		 * apparently kills BPQ boxes... :-(		 * So now we try to follow the established behaviour of		 * G8PZT's Xrouter which is sending packets with command type 7		 * as an extension of the protocol.		 */		if (sysctl_netrom_reset_circuit &&		    (frametype != NR_RESET || flags != 0))			nr_transmit_reset(skb, 1);		return 0;	}	sk = nr_find_listener(dest);	user = (ax25_address *)(skb->data + 21);	if (sk == NULL || sk_acceptq_is_full(sk) ||	    (make = nr_make_new(sk)) == NULL) {		nr_transmit_refusal(skb, 0);		if (sk)			bh_unlock_sock(sk);		return 0;	}	window = skb->data[20];	skb->sk             = make;	make->sk_state	    = TCP_ESTABLISHED;	/* Fill in his circuit details */	nr_make = nr_sk(make);	nr_make->source_addr = *dest;	nr_make->dest_addr   = *src;	nr_make->user_addr   = *user;	nr_make->your_index  = circuit_index;	nr_make->your_id     = circuit_id;	bh_unlock_sock(sk);	circuit = nr_find_next_circuit();	bh_lock_sock(sk);	nr_make->my_index    = circuit / 256;	nr_make->my_id       = circuit % 256;	circuit++;	/* Window negotiation */	if (window < nr_make->window)		nr_make->window = window;	/* L4 timeout negotiation */	if (skb->len == 37) {		timeout = skb->data[36] * 256 + skb->data[35];		if (timeout * HZ < nr_make->t1)			nr_make->t1 = timeout * HZ;		nr_make->bpqext = 1;	} else {		nr_make->bpqext = 0;	}	nr_write_internal(make, NR_CONNACK);	nr_make->condition = 0x00;	nr_make->vs        = 0;	nr_make->va        = 0;	nr_make->vr        = 0;	nr_make->vl        = 0;	nr_make->state     = NR_STATE_3;	sk_acceptq_added(sk);	skb_queue_head(&sk->sk_receive_queue, skb);	if (!sock_flag(sk, SOCK_DEAD))		sk->sk_data_ready(sk, skb->len);	bh_unlock_sock(sk);	nr_insert_socket(make);	nr_start_heartbeat(make);

⌨️ 快捷键说明

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