/************************************************************************************/
[ 92.021903:0] Backtrace:
[ 92.024617:0] [<c03cf724>] (dev_queue_xmit+0x0/0x20) from [<c03dca08>] (neigh_direct_output+0x14/0x18)
[ 92.033983:0] [<c03dc9f4>] (neigh_direct_output+0x0/0x18) from [<c0417734>] (ip_finish_output+0x31c/0x368)
[ 92.043684:0] [<c0417418>] (ip_finish_output+0x0/0x368) from [<c0417878>] (ip_output+0xf8/0x10c)
[ 92.052515:0] [<c0417780>] (ip_output+0x0/0x10c) from [<c0416988>] (ip_local_out+0x44/0x4c)
[ 92.060887:0] r9:dc496000 r8:00000030 r7:00000000 r6:db3e9e24 r5:ea7b1db0
[ 92.067726:0] r4:de3a4f40
[ 92.070609:0] [<c0416944>] (ip_local_out+0x0/0x4c) from [<c04169a8>] (ip_send_skb+0x18/0xa0)
[ 92.079065:0] r4:c0939de0 r3:ea7b1db0
[ 92.082930:0] [<c0416990>] (ip_send_skb+0x0/0xa0) from [<c0435f08>] (udp_send_skb+0x254/0x35c)
[ 92.091560:0] r7:00000000 r6:db3e9e24 r5:ea7b1db0 r4:de3a4f40
[ 92.097563:0] [<c0435cb4>] (udp_send_skb+0x0/0x35c) from [<c04382dc>] (udp_sendmsg+0x4f0/0x738)
[ 92.106310:0] [<c0437dec>] (udp_sendmsg+0x0/0x738) from [<c043f778>] (inet_sendmsg+0xb4/0xbc)
[ 92.114906:0] [<c043f6c4>] (inet_sendmsg+0x0/0xbc) from [<c03c0760>] (sock_sendmsg+0xa0/0xbc)
[ 92.123449:0] r7:00000000 r6:00000000 r5:00000028 r4:dc497df0
[ 92.129456:0] [<c03c06c0>] (sock_sendmsg+0x0/0xbc) from [<c03c0e98>] (sys_sendto+0xb8/0xdc)
[ 92.137825:0] r7:00000000 r6:cfdb5e78 r5:40b8e73c r4:00000028
[ 92.143843:0] [<c03c0de0>] (sys_sendto+0x0/0xdc) from [<c000e040>] (ret_fast_syscall+0x0/0x30)
[ 92.152495:0] Code: e92dd800 e24cb004 e59f0008 eb04b6c5 (e7f001f2)
[ 92.158785:0] Enter crash kexec !!
[ 92.162321:1] CPU 1 will stop doing anything useful since another CPU has crashed
[ 92.170815:0] Loading crashdump kernel...
[ 92.174864:0] Software reset on panic!
/************************************************************************************/
net/socket.c
/*
* Send a datagram to a given address. We move the address into kernel
* space and check the user space data area is readable before invoking
* the protocol.
*/
SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
unsigned, flags, struct sockaddr __user *, addr,
int, addr_len)
{
struct socket *sock;
struct sockaddr_storage address;
int err;
struct msghdr msg;
struct iovec iov;
int fput_needed;
if (len > INT_MAX)
len = INT_MAX;
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;
iov.iov_base = buff;
iov.iov_len = len;
msg.msg_name = NULL;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_namelen = 0;
if (addr) {
err = move_addr_to_kernel(addr, addr_len, &address);
if (err < 0)
goto out_put;
msg.msg_name = (struct sockaddr *)&address;
msg.msg_namelen = addr_len;
}
if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT;
msg.msg_flags = flags;
err = sock_sendmsg(sock, &msg, len);
out_put:
fput_light(sock->file, fput_needed);
out:
return err;
}
/*从fd得到对应的file, 从file得到对应的socket*/
static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
{
struct file *file;
struct socket *sock;
*err = -EBADF;
file = fget_light(fd, fput_needed);
if (file) {
sock = sock_from_file(file, err);
if (sock)
return sock;
fput_light(file, *fput_needed);
}
return NULL;
}
/*message header: socket name,data,control message,和上面的代码对应一下
*socket name来自结构体struct sockaddr
**/
struct msghdr {
void * msg_name; /* Socket name */
int msg_namelen; /* Length of name */
struct iovec * msg_iov; /* Data blocks */
__kernel_size_t msg_iovlen; /* Number of blocks */
void * msg_control; /* Per protocol magic (eg BSD file descriptor passing) */
__kernel_size_t msg_controllen; /* Length of cmsg list */
unsigned msg_flags;
};
/*14 bytes of protocol address指的是什么?
**/
struct sockaddr {
sa_family_t sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
};
struct iovec
{
void __user *iov_base; /* BSD uses caddr_t (1003.1g requires void *) */
__kernel_size_t iov_len; /* Must be size_t (1003.1g) */
};
/* sock_iocb: used to kick off async processing of socket ios */
struct sock_iocb {
struct list_head list;
int flags;
int size;
struct socket *sock;
struct sock *sk;
struct scm_cookie *scm;
struct msghdr *msg, async_msg;
struct kiocb *kiocb;
};
/*kiocb是个比sock_iocb更大的结构体*/
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);
if (-EIOCBQUEUED == ret)
ret = wait_on_sync_kiocb(&iocb);
return ret;
}
static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size)
{
int err = security_socket_sendmsg(sock, msg, size);
return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size);
}
static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size)
{
struct sock_iocb *si = kiocb_to_siocb(iocb);
/*这两个函数由CONFIG_CGROUPS控制,当前是没有定义*/
sock_update_classid(sock->sk);
sock_update_netprioidx(sock->sk);
/*该函数就是设置了sock_iocb,并调用socket的 对应ops*/
si->sock = sock;
si->scm = NULL;
si->msg = msg;
si->size = size;
return sock->ops->sendmsg(iocb, sock, msg, size);
}
crash> struct socket.ops
struct socket {
[24] const struct proto_ops *ops;
}
struct proto_ops {
int family;
struct module *owner;
int (*release)(struct socket *);
int (*bind)(struct socket *, struct sockaddr *, int);
int (*connect)(struct socket *, struct sockaddr *, int, int);
int (*socketpair)(struct socket *, struct socket *);
int (*accept)(struct socket *, struct socket *, int);
int (*getname)(struct socket *, struct sockaddr *, int *, int);
unsigned int (*poll)(struct file *, struct socket *, struct poll_table_struct *);
int (*ioctl)(struct socket *, unsigned int, unsigned long);
int (*listen)(struct socket *, int);
int (*shutdown)(struct socket *, int);
int (*setsockopt)(struct socket *, int, int, char *, unsigned int);
int (*getsockopt)(struct socket *, int, int, char *, int *);
int (*sendmsg)(struct kiocb *, struct socket *, struct msghdr *, size_t);
int (*recvmsg)(struct kiocb *, struct socket *, struct msghdr *, size_t, int);
int (*mmap)(struct file *, struct socket *, struct vm_area_struct *);
ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
ssize_t (*splice_read)(struct socket *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
void (*set_peek_off)(struct sock *, int);
}
以inet_stream_ops为例:
const struct proto_ops inet_stream_ops = {
.family = PF_INET,
.owner = THIS_MODULE,
.release = inet_release,
.bind = inet_bind,
.connect = inet_stream_connect,
.socketpair = sock_no_socketpair,
.accept = inet_accept,
.getname = inet_getname,
.poll = tcp_poll,
.ioctl = inet_ioctl,
.listen = inet_listen,
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
.getsockopt = sock_common_getsockopt,
.sendmsg = inet_sendmsg,
.recvmsg = inet_recvmsg,
.mmap = sock_no_mmap,
.sendpage = inet_sendpage,
.splice_read = tcp_splice_read,
};
/************************************************************************************/
int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
size_t size)
{
struct sock *sk = sock->sk;
sock_rps_record_flow(sk);
/* We may need to bind the socket. */
if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind &&
inet_autobind(sk))
return -EAGAIN;
return sk->sk_prot->sendmsg(iocb, sk, msg, size);
}
/*这里说的bind socket是个什么意思?*/
/*就是得到inet_num,并赋值到inet->inet_sport[Source port]
* Automatically bind an unbound socket.
*/
static int inet_autobind(struct sock *sk)
{
struct inet_sock *inet;
/* We may need to bind the socket. */
lock_sock(sk);
inet = inet_sk(sk);
if (!inet->inet_num) {
if (sk->sk_prot->get_port(sk, 0)) {
release_sock(sk);
return -EAGAIN;
}
inet->inet_sport = htons(inet->inet_num);
}
release_sock(sk);
return 0;
}
crash> sock
struct sock {
struct sock_common __sk_common;
crash> sock_common.skc_prot
struct sock_common {
[28] struct proto *skc_prot;
}
#define sk_prot __sk_common.skc_prot
crash> proto.sendmsg
struct proto {
[40] int (*sendmsg)(struct kiocb *, struct sock *, struct msghdr *, size_t);
}
/*请注意proto_ops的函数参数是socket而 proto的参数是sock,这里调用的是
*
**/
int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len)
{
struct inet_sock *inet = inet_sk(sk);
struct udp_sock *up = udp_sk(sk);
struct flowi4 fl4_stack;
struct flowi4 *fl4;
int ulen = len;
struct ipcm_cookie ipc;
struct rtable *rt = NULL;
udp_send_skb(skb, fl4);
}
static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
{
struct sock *sk = skb->sk;
struct inet_sock *inet = inet_sk(sk);
struct udphdr *uh;
ip_send_skb(skb);
}
int ip_send_skb(struct sk_buff *skb)
{
struct net *net = sock_net(skb->sk);
int err;
err = ip_local_out(skb);
if (err) {
if (err > 0)
err = net_xmit_errno(err);
if (err)
IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
}
return err;
}
int ip_local_out(struct sk_buff *skb)
{
int err;
err = __ip_local_out(skb);
if (likely(err == 1))
err = dst_output(skb);
return err;
}
int __ip_local_out(struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);
iph->tot_len = htons(skb->len);
ip_send_check(iph);
return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL,
skb_dst(skb)->dev, dst_output);
}
/* Output packet to network from transport. */
static inline int dst_output(struct sk_buff *skb)
{
pr_err("dst_output: %p\n", skb_dst(skb)->output);
return skb_dst(skb)->output(skb);
}
int ip_output(struct sk_buff *skb)
{
struct net_device *dev = skb_dst(skb)->dev;
IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len);
skb->dev = dev;
skb->protocol = htons(ETH_P_IP);
return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL, dev,
ip_finish_output,
!(IPCB(skb)->flags & IPSKB_REROUTED));
}
static inline int ip_finish_output2(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct rtable *rt = (struct rtable *)dst;
struct net_device *dev = dst->dev;
unsigned int hh_len = LL_RESERVED_SPACE(dev);
struct neighbour *neigh;
if (rt->rt_type == RTN_MULTICAST) {
IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len);
} else if (rt->rt_type == RTN_BROADCAST)
IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTBCAST, skb->len);
/* Be paranoid, rather than too clever. */
if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
struct sk_buff *skb2;
skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
if (skb2 == NULL) {
kfree_skb(skb);
return -ENOMEM;
}
if (skb->sk)
skb_set_owner_w(skb2, skb->sk);
kfree_skb(skb);
skb = skb2;
}
rcu_read_lock();
neigh = dst_get_neighbour_noref(dst);
if (neigh) {
int res = neigh_output(neigh, skb);
rcu_read_unlock();
return res;
}
rcu_read_unlock();
if (net_ratelimit())
printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n");
kfree_skb(skb);
return -EINVAL;
}
static inline int neigh_output(struct neighbour *n, struct sk_buff *skb)
{
struct hh_cache *hh = &n->hh;
if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
return neigh_hh_output(hh, skb);
else
return n->output(n, skb);
}
int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
{
return dev_queue_xmit(skb);
}
dev_queue_xmit(struct sk_buff *skb) -> dev_hard_start_xmit -> net_device_ops->ndo_start_xmit[ppp_start_xmit]
ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
-> ppp_xmit_process -> ppp_send_frame -> ppp_push -> ppp_channel_ops->start_xmit[ppp_async_send]
[ 92.021903:0] Backtrace:
[ 92.024617:0] [<c03cf724>] (dev_queue_xmit+0x0/0x20) from [<c03dca08>] (neigh_direct_output+0x14/0x18)
[ 92.033983:0] [<c03dc9f4>] (neigh_direct_output+0x0/0x18) from [<c0417734>] (ip_finish_output+0x31c/0x368)
[ 92.043684:0] [<c0417418>] (ip_finish_output+0x0/0x368) from [<c0417878>] (ip_output+0xf8/0x10c)
[ 92.052515:0] [<c0417780>] (ip_output+0x0/0x10c) from [<c0416988>] (ip_local_out+0x44/0x4c)
[ 92.060887:0] r9:dc496000 r8:00000030 r7:00000000 r6:db3e9e24 r5:ea7b1db0
[ 92.067726:0] r4:de3a4f40
[ 92.070609:0] [<c0416944>] (ip_local_out+0x0/0x4c) from [<c04169a8>] (ip_send_skb+0x18/0xa0)
[ 92.079065:0] r4:c0939de0 r3:ea7b1db0
[ 92.082930:0] [<c0416990>] (ip_send_skb+0x0/0xa0) from [<c0435f08>] (udp_send_skb+0x254/0x35c)
[ 92.091560:0] r7:00000000 r6:db3e9e24 r5:ea7b1db0 r4:de3a4f40
[ 92.097563:0] [<c0435cb4>] (udp_send_skb+0x0/0x35c) from [<c04382dc>] (udp_sendmsg+0x4f0/0x738)
[ 92.106310:0] [<c0437dec>] (udp_sendmsg+0x0/0x738) from [<c043f778>] (inet_sendmsg+0xb4/0xbc)
[ 92.114906:0] [<c043f6c4>] (inet_sendmsg+0x0/0xbc) from [<c03c0760>] (sock_sendmsg+0xa0/0xbc)
[ 92.123449:0] r7:00000000 r6:00000000 r5:00000028 r4:dc497df0
[ 92.129456:0] [<c03c06c0>] (sock_sendmsg+0x0/0xbc) from [<c03c0e98>] (sys_sendto+0xb8/0xdc)
[ 92.137825:0] r7:00000000 r6:cfdb5e78 r5:40b8e73c r4:00000028
[ 92.143843:0] [<c03c0de0>] (sys_sendto+0x0/0xdc) from [<c000e040>] (ret_fast_syscall+0x0/0x30)
[ 92.152495:0] Code: e92dd800 e24cb004 e59f0008 eb04b6c5 (e7f001f2)
[ 92.158785:0] Enter crash kexec !!
[ 92.162321:1] CPU 1 will stop doing anything useful since another CPU has crashed
[ 92.170815:0] Loading crashdump kernel...
[ 92.174864:0] Software reset on panic!
/************************************************************************************/
net/socket.c
/*
* Send a datagram to a given address. We move the address into kernel
* space and check the user space data area is readable before invoking
* the protocol.
*/
SYSCALL_DEFINE6(sendto, int, fd, void __user *, buff, size_t, len,
unsigned, flags, struct sockaddr __user *, addr,
int, addr_len)
{
struct socket *sock;
struct sockaddr_storage address;
int err;
struct msghdr msg;
struct iovec iov;
int fput_needed;
if (len > INT_MAX)
len = INT_MAX;
sock = sockfd_lookup_light(fd, &err, &fput_needed);
if (!sock)
goto out;
iov.iov_base = buff;
iov.iov_len = len;
msg.msg_name = NULL;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
msg.msg_control = NULL;
msg.msg_controllen = 0;
msg.msg_namelen = 0;
if (addr) {
err = move_addr_to_kernel(addr, addr_len, &address);
if (err < 0)
goto out_put;
msg.msg_name = (struct sockaddr *)&address;
msg.msg_namelen = addr_len;
}
if (sock->file->f_flags & O_NONBLOCK)
flags |= MSG_DONTWAIT;
msg.msg_flags = flags;
err = sock_sendmsg(sock, &msg, len);
out_put:
fput_light(sock->file, fput_needed);
out:
return err;
}
/*从fd得到对应的file, 从file得到对应的socket*/
static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed)
{
struct file *file;
struct socket *sock;
*err = -EBADF;
file = fget_light(fd, fput_needed);
if (file) {
sock = sock_from_file(file, err);
if (sock)
return sock;
fput_light(file, *fput_needed);
}
return NULL;
}
/*message header: socket name,data,control message,和上面的代码对应一下
*socket name来自结构体struct sockaddr
**/
struct msghdr {
void * msg_name; /* Socket name */
int msg_namelen; /* Length of name */
struct iovec * msg_iov; /* Data blocks */
__kernel_size_t msg_iovlen; /* Number of blocks */
void * msg_control; /* Per protocol magic (eg BSD file descriptor passing) */
__kernel_size_t msg_controllen; /* Length of cmsg list */
unsigned msg_flags;
};
/*14 bytes of protocol address指的是什么?
**/
struct sockaddr {
sa_family_t sa_family; /* address family, AF_xxx */
char sa_data[14]; /* 14 bytes of protocol address */
};
struct iovec
{
void __user *iov_base; /* BSD uses caddr_t (1003.1g requires void *) */
__kernel_size_t iov_len; /* Must be size_t (1003.1g) */
};
/* sock_iocb: used to kick off async processing of socket ios */
struct sock_iocb {
struct list_head list;
int flags;
int size;
struct socket *sock;
struct sock *sk;
struct scm_cookie *scm;
struct msghdr *msg, async_msg;
struct kiocb *kiocb;
};
/*kiocb是个比sock_iocb更大的结构体*/
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);
if (-EIOCBQUEUED == ret)
ret = wait_on_sync_kiocb(&iocb);
return ret;
}
static inline int __sock_sendmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size)
{
int err = security_socket_sendmsg(sock, msg, size);
return err ?: __sock_sendmsg_nosec(iocb, sock, msg, size);
}
static inline int __sock_sendmsg_nosec(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size)
{
struct sock_iocb *si = kiocb_to_siocb(iocb);
/*这两个函数由CONFIG_CGROUPS控制,当前是没有定义*/
sock_update_classid(sock->sk);
sock_update_netprioidx(sock->sk);
/*该函数就是设置了sock_iocb,并调用socket的 对应ops*/
si->sock = sock;
si->scm = NULL;
si->msg = msg;
si->size = size;
return sock->ops->sendmsg(iocb, sock, msg, size);
}
crash> struct socket.ops
struct socket {
[24] const struct proto_ops *ops;
}
struct proto_ops {
int family;
struct module *owner;
int (*release)(struct socket *);
int (*bind)(struct socket *, struct sockaddr *, int);
int (*connect)(struct socket *, struct sockaddr *, int, int);
int (*socketpair)(struct socket *, struct socket *);
int (*accept)(struct socket *, struct socket *, int);
int (*getname)(struct socket *, struct sockaddr *, int *, int);
unsigned int (*poll)(struct file *, struct socket *, struct poll_table_struct *);
int (*ioctl)(struct socket *, unsigned int, unsigned long);
int (*listen)(struct socket *, int);
int (*shutdown)(struct socket *, int);
int (*setsockopt)(struct socket *, int, int, char *, unsigned int);
int (*getsockopt)(struct socket *, int, int, char *, int *);
int (*sendmsg)(struct kiocb *, struct socket *, struct msghdr *, size_t);
int (*recvmsg)(struct kiocb *, struct socket *, struct msghdr *, size_t, int);
int (*mmap)(struct file *, struct socket *, struct vm_area_struct *);
ssize_t (*sendpage)(struct socket *, struct page *, int, size_t, int);
ssize_t (*splice_read)(struct socket *, loff_t *, struct pipe_inode_info *, size_t, unsigned int);
void (*set_peek_off)(struct sock *, int);
}
以inet_stream_ops为例:
const struct proto_ops inet_stream_ops = {
.family = PF_INET,
.owner = THIS_MODULE,
.release = inet_release,
.bind = inet_bind,
.connect = inet_stream_connect,
.socketpair = sock_no_socketpair,
.accept = inet_accept,
.getname = inet_getname,
.poll = tcp_poll,
.ioctl = inet_ioctl,
.listen = inet_listen,
.shutdown = inet_shutdown,
.setsockopt = sock_common_setsockopt,
.getsockopt = sock_common_getsockopt,
.sendmsg = inet_sendmsg,
.recvmsg = inet_recvmsg,
.mmap = sock_no_mmap,
.sendpage = inet_sendpage,
.splice_read = tcp_splice_read,
};
/************************************************************************************/
int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
size_t size)
{
struct sock *sk = sock->sk;
sock_rps_record_flow(sk);
/* We may need to bind the socket. */
if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind &&
inet_autobind(sk))
return -EAGAIN;
return sk->sk_prot->sendmsg(iocb, sk, msg, size);
}
/*这里说的bind socket是个什么意思?*/
/*就是得到inet_num,并赋值到inet->inet_sport[Source port]
* Automatically bind an unbound socket.
*/
static int inet_autobind(struct sock *sk)
{
struct inet_sock *inet;
/* We may need to bind the socket. */
lock_sock(sk);
inet = inet_sk(sk);
if (!inet->inet_num) {
if (sk->sk_prot->get_port(sk, 0)) {
release_sock(sk);
return -EAGAIN;
}
inet->inet_sport = htons(inet->inet_num);
}
release_sock(sk);
return 0;
}
crash> sock
struct sock {
struct sock_common __sk_common;
crash> sock_common.skc_prot
struct sock_common {
[28] struct proto *skc_prot;
}
#define sk_prot __sk_common.skc_prot
crash> proto.sendmsg
struct proto {
[40] int (*sendmsg)(struct kiocb *, struct sock *, struct msghdr *, size_t);
}
/*请注意proto_ops的函数参数是socket而 proto的参数是sock,这里调用的是
*
**/
int udp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
size_t len)
{
struct inet_sock *inet = inet_sk(sk);
struct udp_sock *up = udp_sk(sk);
struct flowi4 fl4_stack;
struct flowi4 *fl4;
int ulen = len;
struct ipcm_cookie ipc;
struct rtable *rt = NULL;
udp_send_skb(skb, fl4);
}
static int udp_send_skb(struct sk_buff *skb, struct flowi4 *fl4)
{
struct sock *sk = skb->sk;
struct inet_sock *inet = inet_sk(sk);
struct udphdr *uh;
ip_send_skb(skb);
}
int ip_send_skb(struct sk_buff *skb)
{
struct net *net = sock_net(skb->sk);
int err;
err = ip_local_out(skb);
if (err) {
if (err > 0)
err = net_xmit_errno(err);
if (err)
IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS);
}
return err;
}
int ip_local_out(struct sk_buff *skb)
{
int err;
err = __ip_local_out(skb);
if (likely(err == 1))
err = dst_output(skb);
return err;
}
int __ip_local_out(struct sk_buff *skb)
{
struct iphdr *iph = ip_hdr(skb);
iph->tot_len = htons(skb->len);
ip_send_check(iph);
return nf_hook(NFPROTO_IPV4, NF_INET_LOCAL_OUT, skb, NULL,
skb_dst(skb)->dev, dst_output);
}
/* Output packet to network from transport. */
static inline int dst_output(struct sk_buff *skb)
{
pr_err("dst_output: %p\n", skb_dst(skb)->output);
return skb_dst(skb)->output(skb);
}
int ip_output(struct sk_buff *skb)
{
struct net_device *dev = skb_dst(skb)->dev;
IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUT, skb->len);
skb->dev = dev;
skb->protocol = htons(ETH_P_IP);
return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING, skb, NULL, dev,
ip_finish_output,
!(IPCB(skb)->flags & IPSKB_REROUTED));
}
static inline int ip_finish_output2(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
struct rtable *rt = (struct rtable *)dst;
struct net_device *dev = dst->dev;
unsigned int hh_len = LL_RESERVED_SPACE(dev);
struct neighbour *neigh;
if (rt->rt_type == RTN_MULTICAST) {
IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTMCAST, skb->len);
} else if (rt->rt_type == RTN_BROADCAST)
IP_UPD_PO_STATS(dev_net(dev), IPSTATS_MIB_OUTBCAST, skb->len);
/* Be paranoid, rather than too clever. */
if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) {
struct sk_buff *skb2;
skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
if (skb2 == NULL) {
kfree_skb(skb);
return -ENOMEM;
}
if (skb->sk)
skb_set_owner_w(skb2, skb->sk);
kfree_skb(skb);
skb = skb2;
}
rcu_read_lock();
neigh = dst_get_neighbour_noref(dst);
if (neigh) {
int res = neigh_output(neigh, skb);
rcu_read_unlock();
return res;
}
rcu_read_unlock();
if (net_ratelimit())
printk(KERN_DEBUG "ip_finish_output2: No header cache and no neighbour!\n");
kfree_skb(skb);
return -EINVAL;
}
static inline int neigh_output(struct neighbour *n, struct sk_buff *skb)
{
struct hh_cache *hh = &n->hh;
if ((n->nud_state & NUD_CONNECTED) && hh->hh_len)
return neigh_hh_output(hh, skb);
else
return n->output(n, skb);
}
int neigh_direct_output(struct neighbour *neigh, struct sk_buff *skb)
{
return dev_queue_xmit(skb);
}
dev_queue_xmit(struct sk_buff *skb) -> dev_hard_start_xmit -> net_device_ops->ndo_start_xmit[ppp_start_xmit]
ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
-> ppp_xmit_process -> ppp_send_frame -> ppp_push -> ppp_channel_ops->start_xmit[ppp_async_send]