当前位置:文档之家› 网络协议栈函数.doc

网络协议栈函数.doc

T i p^TTnlsfiToti Ipu H 11 i .Li

I n«Cif ri I

■ ep rJCPoH

i cp.interrupt

ip^queue.xait

iIp^output 图2 TCP协议栈在Linux上的实现

(以下文件路径都是在2628.7内核之下,在其它内核下有可能源码的位置不一样)

输岀过程: 1、(sock_sendmsg 在 kemel/net/socket.c) int sock_sendmsg(struct socket * sock, struct msghdr *msg, size_t size) { struct kiocb iocb; struct sock_iocb siocb; int ret;

init_sync_kiocb(&iocb, NULL); iocb.private = & siocb; ret = —sock_sendmsg(&iocb, sock, msg, size);

讦(-EIOCBQUEUED == ret)

t write ■ Sys^write

Sock_readv_wri tev .

read i i recv 1 ♦ Sya.recv

Sock.sendaBK sock.recvBsg • -T --------- Tcp^sendasg tcp.recvasg ] [ tc

p .rev. established

▼ r tcp^vi.do^rcv1 ”

tcp rcv-it«te proc«if 1 !

tcp^transait^skb tcp^v4^rcv

Ipjrcv netif^receive.skb

|| cp.Btert^iBit ! ldev queue.i»it ret = wait_on_s yn c_kiocb (&iocb); return ret; }

2、tcp_sendmsg 在 kernel/net/ipv4/tcp.c T int tcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size) { struct sock *sk = sock->sk; struct iovec *iov; struct tcp_sock *tp = tcp_sk(sk); struct sk_buff *skb; int iovlen、flags; int mss_now, size_goal; int err, copied; long timeo;

lock_sock(sk); TCP_CHECK_TIMER(sk);

flags = msg->msg_flags; timeo = sock_sndtimeo(sk, flags & MSG_DONTWAIT);

/* Wait for a connection to finish. */ 讦((1 « sk->sk_state) & 〜(TCPF_ESTABLISHED | TCPF_CLOSE_WAIT)) if ((err = sk_stream_wait_connect(sk, &timeo)) != 0) goto out_err;

/* This should be in poll */ clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); mss_now = tcp_current_mss(sk, !(flags&MSG_OOB)); size_goal = tp->x mi t_s ize_goal; /* Ok commence sending. */ iovlen = msg->msg_iovlen; iov = msg->msg_iov; copied = 0;

err = -EPIPE; if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))

goto do_error;

while (—iovlen >= 0) { int seglen = iov->iov_len; unsigned char —user *from = iov->iov_base; iov++; while (seglen > 0) { int copy;

skb = tcp_write_queue_tail(sk); if (!tcp_send_head(sk) || (copy = size_goal - skb->len) <= 0) {

new_segment: /* Allocate new segment. If the interface is SG * allocate skb fitting to single page・ */ if (!sk_stream_memory_free(sk)) goto wait_fbr_sndbuf;

skb = sk_stream_alloc_skb(sk, select_size(sk), sk->sk_allocation); if(!skb) goto wait_for_memory;

/* * Check whether we can use HW checksum. */ if(sk->sk_route_caps & NETIF_F_ALL_CSUM) skb->ip_summed = CHECKSUM_PARTIAL;

skb_entail(sk, skb); copy = size_goal; 1

/* Try to append data to the end of skb. */ if (copy > seglen) copy = seglen;

/* Where to copy to? */ if (skb_tailroom(skb) > 0) { /* We have some space in skb head. Superb! */ if (copy > skb_tailroom(skb)) copy = skb_tailroom(skb); if ((err = skb_add_data(skb, from, copy)) != 0) goto do_fault; } else { int merge = 0; int i = skb_shinfo(skb)->nr_frags; struct page *page = TCP_PAGE(sk); int off=TCP_OFF(sk);

if (skb_can_coalesce(skb, i, page, off) && off != PAGE_SIZE) { /* We can extend the last page * fragment. */ merge = I; )else 讦(i == MAX_SKB_FRAGS || (!i&& ! (sk->sk_route_caps & NETIF_F_SG))) { /* Need to add new fragment and cannot * do this because interface is non-SG, * or because all the page slots are * busy. */ tcp_mark_push(tp, skb); goto new_segment; } else if (page) {

讦(off==PAGE_SIZE) { put_page(page); TCP_PAGE(sk) = page = NULL; off = 0; } } else off = 0;

讦(copy > PAGE_SIZE ・ off) copy = PAGE_SIZE - off; if (!sk_wmem_schedule(sk, copy)) goto wait_for_memory; if (!page) { /* Allocate new cache page. */ if (! (page = sk_stream_alloc_page(sk))) goto wait_for_memory;

/* Time to copy data. We are close to * the end! */ eiT = skb_copy_to_page(sk, from, skb, page, off, copy); if (err) { /* If this page was new, give it to the * socket so it does not get leaked. */ if(!TCP_PAGE(sk)) { TCP_PAGE(sk) = page; TCP_OFF(sk) = 0; } goto do_enor;

}

/* Update the skb. */ if (merge) { skb_shinfo(skb)->frags[i ・ l].size += copy; )else { skb_fill_page_desc(skb, i, page, off, copy); if (TCP_PAGE(sk)) { get_page(page); )else if (off + copy < PAGE.SIZE) {

相关主题