📄 dn_nsp_in.c
字号:
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 + -