socket Tx

/************************************************************************************/
[   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]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在lwIP中,可以使用`netconn_get_info()`函数来获取一个连接(socket)的状态信息。该函数的定义如下: ``` err_t netconn_get_info(struct netconn *conn, struct netconn_info *info); ``` 其中,`conn`参数是一个指向`struct netconn`类型的指针,表示要获取信息的连接;`info`参数是一个指向`struct netconn_info`类型的指针,用于存储获取到的连接信息。 `struct netconn_info`类型定义如下: ``` struct netconn_info { u16_t pcb_type; /* protocol control block type (TCP/UDP) */ u16_t local_port; /* local port */ u16_t remote_port; /* remote port */ ip_addr_t local_ip; /* local IP address */ ip_addr_t remote_ip; /* remote IP address */ u8_t used; /* whether the pcb is used or not */ u8_t state; /* TCP state or UDP PCB state */ u32_t rcv_wnd; /* receive window */ u32_t rcv_queued; /* receive queued */ u32_t snd_queued; /* send queued */ u32_t acked; /* ACKed */ u32_t unacked; /* UnACKed */ u32_t last_ack; /* Last ACKed */ u32_t last_rcv_ack; /* Last ACK sent */ u32_t last_rcv_wnd; /* Last receive window */ u32_t total_rx; /* Total received */ u32_t total_tx; /* Total transmitted */ u32_t err_tx; /* Transmit errors */ u32_t err_rx; /* Receive errors */ u32_t err_connect; /* Connect errors */ u32_t err_timeout; /* Timeout errors */ u32_t err_abrt; /* Abort errors */ }; ``` 在获取连接状态信息后,可以根据`state`字段的值来判断连接的状态。具体的状态值定义在`tcp.h`或`udp.h`中。例如,以下是TCP连接的状态值定义: ``` /* TCP connection states */ #define CLOSED 0 /* closed */ #define LISTEN 1 /* listening for connection */ #define SYN_SENT 2 /* active, have sent syn */ #define SYN_RCVD 3 /* have sent and received syn */ #define ESTABLISHED 4 /* established */ #define FIN_WAIT_1 5 /* have closed, sent fin */ #define FIN_WAIT_2 6 /* have closed, fin is acked */ #define CLOSE_WAIT 7 /* have closed, remote peer is closing */ #define CLOSING 8 /* closed xchd FIN; await FIN-ACK */ #define LAST_ACK 9 /* had fin and close; await FIN-ACK */ #define TIME_WAIT 10 /* in 2*msl quiet wait after close */ ``` 因此,可以通过判断`state`字段的值来确定连接的状态,进而进行相应的处理。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值