网络子系统80_inet协议族-SOCK_RAW(一)
// SOCK_RAW 1.1 static struct inet_protosw inetsw_array[] = { ... { .type = SOCK_RAW, .protocol = IPPROTO_IP, /* 通配符 */ .prot = &raw_prot, /* Networking protocol blocks attached to sockets */ .ops = &inet_sockraw_ops, .no_check = UDP_CSUM_DEFAULT, .flags = INET_PROTOSW_REUSE, } ... } // struct socket->ops字段 // 向上的数据结构 2.1 static const struct proto_ops inet_sockraw_ops = { .family = PF_INET, .owner = THIS_MODULE, .release = inet_release, .bind = inet_bind, .connect = inet_dgram_connect, .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = inet_getname, .poll = datagram_poll, .ioctl = inet_ioctl, .listen = sock_no_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, }; // sock绑定地址 // inet_sock->inet_rcv_saddr - Bound local ipv4 addr // inet_sock->inet_num - Local port // 步骤: // 1.安全性检查 // 1.1 地址长度是否足够 // 1.2 地址类型是否正确 // 1.3 端口是否已经被占用 // 2.设置inet_sock结构的源地址和源端口 3.1 int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) { //inet使用sockaddr_in struct sockaddr_in *addr = (struct sockaddr_in *)uaddr; struct sock *sk = sock->sk; //inet使用inet_sock struct inet_sock *inet = inet_sk(sk); struct net *net = sock_net(sk); unsigned short snum; int chk_addr_ret; int err; //调用sock提供的bind if (sk->sk_prot->bind) { err = sk->sk_prot->bind(sk, uaddr, addr_len); goto out; } err = -EINVAL; //地址长度 if (addr_len < sizeof(struct sockaddr_in)) goto out; //兼容性检查 if (addr->sin_family != AF_INET) { err = -EAFNOSUPPORT; if (addr->sin_family != AF_UNSPEC || addr->sin_addr.s_addr != htonl(INADDR_ANY)) goto out; } //检查地址类型 chk_addr_ret = inet_addr_type(net, addr->sin_addr.s_addr); err = -EADDRNOTAVAIL; if (!sysctl_ip_nonlocal_bind && !(inet->freebind || inet->transparent) && addr->sin_addr.s_addr != htonl(INADDR_ANY) && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) goto out; //端口号检查 snum = ntohs(addr->sin_port); err = -EACCES; if (snum && snum < PROT_SOCK && !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) goto out; lock_sock(sk); err = -EINVAL; //二次绑定 if (sk->sk_state != TCP_CLOSE || inet->inet_num) goto out_release_sock; //绑定地址 inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr; //检查端口是否已经被绑定 if (sk->sk_prot->get_port(sk, snum)) { inet->inet_saddr = inet->inet_rcv_saddr = 0; err = -EADDRINUSE; goto out_release_sock; } //绑定端口 inet->inet_sport = htons(inet->inet_num); inet->inet_daddr = 0; inet->inet_dport = 0; sk_dst_reset(sk); err = 0; out_release_sock: release_sock(sk); out: return err; } // 发送数据 // 统计流量,绑定端口,由prot完成数据发送 3.2 int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size) { struct sock *sk = sock->sk; //统计sock的流量 sock_rps_record_flow(sk); //绑定port if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind && inet_autobind(sk)) return -EAGAIN; //通过prot->sendmsg发送数据 return sk->sk_prot->sendmsg(iocb, sk, msg, size); } // 接收数据 // 统计流量,由prot完成数据接收 3.3 int inet_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags) { struct sock *sk = sock->sk; int addr_len = 0; int err; //统计sock流量 sock_rps_record_flow(sk); //通过prot->recvmsg接收数据 err = sk->sk_prot->recvmsg(iocb, sk, msg, size, flags & MSG_DONTWAIT, flags & ~MSG_DONTWAIT, &addr_len); if (err >= 0) msg->msg_namelen = addr_len; return err; } // 建立连接 // 步骤: // 1.常规检查 // 1.1 如果未绑定端口,先随机分配一个端口并绑定 // 2.由struct sock->sk_prot->connect建立连接 3.4 int inet_dgram_connect(struct socket *sock, struct sockaddr *uaddr, int addr_len, int flags) { struct sock *sk = sock->sk; //未绑定端口,先绑定 if (!inet_sk(sk)->inet_num && inet_autobind(sk)) return -EAGAIN; return sk->sk_prot->connect(sk, uaddr, addr_len); } // 关闭sock // 步骤: // 1.如果struct sock正在连接建立的过程中(TCP_SYN_SENT),调用disconnect关闭连接 // 2.否则,由shutdown关闭连接 // 3.通知sock的拥有者,sock状态发生了改变 3.5 int inet_shutdown(struct socket *sock, int how) { struct sock *sk = sock->sk; int err = 0; lock_sock(sk); //SS_CONNECTING在TCP中使用 if (sock->state == SS_CONNECTING) { if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE)) sock->state = SS_DISCONNECTING; else sock->state = SS_CONNECTED; } switch (sk->sk_state) { case TCP_CLOSE: err = -ENOTCONN; //由具体的sock完成关闭 default: sk->sk_shutdown |= how; if (sk->sk_prot->shutdown) sk->sk_prot->shutdown(sk, how); break; case TCP_SYN_SENT: //已经发送了syn,则通过disconnect关闭连接 err = sk->sk_prot->disconnect(sk, O_NONBLOCK); sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED; break; } //通知sock的拥有者,sock状态改变 sk->sk_state_change(sk); release_sock(sk); return err; } // 通用的数据报poll调用 3.6 unsigned int datagram_poll(struct file *file, struct socket *sock, poll_table *wait) { struct sock *sk = sock->sk; unsigned int mask; //在sock上等待数据 sock_poll_wait(file, sk_sleep(sk), wait); mask = 0; //有接收到的数据 if (!skb_queue_empty(&sk->sk_receive_queue)) mask |= POLLIN | POLLRDNORM; //有可写内存 if (sock_writeable(sk)) mask |= POLLOUT | POLLWRNORM | POLLWRBAND; else set_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags); //返回标志结合,指示poll的结果 return mask; } // 发送page // 步骤: // 1. 检查是否分配了端口 // 1.1 如果没有分配,则内核为其选择一个端口 // 2. 如果sock提供了sendpage,则调用 // 3. 否则,映射page到msghdr结构,通过sk->sk_prot->sendmsg发送 // 注: // 对于不支持sendpage的sock,填充page数据到msghdr 3.7 ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) { struct sock *sk = sock->sk; sock_rps_record_flow(sk); //没有指定端口号,内核随机选择一个端口 if (!inet_sk(sk)->inet_num && !sk->sk_prot->no_autobind && inet_autobind(sk)) return -EAGAIN; //如果sock提供了sendpage,则调用 if (sk->sk_prot->sendpage) return sk->sk_prot->sendpage(sk, page, offset, size, flags); //否则将page映射到msghdr中 return sock_no_sendpage(sock, page, offset, size, flags); } // 映射page到核心地址空间,填充msghdr结构 3.8 ssize_t sock_no_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags) { ssize_t res; struct msghdr msg = {.msg_flags = flags}; struct kvec iov; //映射page结构到核心地址空间 char *kaddr = kmap(page); iov.iov_base = kaddr + offset; iov.iov_len = size; //发送msghdr res = kernel_sendmsg(sock, &msg, &iov, 1, size); //解映射 kunmap(page); return res; } // 发送msghdr // 步骤: // 1.初始化kiocb,用于sock的同步处理 // 2.通过sock->sk_prot->sendmsg发送msghdr // 3.如果底层为异步发送,则等待数据发送完成 3.9 int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) { struct kiocb iocb; struct sock_iocb siocb; int ret; //初始化sock同步控制块 init_sync_kiocb(&iocb, NULL); iocb.private = &siocb; //通过sk->sk_prot->sendmsg发送msghdr ret = __sock_sendmsg(&iocb, sock, msg, size); //如果底层发送为异步,则等待发送的完成 if (-EIOCBQUEUED == ret) ret = wait_on_sync_kiocb(&iocb); return ret; }
最后更新:2017-04-03 12:55:18