📄 tcp.c
字号:
newconf.nwtc_flags= ((unsigned long)new_di_flags << 16) | new_en_flags; all_flags= new_en_flags | new_di_flags; /* check the access modes */ if ((all_flags & NWTC_LOCPORT_MASK) != NWTC_LP_UNSET) { for (i=0, fd_ptr= tcp_fd_table; i<TCP_FD_NR; i++, fd_ptr++) { if (fd_ptr == tcp_fd) continue; if (!(fd_ptr->tf_flags & TFF_INUSE)) continue; if (fd_ptr->tf_port != tcp_fd->tf_port) continue; flags= fd_ptr->tf_tcpconf.nwtc_flags; if ((flags & NWTC_LOCPORT_MASK) == NWTC_LP_UNSET) continue; if (fd_ptr->tf_tcpconf.nwtc_locport != newconf.nwtc_locport) continue; if ((flags & NWTC_ACC_MASK) != (all_flags & NWTC_ACC_MASK) || (all_flags & NWTC_ACC_MASK) == NWTC_EXCL) { tcp_fd->tf_flags &= ~TFF_IOCTL_IP; reply_thr_get(tcp_fd, EADDRINUSE, TRUE); bf_afree(data); return NW_OK; } } } tcp_fd->tf_tcpconf= newconf; if ((all_flags & NWTC_ACC_MASK) && ((all_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SET || (all_flags & NWTC_LOCPORT_MASK) == NWTC_LP_SEL) && (all_flags & NWTC_REMADDR_MASK) && (all_flags & NWTC_REMPORT_MASK)) tcp_fd->tf_flags |= TFF_CONF_SET; else { tcp_fd->tf_flags &= ~TFF_CONF_SET; } bf_afree(data); tcp_fd->tf_flags &= ~TFF_IOCTL_IP; reply_thr_get(tcp_fd, NW_OK, TRUE); return NW_OK;}/*tcp_setopt*/PRIVATE int tcp_setopt(tcp_fd)tcp_fd_t *tcp_fd;{ nwio_tcpopt_t *tcpopt; nwio_tcpopt_t oldopt, newopt; acc_t *data; unsigned int new_en_flags, new_di_flags, old_en_flags, old_di_flags; data= (*tcp_fd->tf_get_userdata) (tcp_fd->tf_srfd, 0, sizeof(nwio_tcpopt_t), TRUE); if (!data) return EFAULT; data= bf_packIffLess(data, sizeof(nwio_tcpopt_t));assert (data->acc_length == sizeof(nwio_tcpopt_t)); tcpopt= (nwio_tcpopt_t *)ptr2acc_data(data); oldopt= tcp_fd->tf_tcpopt; newopt= *tcpopt; old_en_flags= oldopt.nwto_flags & 0xffff; old_di_flags= (oldopt.nwto_flags >> 16) & 0xffff; new_en_flags= newopt.nwto_flags & 0xffff; new_di_flags= (newopt.nwto_flags >> 16) & 0xffff; if (new_en_flags & new_di_flags) { tcp_fd->tf_flags &= ~TFF_IOCTL_IP; reply_thr_get(tcp_fd, EBADMODE, TRUE); return NW_OK; } /* NWTO_SND_URG_MASK */ if (!((new_en_flags | new_di_flags) & NWTO_SND_URG_MASK)) { new_en_flags |= (old_en_flags & NWTO_SND_URG_MASK); new_di_flags |= (old_di_flags & NWTO_SND_URG_MASK); } /* NWTO_RCV_URG_MASK */ if (!((new_en_flags | new_di_flags) & NWTO_RCV_URG_MASK)) { new_en_flags |= (old_en_flags & NWTO_RCV_URG_MASK); new_di_flags |= (old_di_flags & NWTO_RCV_URG_MASK); } /* NWTO_BSD_URG_MASK */ if (!((new_en_flags | new_di_flags) & NWTO_BSD_URG_MASK)) { new_en_flags |= (old_en_flags & NWTO_BSD_URG_MASK); new_di_flags |= (old_di_flags & NWTO_BSD_URG_MASK); } else { if (tcp_fd->tf_conn == NULL) { bf_afree(data); tcp_fd->tf_flags &= ~TFF_IOCTL_IP; reply_thr_get(tcp_fd, EINVAL, TRUE); return NW_OK; } } /* NWTO_DEL_RST_MASK */ if (!((new_en_flags | new_di_flags) & NWTO_DEL_RST_MASK)) { new_en_flags |= (old_en_flags & NWTO_DEL_RST_MASK); new_di_flags |= (old_di_flags & NWTO_DEL_RST_MASK); } /* NWTO_BULK_MASK */ if (!((new_en_flags | new_di_flags) & NWTO_BULK_MASK)) { new_en_flags |= (old_en_flags & NWTO_BULK_MASK); new_di_flags |= (old_di_flags & NWTO_BULK_MASK); } newopt.nwto_flags= ((unsigned long)new_di_flags << 16) | new_en_flags; tcp_fd->tf_tcpopt= newopt; if (newopt.nwto_flags & NWTO_SND_URG) tcp_fd->tf_flags |= TFF_WR_URG; else tcp_fd->tf_flags &= ~TFF_WR_URG; if (newopt.nwto_flags & NWTO_RCV_URG) tcp_fd->tf_flags |= TFF_RECV_URG; else tcp_fd->tf_flags &= ~TFF_RECV_URG; if (tcp_fd->tf_conn) { if (newopt.nwto_flags & NWTO_BSD_URG) tcp_fd->tf_conn->tc_flags |= TCF_BSD_URG; else tcp_fd->tf_conn->tc_flags &= ~TCF_BSD_URG; } if (newopt.nwto_flags & NWTO_DEL_RST) tcp_fd->tf_flags |= TFF_DEL_RST; else tcp_fd->tf_flags &= ~TFF_DEL_RST; if (newopt.nwto_flags & NWTO_BULK) tcp_fd->tf_flags &= ~TFF_PUSH_DATA; else tcp_fd->tf_flags |= TFF_PUSH_DATA; bf_afree(data); tcp_fd->tf_flags &= ~TFF_IOCTL_IP; reply_thr_get(tcp_fd, NW_OK, TRUE); return NW_OK;}PRIVATE tcpport_t find_unused_port(fd)int fd;{ tcpport_t port, nw_port; for (port= 0x8000+fd; port < 0xffff-TCP_FD_NR; port+= TCP_FD_NR) { nw_port= htons(port); if (is_unused_port(nw_port)) return nw_port; } for (port= 0x8000; port < 0xffff; port++) { nw_port= htons(port); if (is_unused_port(nw_port)) return nw_port; } ip_panic(( "unable to find unused port (shouldn't occur)" )); return 0;}PRIVATE int is_unused_port(port)tcpport_t port;{ int i; tcp_fd_t *tcp_fd; tcp_conn_t *tcp_conn; for (i= 0, tcp_fd= tcp_fd_table; i<TCP_FD_NR; i++, tcp_fd++) { if (!(tcp_fd->tf_flags & TFF_CONF_SET)) continue; if (tcp_fd->tf_tcpconf.nwtc_locport == port) return FALSE; } for (i= tcp_conf_nr, tcp_conn= tcp_conn_table+i; i<TCP_CONN_NR; i++, tcp_conn++) /* the first tcp_conf_nr ports are special */ { if (!(tcp_conn->tc_flags & TCF_INUSE)) continue; if (tcp_conn->tc_locport == port) return FALSE; } return TRUE;}PRIVATE int reply_thr_put(tcp_fd, reply, for_ioctl)tcp_fd_t *tcp_fd;int reply;int for_ioctl;{ assert (tcp_fd); return (*tcp_fd->tf_put_userdata)(tcp_fd->tf_srfd, reply, (acc_t *)0, for_ioctl);}PRIVATE void reply_thr_get(tcp_fd, reply, for_ioctl)tcp_fd_t *tcp_fd;int reply;int for_ioctl;{ acc_t *result; result= (*tcp_fd->tf_get_userdata)(tcp_fd->tf_srfd, reply, (size_t)0, for_ioctl); assert (!result);}PUBLIC int tcp_su4listen(tcp_fd, tcp_conn, do_listenq)tcp_fd_t *tcp_fd;tcp_conn_t *tcp_conn;int do_listenq;{ tcp_conn->tc_locport= tcp_fd->tf_tcpconf.nwtc_locport; tcp_conn->tc_locaddr= tcp_fd->tf_port->tp_ipaddr; if (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RP) tcp_conn->tc_remport= tcp_fd->tf_tcpconf.nwtc_remport; else tcp_conn->tc_remport= 0; if (tcp_fd->tf_tcpconf.nwtc_flags & NWTC_SET_RA) tcp_conn->tc_remaddr= tcp_fd->tf_tcpconf.nwtc_remaddr; else tcp_conn->tc_remaddr= 0; tcp_setup_conn(tcp_fd->tf_port, tcp_conn); tcp_conn->tc_fd= tcp_fd; tcp_conn->tc_connInprogress= 1; tcp_conn->tc_orglisten= TRUE; tcp_conn->tc_state= TCS_LISTEN; tcp_conn->tc_rt_dead= TCP_DEF_RT_MAX_LISTEN; if (do_listenq) { tcp_fd->tf_flags |= TFF_LISTENQ; tcp_reply_ioctl(tcp_fd, NW_OK); return NW_OK; } return NW_SUSPEND;}/*find_empty_connThis function returns a connection that is not inuse.This includes connections that are never used, and connections without auser that are not used for a while.*/PRIVATE tcp_conn_t *find_empty_conn(){ int i; tcp_conn_t *tcp_conn; for (i=tcp_conf_nr, tcp_conn= tcp_conn_table+i; i<TCP_CONN_NR; i++, tcp_conn++) /* the first tcp_conf_nr connections are reserved for * RSTs */ { if (tcp_conn->tc_flags == TCF_EMPTY) { tcp_conn->tc_connInprogress= 0; tcp_conn->tc_fd= NULL; return tcp_conn; } if (tcp_conn->tc_fd) continue; if (tcp_conn->tc_senddis > get_time()) continue; if (tcp_conn->tc_state != TCS_CLOSED) { tcp_close_connection (tcp_conn, ENOCONN); } tcp_conn->tc_flags= 0; return tcp_conn; } return NULL;}/*find_conn_entryThis function return a connection matching locport, locaddr, remport, remaddr.If no such connection exists NULL is returned.If a connection exists without mainuser it is closed.*/PRIVATE tcp_conn_t *find_conn_entry(locport, locaddr, remport, remaddr)tcpport_t locport;ipaddr_t locaddr;tcpport_t remport;ipaddr_t remaddr;{ tcp_conn_t *tcp_conn; int i, state; assert(remport); assert(remaddr); for (i=tcp_conf_nr, tcp_conn= tcp_conn_table+i; i<TCP_CONN_NR; i++, tcp_conn++) /* the first tcp_conf_nr connections are reserved for RSTs */ { if (tcp_conn->tc_flags == TCF_EMPTY) continue; if (tcp_conn->tc_locport != locport || tcp_conn->tc_locaddr != locaddr || tcp_conn->tc_remport != remport || tcp_conn->tc_remaddr != remaddr) continue; if (tcp_conn->tc_fd) return tcp_conn; state= tcp_conn->tc_state; if (state != TCS_CLOSED) { tcp_close_connection(tcp_conn, ENOCONN); } return tcp_conn; } return NULL;}PRIVATE void read_ip_packets(tcp_port)tcp_port_t *tcp_port;{ int result; do { tcp_port->tp_flags |= TPF_READ_IP; result= ip_read(tcp_port->tp_ipfd, TCP_MAX_DATAGRAM); if (result == NW_SUSPEND) { tcp_port->tp_flags |= TPF_READ_SP; return; } assert(result == NW_OK); tcp_port->tp_flags &= ~TPF_READ_IP; } while(!(tcp_port->tp_flags & TPF_READ_IP));}/*find_best_conn*/PRIVATE tcp_conn_t *find_best_conn(ip_hdr, tcp_hdr)ip_hdr_t *ip_hdr;tcp_hdr_t *tcp_hdr;{ int best_level, new_level; tcp_conn_t *best_conn, *listen_conn, *tcp_conn; tcp_fd_t *tcp_fd; int i; ipaddr_t locaddr; ipaddr_t remaddr; tcpport_t locport; tcpport_t remport; locaddr= ip_hdr->ih_dst; remaddr= ip_hdr->ih_src; locport= tcp_hdr->th_dstport; remport= tcp_hdr->th_srcport; if (!remport) /* This can interfere with a listen, so we reject it * by clearing the requested port */ locport= 0; best_level= 0; best_conn= NULL; listen_conn= NULL; for (i= tcp_conf_nr, tcp_conn= tcp_conn_table+i; i<TCP_CONN_NR; i++, tcp_conn++) /* the first tcp_conf_nr connections are reserved for RSTs */ { if (!(tcp_conn->tc_flags & TCF_INUSE)) continue; /* First fast check for open connections. */ if (tcp_conn->tc_locaddr == locaddr && tcp_conn->tc_locport == locport && tcp_conn->tc_remport == remport && tcp_conn->tc_remaddr == remaddr && tcp_conn->tc_fd) { return tcp_conn; } /* Now check for listens and abandoned connections. */ if (tcp_conn->tc_locaddr != locaddr) { continue; } new_level= 0; if (tcp_conn->tc_locport) { if (tcp_conn->tc_locport != locport) { continue; } new_level += 4; } if (tcp_conn->tc_remport) { if (tcp_conn->tc_remport != remport) { continue; } new_level += 1; } if (tcp_conn->tc_remaddr) { if (tcp_conn->tc_remaddr != remaddr) { continue; } new_level += 2; } if (new_level<best_level) continue; if (new_level != 7 && tcp_conn->tc_state != TCS_LISTEN) continue; if (new_level == 7) /* We found an abandoned connection */ { assert(!tcp_conn->tc_fd); if (best_conn && tcp_Lmod4G(tcp_conn->tc_ISS, best_conn->tc_ISS)) { continue; } best_conn= tcp_conn; continue; } if (!(tcp_hdr->th_flags & THF_SYN)) continue; best_level= new_level; listen_conn= tcp_conn; assert(listen_conn->tc_fd != NULL); } if (listen_conn && listen_conn->tc_fd->tf_flags & TFF_LISTENQ && listen_conn->tc_fd->tf_conn == listen_conn) { /* Special processing for listen queues. Only accept the * connection if there is empty space in the queue and * there are empty connections as well. */ listen_conn= new_conn_for_queue(listen_conn->tc_fd); } if (!best_conn && !listen_conn) { if ((tcp_hdr->th_flags & THF_SYN) && maybe_listen(locaddr, locport, remaddr, remport)) { /* Quick hack to implement listen back logs: * if a SYN arrives and there is no listen waiting * for that packet, then no reply is sent. */ return NULL; } for (i=0, tcp_conn= tcp_conn_table; i<tcp_conf_nr; i++, tcp_conn++) { /* find valid port to send RST */ if ((tcp_conn->tc_flags & TCF_INUSE) && tcp_conn->tc_locaddr==locaddr) { break; } } assert (tcp_conn); assert (tcp_conn->tc_state == TCS_CLOSED); tcp_conn->tc_locport= locport; tcp_conn->tc_locaddr= locaddr; tcp_conn->tc_remport= remport; tcp_conn->tc_remaddr= remaddr; assert (!tcp_conn->tc_fd); return tcp_conn; } if (best_conn) { if (!listen_conn) { assert(!best_conn->tc_fd); return best_conn; } assert(listen_conn->tc_connInprogress); tcp_fd= listen_conn->tc_fd; assert(tcp_fd); assert((tcp_fd->tf_flags & TFF_LISTENQ) || tcp_fd->tf_conn == listen_conn); if (best_conn->tc_state != TCS_CLOSED) tcp_close_connection(best_conn, ENOCONN);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -