-
-int tcp_listen_start(struct sock *sk)
-{
- struct inet_opt *inet = inet_sk(sk);
- struct tcp_opt *tp = tcp_sk(sk);
- struct tcp_listen_opt *lopt;
-
- sk->sk_max_ack_backlog = 0;
- sk->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;
- get_random_bytes(&lopt->hash_rnd, 4);
-
- 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->sk_state = TCP_LISTEN;
- if (!sk->sk_prot->get_port(sk, inet->num)) {
- inet->sport = htons(inet->num);
-
- sk_dst_reset(sk);
- sk->sk_prot->hash(sk);
-
- return 0;
- }
-
- sk->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 = tcp_sk(sk);
- 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);
-
- 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(!sock_owned_by_user(child));
- 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);
-
- sk_acceptq_removed(sk);
- tcp_openreq_fastfree(req);
- }
- BUG_TRAP(!sk->sk_ack_backlog);
-}
-
-/*
- * 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 tcp_opt *tp = tcp_sk(sk);
- struct task_struct *tsk = current;
- DEFINE_WAIT(wait);
-
- while ((1 << sk->sk_state) & ~(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) {
- if (sk->sk_err)
- return sock_error(sk);
- if ((1 << sk->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);
-
- prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
- tp->write_pending++;
-
- release_sock(sk);
- *timeo_p = schedule_timeout(*timeo_p);
- lock_sock(sk);
-
- finish_wait(sk->sk_sleep, &wait);
- tp->write_pending--;
- }
- return 0;
-}
-
-static inline int tcp_memory_free(struct sock *sk)
-{
- return sk->sk_wmem_queued < sk->sk_sndbuf;
-}
-
-/*
- * Wait for more memory for a socket
- */
-static int wait_for_tcp_memory(struct sock *sk, long *timeo)
-{
- struct tcp_opt *tp = tcp_sk(sk);
- int err = 0;
- long vm_wait = 0;
- long current_timeo = *timeo;
- DEFINE_WAIT(wait);
-
- if (tcp_memory_free(sk))
- current_timeo = vm_wait = (net_random() % (HZ / 5)) + 2;
-
- for (;;) {
- set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
-
- prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
-
- if (sk->sk_err || (sk->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->sk_socket->flags);
- if (tcp_memory_free(sk) && !vm_wait)
- break;
-
- set_bit(SOCK_NOSPACE, &sk->sk_socket->flags);
- tp->write_pending++;
- release_sock(sk);
- if (!tcp_memory_free(sk) || vm_wait)
- current_timeo = schedule_timeout(current_timeo);
- lock_sock(sk);
- tp->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:
- finish_wait(sk->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;
-}
-
-static inline int can_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 void fill_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)