📄 tcp.c
字号:
if (answ && !skb_queue_empty(&sk->receive_queue)) answ -= ((struct sk_buff*)sk->receive_queue.prev)->h.th->fin; } else answ = tp->urg_seq - tp->copied_seq; release_sock(sk); break; case SIOCATMARK: { answ = tp->urg_data && tp->urg_seq == tp->copied_seq; break; } case SIOCOUTQ: if (sk->state == TCP_LISTEN) return(-EINVAL); if ((1<<sk->state) & (TCPF_SYN_SENT|TCPF_SYN_RECV)) answ = 0; else answ = tp->write_seq - tp->snd_una; break; default: return(-ENOIOCTLCMD); }; return put_user(answ, (int *)arg);}int tcp_listen_start(struct sock *sk){ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); struct tcp_listen_opt *lopt; sk->max_ack_backlog = 0; sk->ack_backlog = 0; tp->accept_queue = tp->accept_queue_tail = NULL; tp->syn_wait_lock = RW_LOCK_UNLOCKED; tcp_delack_init(tp); lopt = kmalloc(sizeof(struct tcp_listen_opt), GFP_KERNEL); if (!lopt) return -ENOMEM; memset(lopt, 0, sizeof(struct tcp_listen_opt)); for (lopt->max_qlen_log = 6; ; lopt->max_qlen_log++) if ((1<<lopt->max_qlen_log) >= sysctl_max_syn_backlog) break; write_lock_bh(&tp->syn_wait_lock); tp->listen_opt = lopt; write_unlock_bh(&tp->syn_wait_lock); /* There is race window here: we announce ourselves listening, * but this transition is still not validated by get_port(). * It is OK, because this socket enters to hash table only * after validation is complete. */ sk->state = TCP_LISTEN; if (sk->prot->get_port(sk, sk->num) == 0) { sk->sport = htons(sk->num); sk_dst_reset(sk); sk->prot->hash(sk); return 0; } sk->state = TCP_CLOSE; write_lock_bh(&tp->syn_wait_lock); tp->listen_opt = NULL; write_unlock_bh(&tp->syn_wait_lock); kfree(lopt); return -EADDRINUSE;}/* * This routine closes sockets which have been at least partially * opened, but not yet accepted. */static void tcp_listen_stop (struct sock *sk){ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); struct tcp_listen_opt *lopt = tp->listen_opt; struct open_request *acc_req = tp->accept_queue; struct open_request *req; int i; tcp_delete_keepalive_timer(sk); /* make all the listen_opt local to us */ write_lock_bh(&tp->syn_wait_lock); tp->listen_opt =NULL; write_unlock_bh(&tp->syn_wait_lock); tp->accept_queue = tp->accept_queue_tail = NULL; if (lopt->qlen) { for (i=0; i<TCP_SYNQ_HSIZE; i++) { while ((req = lopt->syn_table[i]) != NULL) { lopt->syn_table[i] = req->dl_next; lopt->qlen--; tcp_openreq_free(req); /* Following specs, it would be better either to send FIN * (and enter FIN-WAIT-1, it is normal close) * or to send active reset (abort). * Certainly, it is pretty dangerous while synflood, but it is * bad justification for our negligence 8) * To be honest, we are not able to make either * of the variants now. --ANK */ } } } BUG_TRAP(lopt->qlen == 0); kfree(lopt); while ((req=acc_req) != NULL) { struct sock *child = req->sk; acc_req = req->dl_next; local_bh_disable(); bh_lock_sock(child); BUG_TRAP(child->lock.users==0); sock_hold(child); tcp_disconnect(child, O_NONBLOCK); sock_orphan(child); atomic_inc(&tcp_orphan_count); tcp_destroy_sock(child); bh_unlock_sock(child); local_bh_enable(); sock_put(child); tcp_acceptq_removed(sk); tcp_openreq_fastfree(req); } BUG_TRAP(sk->ack_backlog == 0);}/* * Wait for a socket to get into the connected state * * Note: Must be called with the socket locked. */static int wait_for_tcp_connect(struct sock * sk, int flags, long *timeo_p){ struct task_struct *tsk = current; DECLARE_WAITQUEUE(wait, tsk); while((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) { if(sk->err) return sock_error(sk); if((1 << sk->state) & ~(TCPF_SYN_SENT | TCPF_SYN_RECV)) return -EPIPE; if(!*timeo_p) return -EAGAIN; if(signal_pending(tsk)) return sock_intr_errno(*timeo_p); __set_task_state(tsk, TASK_INTERRUPTIBLE); add_wait_queue(sk->sleep, &wait); sk->tp_pinfo.af_tcp.write_pending++; release_sock(sk); *timeo_p = schedule_timeout(*timeo_p); lock_sock(sk); __set_task_state(tsk, TASK_RUNNING); remove_wait_queue(sk->sleep, &wait); sk->tp_pinfo.af_tcp.write_pending--; } return 0;}static inline int tcp_memory_free(struct sock *sk){ return sk->wmem_queued < sk->sndbuf;}/* * Wait for more memory for a socket */static int wait_for_tcp_memory(struct sock * sk, long *timeo){ int err = 0; long vm_wait = 0; long current_timeo = *timeo; DECLARE_WAITQUEUE(wait, current); if (tcp_memory_free(sk)) current_timeo = vm_wait = (net_random()%(HZ/5))+2; add_wait_queue(sk->sleep, &wait); for (;;) { set_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); set_current_state(TASK_INTERRUPTIBLE); if (sk->err || (sk->shutdown & SEND_SHUTDOWN)) goto do_error; if (!*timeo) goto do_nonblock; if (signal_pending(current)) goto do_interrupted; clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); if (tcp_memory_free(sk) && !vm_wait) break; set_bit(SOCK_NOSPACE, &sk->socket->flags); sk->tp_pinfo.af_tcp.write_pending++; release_sock(sk); if (!tcp_memory_free(sk) || vm_wait) current_timeo = schedule_timeout(current_timeo); lock_sock(sk); sk->tp_pinfo.af_tcp.write_pending--; if (vm_wait) { vm_wait -= current_timeo; current_timeo = *timeo; if (current_timeo != MAX_SCHEDULE_TIMEOUT && (current_timeo -= vm_wait) < 0) current_timeo = 0; vm_wait = 0; } *timeo = current_timeo; }out: current->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait); return err;do_error: err = -EPIPE; goto out;do_nonblock: err = -EAGAIN; goto out;do_interrupted: err = sock_intr_errno(*timeo); goto out;}ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags);static inline intcan_coalesce(struct sk_buff *skb, int i, struct page *page, int off){ if (i) { skb_frag_t *frag = &skb_shinfo(skb)->frags[i-1]; return page == frag->page && off == frag->page_offset+frag->size; } return 0;}static inline voidfill_page_desc(struct sk_buff *skb, int i, struct page *page, int off, int size){ skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; frag->page = page; frag->page_offset = off; frag->size = size; skb_shinfo(skb)->nr_frags = i+1;}static inline void tcp_mark_push(struct tcp_opt *tp, struct sk_buff *skb){ TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_PSH; tp->pushed_seq = tp->write_seq;}static inline int forced_push(struct tcp_opt *tp){ return after(tp->write_seq, tp->pushed_seq + (tp->max_window>>1));}static inline voidskb_entail(struct sock *sk, struct tcp_opt *tp, struct sk_buff *skb){ skb->csum = 0; TCP_SKB_CB(skb)->seq = tp->write_seq; TCP_SKB_CB(skb)->end_seq = tp->write_seq; TCP_SKB_CB(skb)->flags = TCPCB_FLAG_ACK; TCP_SKB_CB(skb)->sacked = 0; __skb_queue_tail(&sk->write_queue, skb); tcp_charge_skb(sk, skb); if (tp->send_head == NULL) tp->send_head = skb;}static inline voidtcp_mark_urg(struct tcp_opt *tp, int flags, struct sk_buff *skb){ if (flags & MSG_OOB) { tp->urg_mode = 1; tp->snd_up = tp->write_seq; TCP_SKB_CB(skb)->sacked |= TCPCB_URG; }}static inline voidtcp_push(struct sock *sk, struct tcp_opt *tp, int flags, int mss_now, int nonagle){ if (tp->send_head) { struct sk_buff *skb = sk->write_queue.prev; if (!(flags&MSG_MORE) || forced_push(tp)) tcp_mark_push(tp, skb); tcp_mark_urg(tp, flags, skb); __tcp_push_pending_frames(sk, tp, mss_now, (flags&MSG_MORE) ? 2 : nonagle); }}static int tcp_error(struct sock *sk, int flags, int err){ if (err == -EPIPE) err = sock_error(sk) ? : -EPIPE; if (err == -EPIPE && !(flags&MSG_NOSIGNAL)) send_sig(SIGPIPE, current, 0); return err;}ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset, size_t psize, int flags){ struct tcp_opt *tp = &(sk->tp_pinfo.af_tcp); int mss_now; int err; ssize_t copied; long timeo = sock_sndtimeo(sk, flags&MSG_DONTWAIT); /* Wait for a connection to finish. */ if ((1 << sk->state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) if((err = wait_for_tcp_connect(sk, 0, &timeo)) != 0) goto out_err; clear_bit(SOCK_ASYNC_NOSPACE, &sk->socket->flags); mss_now = tcp_current_mss(sk); copied = 0; err = -EPIPE; if (sk->err || (sk->shutdown & SEND_SHUTDOWN)) goto do_error; while (psize > 0) { struct sk_buff *skb = sk->write_queue.prev; int offset, size, copy, i; struct page *page; page = pages[poffset/PAGE_SIZE]; offset = poffset % PAGE_SIZE; size = min_t(size_t, psize, PAGE_SIZE-offset); if (tp->send_head==NULL || (copy = mss_now - skb->len) <= 0) {new_segment: if (!tcp_memory_free(sk)) goto wait_for_sndbuf; skb = tcp_alloc_pskb(sk, 0, tp->mss_cache, sk->allocation); if (skb == NULL) goto wait_for_memory; skb_entail(sk, tp, skb); copy = mss_now; } if (copy > size) copy = size; i = skb_shinfo(skb)->nr_frags; if (can_coalesce(skb, i, page, offset)) { skb_shinfo(skb)->frags[i-1].size += copy; } else if (i < MAX_SKB_FRAGS) { get_page(page); fill_page_desc(skb, i, page, offset, copy); } else { tcp_mark_push(tp, skb); goto new_segment; } skb->len += copy; skb->data_len += copy; skb->ip_summed = CHECKSUM_HW; tp->write_seq += copy; TCP_SKB_CB(skb)->end_seq += copy; if (!copied) TCP_SKB_CB(skb)->flags &= ~TCPCB_FLAG_PSH; copied += copy; poffset += copy; if (!(psize -= copy)) goto out; if (skb->len != mss_now || (flags&MSG_OOB)) continue; if (forced_push(tp)) { tcp_mark_push(tp, skb); __tcp_push_pending_frames(sk, tp, mss_now, 1); } else if (skb == tp->send_head) tcp_push_one(sk, mss_now); continue;wait_for_sndbuf: set_bit(SOCK_NOSPACE, &sk->socket->flags);wait_for_memory: if (copied) tcp_push(sk, tp, flags&~MSG_MORE, mss_now, 1); if ((err = wait_for_tcp_memory(sk, &timeo)) != 0) goto do_error; mss_now = tcp_current_mss(sk); }out: if (copied) tcp_push(sk, tp, flags, mss_now, tp->nonagle); return copied;do_error: if (copied) goto out;out_err: return tcp_error(sk, flags, err);}ssize_t tcp_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags){ ssize_t res; struct sock *sk = sock->sk;#define TCP_ZC_CSUM_FLAGS (NETIF_F_IP_CSUM|NETIF_F_NO_CSUM|NETIF_F_HW_CSUM) if (!(sk->route_caps & NETIF_F_SG) || !(sk->route_caps & TCP_ZC_CSUM_FLAGS)) return sock_no_sendpage(sock, page, offset, size, flags);#undef TCP_ZC_CSUM_FLAGS lock_sock(sk); TCP_CHECK_TIMER(sk); res = do_tcp_sendpages(sk, &page, offset, size, flags); TCP_CHECK_TIMER(sk); release_sock(sk); return res;}#define TCP_PAGE(sk) (sk->tp_pinfo.af_tcp.sndmsg_page)#define TCP_OFF(sk) (sk->tp_pinfo.af_tcp.sndmsg_off)static inline inttcp_copy_to_page(struct sock *sk, char *from, struct sk_buff *skb, struct page *page, int off, int copy){ int err = 0; unsigned int csum; csum = csum_and_copy_from_user(from, page_address(page)+off, copy, 0, &err); if (!err) { if (skb->ip_summed == CHECKSUM_NONE) skb->csum = csum_block_add(skb->csum, csum, skb->len); skb->len += copy; skb->data_len += copy; skb->truesize += copy; sk->wmem_queued += copy; sk->forward_alloc -= copy; } return err;}static inline intskb_add_data(struct sk_buff *skb, char *from, int copy){ int err = 0; unsigned int csum; int off = skb->len; csum = csum_and_copy_from_user(from, skb_put(skb, copy), copy, 0, &err); if (!err) { skb->csum = csum_block_add(skb->csum, csum, off); return 0; } __skb_trim(skb, off); return -EFAULT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -