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

📄 dn_nsp_in.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	kfree_skb(skb);}/* * disc_conf messages are also called no_resources or no_link * messages depending upon the "reason" field. */static void dn_nsp_disc_conf(struct sock *sk, struct sk_buff *skb){	struct dn_scp *scp = &sk->protinfo.dn;	unsigned short reason;	if (skb->len != 2)		goto out;	reason = dn_ntohs(*(__u16 *)skb->data);	sk->state = TCP_CLOSE;	switch(scp->state) {		case DN_CI:			scp->state = DN_NR;			break;		case DN_DR:			if (reason == NSP_REASON_DC)				scp->state = DN_DRC;			if (reason == NSP_REASON_NL)				scp->state = DN_CN;			break;		case DN_DI:			scp->state = DN_DIC;			break;		case DN_RUN:			sk->shutdown |= SHUTDOWN_MASK;		case DN_CC:			scp->state = DN_CN;	}	if (!sk->dead) {		if (sk->socket->state != SS_UNCONNECTED)			sk->socket->state = SS_DISCONNECTING;		sk->state_change(sk);	}	scp->persist_fxn = dn_destroy_timer;	scp->persist = dn_nsp_persist(sk);out:	kfree_skb(skb);}static void dn_nsp_linkservice(struct sock *sk, struct sk_buff *skb){	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;	unsigned short segnum;	unsigned char lsflags;	char fcval;	if (skb->len != 4)		goto out;	cb->segnum = segnum = dn_ntohs(*(__u16 *)skb->data);	skb_pull(skb, 2);	lsflags = *(unsigned char *)skb->data;	skb_pull(skb, 1);	fcval = *(char *)skb->data;	if (lsflags & 0xf0)		goto out;	if (((sk->protinfo.dn.numoth_rcv + 1) & 0x0FFF) == (segnum & 0x0FFF)) {        	sk->protinfo.dn.numoth_rcv += 1;                        switch(lsflags & 0x03) {                	case 0x00:                              	break;                        case 0x01:                                      sk->protinfo.dn.flowrem_sw = DN_DONTSEND;                                break;                        case 0x02:                                      sk->protinfo.dn.flowrem_sw = DN_SEND;				dn_nsp_output(sk);				if (!sk->dead)					sk->state_change(sk);                }                        }	dn_nsp_send_oth_ack(sk);out:	kfree_skb(skb);}/* * Copy of sock_queue_rcv_skb (from sock.h) without * bh_lock_sock() (its already held when this is called) which * also allows data and other data to be queued to a socket. */static __inline__ int dn_queue_skb(struct sock *sk, struct sk_buff *skb, int sig, struct sk_buff_head *queue){#ifdef CONFIG_FILTER	struct sk_filter *filter;#endif        /* Cast skb->rcvbuf to unsigned... It's pointless, but reduces           number of warnings when compiling with -W --ANK         */        if (atomic_read(&sk->rmem_alloc) + skb->truesize >= (unsigned)sk->rcvbuf)                return -ENOMEM;#ifdef CONFIG_FILTER        if (sk->filter) {		int err = 0;                if ((filter = sk->filter) != NULL && sk_filter(skb, sk->filter))                        err = -EPERM;  /* Toss packet */		if (err)			return err;        }#endif /* CONFIG_FILTER */        skb_set_owner_r(skb, sk);        skb_queue_tail(queue, skb);	/* This code only runs from BH or BH protected context.	 * Therefore the plain read_lock is ok here. -DaveM	 */	read_lock(&sk->callback_lock);        if (!sk->dead) {		struct socket *sock = sk->socket;		wake_up_interruptible(sk->sleep);		if (sock && sock->fasync_list &&		    !test_bit(SOCK_ASYNC_WAITDATA, &sock->flags))			__kill_fasync(sock->fasync_list, sig, 				    (sig == SIGURG) ? POLL_PRI : POLL_IN);	}	read_unlock(&sk->callback_lock);        return 0;}static void dn_nsp_otherdata(struct sock *sk, struct sk_buff *skb){	struct dn_scp *scp = &sk->protinfo.dn;	unsigned short segnum;	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;	int queued = 0;	if (skb->len < 2)		goto out;	cb->segnum = segnum = dn_ntohs(*(__u16 *)skb->data);	skb_pull(skb, 2);	if (((sk->protinfo.dn.numoth_rcv + 1) & 0x0fff) == (segnum & 0x0fff)) {		if (dn_queue_skb(sk, skb, SIGURG, &scp->other_receive_queue) == 0) {			sk->protinfo.dn.numoth_rcv++;			scp->other_report = 0;			queued = 1;		}	}	dn_nsp_send_oth_ack(sk);out:	if (!queued)		kfree_skb(skb);}static void dn_nsp_data(struct sock *sk, struct sk_buff *skb){	int queued = 0;	unsigned short segnum;	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;	struct dn_scp *scp = &sk->protinfo.dn;	if (skb->len < 2)		goto out;	cb->segnum = segnum = dn_ntohs(*(__u16 *)skb->data);	skb_pull(skb, 2);	if (((sk->protinfo.dn.numdat_rcv + 1) & 0x0FFF) ==                      (segnum & 0x0FFF)) {                if (dn_queue_skb(sk, skb, SIGIO, &sk->receive_queue) == 0) {			sk->protinfo.dn.numdat_rcv++;                	queued = 1;                }		if ((scp->flowloc_sw == DN_SEND) && dn_congested(sk)) {			scp->flowloc_sw = DN_DONTSEND;			dn_nsp_send_lnk(sk, DN_DONTSEND);		}        }	dn_nsp_send_data_ack(sk);out:	if (!queued)		kfree_skb(skb);}/* * If one of our conninit messages is returned, this function * deals with it. It puts the socket into the NO_COMMUNICATION * state. */static void dn_returned_conn_init(struct sock *sk, struct sk_buff *skb){	struct dn_scp *scp = &sk->protinfo.dn;	if (scp->state == DN_CI) {		scp->state = DN_NC;		sk->state = TCP_CLOSE;		if (!sk->dead)			sk->state_change(sk);	}	kfree_skb(skb);}static void dn_nsp_no_socket(struct sk_buff *skb, unsigned short reason){	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;	if ((reason != NSP_REASON_OK) && ((cb->nsp_flags & 0x0c) == 0x08)) {		switch(cb->nsp_flags & 0x70) {			case 0x10:			case 0x60: /* (Retransmitted) Connect Init */				dn_nsp_return_disc(skb, NSP_DISCINIT, reason);				break;			case 0x20: /* Connect Confirm */				dn_nsp_return_disc(skb, NSP_DISCCONF, reason);				break;		}	}	kfree_skb(skb);}static int dn_nsp_rx_packet(struct sk_buff *skb){	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;	struct sock *sk = NULL;	unsigned char *ptr = (unsigned char *)skb->data;	unsigned short reason = NSP_REASON_NL;	skb->h.raw    = skb->data;	cb->nsp_flags = *ptr++;	if (decnet_debug_level & 2)		printk(KERN_DEBUG "dn_nsp_rx: Message type 0x%02x\n", (int)cb->nsp_flags);	if (skb->len < 2) 		goto free_out;	if (cb->nsp_flags & 0x83) 		goto free_out;	/*	 * Returned packets...	 * Swap src & dst and look up in the normal way.	 */	if (cb->rt_flags & DN_RT_F_RTS) {		unsigned short tmp = cb->dst_port;		cb->dst_port = cb->src_port;		cb->src_port = tmp;		tmp = cb->dst;		cb->dst = cb->src;		cb->src = tmp;		sk = dn_find_by_skb(skb);		goto got_it;	}	/*	 * Filter out conninits and useless packet types	 */	if ((cb->nsp_flags & 0x0c) == 0x08) {		switch(cb->nsp_flags & 0x70) {			case 0x00: /* NOP */			case 0x70: /* Reserved */			case 0x50: /* Reserved, Phase II node init */				goto free_out;			case 0x10:			case 0x60:				sk = dn_find_listener(skb, &reason);				goto got_it;		}	}	if (skb->len < 3)		goto free_out;	/*	 * Grab the destination address.	 */	cb->dst_port = *(unsigned short *)ptr;	cb->src_port = 0;	ptr += 2;	/*	 * If not a connack, grab the source address too.	 */	if (skb->len >= 5) {		cb->src_port = *(unsigned short *)ptr;		ptr += 2;		skb_pull(skb, 5);	}	/*	 * Find the socket to which this skb is destined.	 */	sk = dn_find_by_skb(skb);got_it:	if (sk != NULL) {		struct dn_scp *scp = &sk->protinfo.dn;		int ret;		/* Reset backoff */		scp->nsp_rxtshift = 0;		bh_lock_sock(sk);		ret = 0;		if (sk->lock.users == 0)			ret = dn_nsp_backlog_rcv(sk, skb);		else			sk_add_backlog(sk, skb);		bh_unlock_sock(sk);		sock_put(sk);		return ret;	}	dn_nsp_no_socket(skb, reason);	return 1;free_out:	kfree_skb(skb);	return 0;}int dn_nsp_rx(struct sk_buff *skb){	return NF_HOOK(PF_DECnet, NF_DN_LOCAL_IN, skb, skb->dev, NULL, dn_nsp_rx_packet);}/* * This is the main receive routine for sockets. It is called * from the above when the socket is not busy, and also from * sock_release() when there is a backlog queued up. */int dn_nsp_backlog_rcv(struct sock *sk, struct sk_buff *skb){	struct dn_scp *scp = &sk->protinfo.dn;	struct dn_skb_cb *cb = (struct dn_skb_cb *)skb->cb;	if (cb->rt_flags & DN_RT_F_RTS) {		dn_returned_conn_init(sk, skb);		return 0;	}	/*	 * Control packet.	 */	if ((cb->nsp_flags & 0x0c) == 0x08) {		switch(cb->nsp_flags & 0x70) {			case 0x10:			case 0x60:				dn_nsp_conn_init(sk, skb);				break;			case 0x20:				dn_nsp_conn_conf(sk, skb);				break;			case 0x30:				dn_nsp_disc_init(sk, skb);				break;			case 0x40:      				dn_nsp_disc_conf(sk, skb);				break;		}	} else if (cb->nsp_flags == 0x24) {		/*		 * Special for connacks, 'cos they don't have		 * ack data or ack otherdata info.		 */		dn_nsp_conn_ack(sk, skb);	} else {		int other = 1;		/* both data and ack frames can kick a CC socket into RUN */		if ((scp->state == DN_CC) && !sk->dead) {			scp->state = DN_RUN;			sk->state = TCP_ESTABLISHED;			sk->state_change(sk);		}		if ((cb->nsp_flags & 0x1c) == 0)			other = 0;		if (cb->nsp_flags == 0x04)			other = 0;		/*		 * Read out ack data here, this applies equally		 * to data, other data, link serivce and both		 * ack data and ack otherdata.		 */		dn_process_ack(sk, skb, other);		/*		 * If we've some sort of data here then call a		 * suitable routine for dealing with it, otherwise		 * the packet is an ack and can be discarded.		 */		if ((cb->nsp_flags & 0x0c) == 0) {			if (scp->state != DN_RUN)				goto free_out;			switch(cb->nsp_flags) {				case 0x10: /* LS */					dn_nsp_linkservice(sk, skb);					break;				case 0x30: /* OD */					dn_nsp_otherdata(sk, skb);					break;				default:					dn_nsp_data(sk, skb);			}		} else { /* Ack, chuck it out here */free_out:			kfree_skb(skb);		}	}	return 0;}

⌨️ 快捷键说明

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