浅析ethx网卡发送函数sys_write简易流程
sys_write=
>
vfs_write=
>
do_sync_write=
>
filp-
>
f_op-
>
aio_write(
&
kiocb,
&
iov,
1,
kiocb.
ki_pos)
;
{
也就是对应socket_file_ops中的sock_aio_write}
sock_aio_write=
>
do_sock_write=
>
__sock_sendmsg=
>
sock-
>
ops-
>
sendmsg
(
iocb,
sock,
msg,
size)
;
{
也就是对应inetsw_array[
]
中的inet_stream_ops下的tcp_sendmsg}
tcp_sendmsg=
>
经过skb拷贝之后,
最终在退出之前调用tcp_push,
将数据发送到网络=
>
tcp_push=
>
__tcp_push_pending_frames=
>
tcp_write_xmit=
>
tcp_transmit_skb=
>
icsk-
>
icsk_af_ops-
>
queue_xmit(
skb,
0)
;
/*
在tcp_v4_init_sock中初始化的如下方法:
icsk->icsk_af_ops = &ipv4_specific;
icsk->icsk_ca_ops = &tcp_init_congestion_ops;
tp->reordering = sysctl_tcp_reordering;
sk->sk_write_space = sk_stream_write_space;
icsk->icsk_sync_mss = tcp_sync_mss;
tp->af_specific = &tcp_sock_ipv4_specific;
所以icsk_af_ops就是ipv4_specific,
struct inet_connection_sock_af_ops ipv4_specific = {
.queue_xmit = ip_queue_xmit,
.send_check = tcp_v4_send_check,
.rebuild_header = inet_sk_rebuild_header,
.conn_request = tcp_v4_conn_request,
.syn_recv_sock = tcp_v4_syn_recv_sock,
.remember_stamp = tcp_v4_remember_stamp,
.net_header_len = sizeof(struct iphdr),
.setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt,
.addr2sockaddr = inet_csk_addr2sockaddr,
.sockaddr_len = sizeof(struct sockaddr_in),
#ifdef CONFIG_COMPAT
.compat_setsockopt = compat_ip_setsockopt,
.compat_getsockopt = compat_ip_getsockopt,
#endif
};
*/
ip_queue_xmit=
>
return
NF_HOOK(
PF_INET
,
NF_IP_LOCAL_OUT,
skb,
NULL
,
rt-
>
u.
dst.
dev,
dst_output)
;
也就是调用dst_output将package发送到网络中出去.
/* Output packet to network from transport. */
static
inline
int
dst_output(
struct
sk_buff *
skb)
{
return
skb-
>
dst-
>
output(
skb)
;
}
__mkroute_output=
>
dst_alloc=
>
rth =
dst_alloc(
&
ipv4_dst_ops)
;
然后dst-
>
ops =
ipv4_dst_ops;
rth-
>
u.
dst.
output=
ip_output;
ip_output=
>
return
NF_HOOK_COND(
PF_INET
,
NF_IP_POST_ROUTING,
skb,
NULL
,
dev,
ip_finish_output,
!
(
IPCB(
skb)
-
>
flags &
IPSKB_REROUTED)
)
;
ip_finish_output=
>
ip_finish_output2=
>
/*
if (dst->hh)
return neigh_hh_output(dst->hh, skb);
else if (dst->neighbour)
return dst->neighbour->output(skb);
*/
/*
static struct neigh_ops arp_generic_ops = {
.family = AF_INET,
.solicit = arp_solicit,
.error_report = arp_error_report,
.output = neigh_resolve_output,
.connected_output = neigh_connected_output,
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
static struct neigh_ops arp_hh_ops = {
.family = AF_INET,
.solicit = arp_solicit,
.error_report = arp_error_report,
.output = neigh_resolve_output,
.connected_output = neigh_resolve_output,
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
static struct neigh_ops arp_direct_ops = {
.family = AF_INET,
.output = dev_queue_xmit,
.connected_output = dev_queue_xmit,
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
struct neigh_ops arp_broken_ops = {
.family = AF_INET,
.solicit = arp_solicit,
.error_report = arp_error_report,
.output = neigh_compat_output,
.connected_output = neigh_compat_output,
.hh_output = dev_queue_xmit,
.queue_xmit = dev_queue_xmit,
};
*/
因为ip通信都是以arp开始来获取通信对端的mac地址,
所以arp应该是网络通信的第一步,
这样就调用到了dev_queue_xmit(
)
想物理网卡发送网络数据包,
dev_queue_xmit=
>
dev_hard_start_xmit=
>
return
dev-
>
hard_start_xmit(
skb,
dev)
;
就是网卡驱动的发送函数wlan_hard_start_xmit,
比较粗糙,
凑活着看吧【gliethttp.
Leith】
看看sys_socket(
)
对空间结构的申请步骤:
sk-
>
sk_prot =
tcp_prot;
他的.
obj_size =
sizeof
(
struct
tcp_sock)
,
所以
struct
tcp_sock {
/* inet_connection_sock has to be the first member of tcp_sock */
struct
inet_connection_sock inet_conn;
.
.
.
}
struct
inet_connection_sock {
/* inet_sock has to be the first member! */
struct
inet_sock icsk_inet;
.
.
.
}
struct
inet_sock {
/* sk and pinet6 has to be the first two members of inet_sock */
struct
sock sk;
.
.
.
}
所以sk_alloc申请到的sk,
指向的是tcp_sock下inet_connection_sock下inet_sock中的sk,
然后
__sock_create=
>
pf-
>
create(
net,
sock,
protocol)
;
inet_create=
>
sk-
>
sk_prot-
>
init(
sk)
也就是调用tcp_prot的init,
也就是tcp_v4_init_sock【gliethttp.
Leith】.