网络子系统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;
	}

	if (inet->inet_rcv_saddr)
		sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
	if (snum)
		sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
	
	//绑定端口
	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;
}

网络子系统80_inet协议族-SOCK_RAW(一),古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。