📄 tcpsp_conn.c
字号:
struct rtable *rt; /* Route to the other host */ struct iphdr *iph = skb->nh.iph; u8 tos = iph->tos; int mtu; EnterFunction(7); if (ip_route_output(&rt, iph->daddr, 0, RT_TOS(tos), 0)) { TCPSP_DBG_RL("tcpsp_xmit(): ip_route_output error, " "dest: %u.%u.%u.%u\n", NIPQUAD(iph->daddr)); goto tx_error_icmp; } /* MTU checking ??? */ mtu = rt->u.dst.pmtu; if ((skb->len > mtu) && (iph->frag_off&__constant_htons(IP_DF))) { icmp_send(skb, ICMP_DEST_UNREACH,ICMP_FRAG_NEEDED, htonl(mtu)); ip_rt_put(rt); TCPSP_DBG_RL("tcpsp_xmit(): frag needed\n"); goto tx_error; } /* drop old route */ dst_release(skb->dst); skb->dst = &rt->u.dst;#ifdef CONFIG_NETFILTER_DEBUG skb->nf_debug = 1 << NF_IP_LOCAL_OUT;#endif /* CONFIG_NETFILTER_DEBUG */ ip_send(skb); LeaveFunction(7); return NF_STOLEN; tx_error_icmp: dst_link_failure(skb); tx_error: kfree_skb(skb); return NF_STOLEN;}/* * Bind a connection entry with the corresponding packet_xmit. * Called by tcpsp_conn_new. */static inline void tcpsp_bind_xmit(struct tcpsp_conn *cp){ cp->packet_xmit = tcpsp_xmit;}static inline voidtcpsp_timeout_attach(struct tcpsp_conn *cp, struct tcpsp_timeout_table *tt){ atomic_inc(&tt->refcnt); cp->timeout_table = tt;}static inline void tcpsp_timeout_detach(struct tcpsp_conn *cp){ struct tcpsp_timeout_table *tt = cp->timeout_table; if (!tt) return; cp->timeout_table = NULL; atomic_dec(&tt->refcnt);}static void tcpsp_conn_expire(unsigned long data){ struct tcpsp_conn *cp = (struct tcpsp_conn *)data; if (cp->timeout_table) cp->timeout = cp->timeout_table->timeout[TCPSP_S_TIME_WAIT]; else cp->timeout = tcpsp_timeout_tbl.timeout[TCPSP_S_TIME_WAIT]; /* * hey, I'm using it */ atomic_inc(&cp->refcnt); /* * unhash it if it is hashed in the conn table */ tcpsp_conn_unhash(cp); /* * refcnt==1 implies I'm the only one referrer */ if (atomic_read(&cp->refcnt) == 1) { /* make sure that there is no timer on it now */ if (timer_pending(&cp->timer)) del_timer(&cp->timer); tcpsp_timeout_detach(cp); atomic_dec(&tcpsp_conn_count); kmem_cache_free(tcpsp_conn_cachep, cp); return; } TCPSP_DBG(5, "delayed: refcnt-1=%d\n", atomic_read(&cp->refcnt)-1); tcpsp_conn_put(cp);}static inline void fill_conn_tuple(struct conn_tuple *t, struct sock *sk){ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); t->laddr = sk->rcv_saddr; t->lport = sk->sport; t->raddr = sk->daddr; t->rport = sk->dport; t->splice_iss = tp->snd_nxt; t->splice_irs = tp->rcv_nxt; t->splice_tsv = tp->rcv_tsval; t->splice_tse = tp->rcv_tsecr; t->timestamp_ok = tp->tstamp_ok;}/* * Create and hash a new tcpsp into the tcpsp_conn_tabs. */struct tcpsp_conn *tcpsp_conn_new(struct socket *sock1, struct socket *sock2, int n){ struct tcp_opt *tp1, *tp2; struct tcpsp_conn *cp; cp = kmem_cache_alloc(tcpsp_conn_cachep, GFP_ATOMIC); if (cp == NULL) { TCPSP_ERR_RL("tcpsp_conn_new: no memory available.\n"); return NULL; } memset(cp, 0, sizeof(*cp)); cp->lock = SPIN_LOCK_UNLOCKED; init_timer(&cp->timer); cp->timer.data = (unsigned long) cp; cp->timer.function = tcpsp_conn_expire; tcpsp_timeout_attach(cp, &tcpsp_timeout_tbl); cp->socket[0] = sock1; cp->socket[1] = sock2; atomic_set(&cp->need_rst, 1); fill_conn_tuple(&cp->conn[0], sock1->sk); fill_conn_tuple(&cp->conn[1], sock2->sk); cp->conn[1].splice_iss += n; atomic_inc(&tcpsp_conn_count); /* Set its state and timeout */ if (sock1->sk->state == TCP_ESTABLISHED && sock2->sk->state == TCP_ESTABLISHED) set_state_timeout(cp, TCPSP_S_ESTABLISHED); else /* probably need to consider other states here */ set_state_timeout(cp, TCPSP_S_NONE); /* Bind its packet transmitter */ tcpsp_bind_xmit(cp); atomic_set(&cp->refcnt, 1); /* Hash it in the tcpsp_conn_tab finally */ tcpsp_conn_hash(cp); tp1 = &(sock1->sk->tp_pinfo.af_tcp); tp2 = &(sock2->sk->tp_pinfo.af_tcp); TCPSP_DBG(5, "sock1: rcv_nxt %u snd_nxt %u snd_una %u\n", tp1->rcv_nxt, tp1->snd_nxt, tp1->snd_una); TCPSP_DBG(5, "sock2: rcv_nxt %u snd_nxt %u snd_una %u\n", tp2->rcv_nxt, tp2->snd_nxt, tp2->snd_una); TCPSP_DBG(5, "sock2: iss %u irs %u\n", cp->conn[1].splice_iss, cp->conn[1].splice_irs); return cp;}/* * /proc/net/tcpsp_conn entries */static inttcpsp_conn_getinfo(char *buffer, char **start, off_t offset, int length){ off_t pos=0; int idx, len=0; char temp[70]; struct tcpsp_conn *cp; struct list_head *l, *e; pos = 128; if (pos > offset) { len += sprintf(buffer+len, "%-127s\n", "FromIP FPrt ToIP TPrt LocalIP LPrt DestIP DPrt State Expires"); } for(idx = 0; idx < TCPSP_CONN_TAB_SIZE; idx++) { /* * Lock is actually only need in next loop * we are called from uspace: must stop bh. */ read_lock_bh(&tcpsp_conn_lock); l = &tcpsp_conn_tab1[idx]; for (e=l->next; e!=l; e=e->next) { cp = list_entry(e, struct tcpsp_conn, f_list); pos += 128; if (pos <= offset) continue; sprintf(temp, "%08X %04X %08X %04X %08X %04X %08X %04X %-11s %7lu", ntohl(cp->conn[0].raddr), ntohs(cp->conn[0].rport), ntohl(cp->conn[0].laddr), ntohs(cp->conn[0].lport), ntohl(cp->conn[1].laddr), ntohs(cp->conn[1].lport), ntohl(cp->conn[1].raddr), ntohs(cp->conn[1].rport), tcpsp_state_name(cp->state), cp->timer.expires-jiffies); len += sprintf(buffer+len, "%-127s\n", temp); if (pos >= offset+length) { read_unlock_bh(&tcpsp_conn_lock); goto done; } } read_unlock_bh(&tcpsp_conn_lock); } done: *start = buffer+len-(pos-offset); /* Start of wanted data */ len = pos-offset; if (len > length) len = length; if (len < 0) len = 0; return len;}/* * Flush all the connection entries in the tcpsp_conn_tab */static void tcpsp_conn_flush(void){ int idx; struct list_head *list; struct tcpsp_conn *cp; flush_again: for (idx=0; idx<TCPSP_CONN_TAB_SIZE; idx++) { /* * Lock is actually needed in this loop. */ write_lock_bh(&tcpsp_conn_lock); list = &tcpsp_conn_tab1[idx]; while (!list_empty(list)) { cp = list_entry(list->next, struct tcpsp_conn, f_list); TCPSP_DBG(4, "delete the spliced connection\n"); if (del_timer(&cp->timer)) { write_unlock(&tcpsp_conn_lock); tcpsp_conn_expire_now(cp); write_lock(&tcpsp_conn_lock); } } write_unlock_bh(&tcpsp_conn_lock); } /* the counter may be not NULL, because maybe some conn entries are run by slow timer handler or unhashed but still referred */ if (atomic_read(&tcpsp_conn_count) != 0) { schedule(); goto flush_again; }}int tcpsp_conn_init(void){ int idx; /* * Allocate the connection hash table and initialize its list heads */ if (!(tcpsp_conn_tab1 = vmalloc(TCPSP_CONN_TAB_SIZE * sizeof(struct list_head)))) return -ENOMEM; if (!(tcpsp_conn_tab2 = vmalloc(TCPSP_CONN_TAB_SIZE * sizeof(struct list_head)))) { vfree(tcpsp_conn_tab1); return -ENOMEM; } /* Allocate tcpsp_conn slab cache */ tcpsp_conn_cachep = kmem_cache_create("tcpsp_conn", sizeof(struct tcpsp_conn), 0, SLAB_HWCACHE_ALIGN, NULL, NULL); if (!tcpsp_conn_cachep) { vfree(tcpsp_conn_tab1); vfree(tcpsp_conn_tab2); return -ENOMEM; } TCPSP_INFO("Connection hash table configured " "(size=%d, memory=%ldKbytes)\n", TCPSP_CONN_TAB_SIZE, (long)(TCPSP_CONN_TAB_SIZE*sizeof(struct list_head))/1024); TCPSP_DBG(0, "Each connection entry needs %d bytes at least\n", sizeof(struct tcpsp_conn)); for (idx = 0; idx < TCPSP_CONN_TAB_SIZE; idx++) { INIT_LIST_HEAD(&tcpsp_conn_tab1[idx]); INIT_LIST_HEAD(&tcpsp_conn_tab2[idx]); } proc_net_create("tcpsp_conn", 0, tcpsp_conn_getinfo); return 0;}void tcpsp_conn_cleanup(void){ /* flush all the connection entries first */ tcpsp_conn_flush(); /* Release the empty cache */ kmem_cache_destroy(tcpsp_conn_cachep); proc_net_remove("tcpsp_conn"); vfree(tcpsp_conn_tab1); vfree(tcpsp_conn_tab2);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -