Linux内核网络协议栈6-socket地址绑定(续)
chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);if (!sysctl_ip_nonlocal_bind && !inet->freebind && 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;?
inet_addr_type()函数根据设置的ip地址检查其类型:
static inline unsigned __inet_dev_addr_type(struct net *net, const struct net_device *dev, __be32 addr){ …… if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr)) return RTN_BROADCAST; if (ipv4_is_multicast(addr)) return RTN_MULTICAST; …… local_table = fib_get_table(net, RT_TABLE_LOCAL); if (local_table) { ret = RTN_UNICAST; if (!local_table->tb_lookup(local_table, &fl, &res)) { if (!dev || dev == res.fi->fib_dev) ret = res.type; fib_res_put(&res); } } return ret;}?
a.ipv4_is_zeronet()用于检查地址的高8位是否为0,即地址是否为0.x.x.x,这类地址称为零网地址,零网地址也属于广播地址;
b.ipv4_is_lbcast()用于检查地址是否是广播地址(广播地址有两种,一种是有限广播,即255.255.255.255,它不会被路由但是会发送到物理网段上的所有主机;另一种是直接广播,该类地址的主机字段为255,如192.168.1.255,该广播会路由到192.168.1网段的所有主机上);这里只是检查是否是有限广播地址;
c.ipv4_is_multicast()用于检查地址是否是多播地址,即224.x.x.x的D类地址;
snum = ntohs(addr->sin_port);if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))goto out;/* Sockets 0-1023 can't be bound to unless you are superuser */#define PROT_SOCK 1024?
if (sk->sk_state != TCP_CLOSE || inet->num)goto out_release_sock; inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr;if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST)inet->saddr = 0; /* Use device */?
if (sk->sk_prot->get_port(sk, snum)) {inet->saddr = inet->rcv_saddr = 0;err = -EADDRINUSE;goto out_release_sock;}?
inet->sport = htons(inet->num);inet->daddr = 0;inet->dport = 0;?
1、 根据文件描述符从进程描述符中取出相应的文件,再得到socket结构;
2、 检查ip地址的类型是否是单播、多播或广播;
3、 检查端口是否被占用;