当前位置:文档之家› 网络协议栈函数.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;

相关主题