1 /* 2 * Bind a name to a socket. Nothing much to do here since it's 3 * the protocol's responsibility to handle the local address. 4 * 5 * We move the socket address to kernel space before we call 6 * the protocol layer (having also checked the address is ok). 7 */ 8 9 SYSCALL_DEFINE3(bind, int, fd, struct sockaddr __user *, umyaddr, int, addrlen) 10 { 11 struct socket *sock; 12 struct sockaddr_storage address; 13 int err, fput_needed; 14 15 /* 获取socket ,fput_need标识是否需要减少文件引用计数*/ 16 sock = sockfd_lookup_light(fd, &err, &fput_needed); 17 if (sock) { 18 /* 将用户空间地址复制到内核空间 */ 19 err = move_addr_to_kernel(umyaddr, addrlen, &address); 20 if (err >= 0) { 21 /* 安全模块的bind检查 */ 22 err = security_socket_bind(sock, 23 (struct sockaddr *)&address, 24 addrlen); 25 if (!err) 26 /* 调用socket的bind操作 */ 27 err = sock->ops->bind(sock, 28 (struct sockaddr *) 29 &address, addrlen); 30 } 31 32 /* 根据fput_needed决定是否减少引用计数 */ 33 fput_light(sock->file, fput_needed); 34 } 35 return err; 36 }
1 static struct socket *sockfd_lookup_light(int fd, int *err, int *fput_needed) 2 { 3 /* 获取fd结构 */ 4 struct fd f = fdget(fd); 5 struct socket *sock; 6 7 *err = -EBADF; 8 if (f.file) { 9 /* 从文件的私有数据中获取socket */ 10 sock = sock_from_file(f.file, err); 11 if (likely(sock)) { 12 /* 设置是否需要减少引用计数的标志 */ 13 *fput_needed = f.flags; 14 return sock; 15 } 16 fdput(f); 17 } 18 return NULL; 19 }
1 /* 2 * Support routines. 3 * Move socket addresses back and forth across the kernel/user 4 * divide and look after the messy bits. 5 */ 6 7 /** 8 * move_addr_to_kernel - copy a socket address into kernel space 9 * @uaddr: Address in user space 10 * @kaddr: Address in kernel space 11 * @ulen: Length in user space 12 * 13 * The address is copied into kernel space. If the provided address is 14 * too long an error code of -EINVAL is returned. If the copy gives 15 * invalid addresses -EFAULT is returned. On a success 0 is returned. 16 */ 17 18 /* 复制socket地址到内核空间 */ 19 int move_addr_to_kernel(void __user *uaddr, int ulen, struct sockaddr_storage *kaddr) 20 { 21 /* 长度检查 */ 22 if (ulen < 0 || ulen > sizeof(struct sockaddr_storage)) 23 return -EINVAL; 24 if (ulen == 0) 25 return 0; 26 27 /* 从用户空间拷贝数据 */ 28 if (copy_from_user(kaddr, uaddr, ulen)) 29 return -EFAULT; 30 31 /* 审计信息 */ 32 return audit_sockaddr(ulen, kaddr); 33 }
bind系统调用函数实现的红色部分,最终会调用inet_bind;
1 /* 地址绑定 */ 2 int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len) 3 { 4 struct sockaddr_in *addr = (struct sockaddr_in *)uaddr; 5 struct sock *sk = sock->sk; 6 struct inet_sock *inet = inet_sk(sk); 7 struct net *net = sock_net(sk); 8 unsigned short snum; 9 int chk_addr_ret; 10 u32 tb_id = RT_TABLE_LOCAL; 11 int err; 12 13 /* If the socket has its own bind function then use it. (RAW) */ 14 /* 15 如果传输控制块有自己的bind操作则调用, 16 目前只有raw实现了自己的bind 17 */ 18 if (sk->sk_prot->bind) { 19 err = sk->sk_prot->bind(sk, uaddr, addr_len); 20 goto out; 21 } 22 23 err = -EINVAL; 24 /* 地址长度错误 */ 25 if (addr_len < sizeof(struct sockaddr_in)) 26 goto out; 27 28 /* 如果不是AF_INET协议族 */ 29 if (addr->sin_family != AF_INET) { 30 /* Compatibility games : accept AF_UNSPEC (mapped to AF_INET) 31 * only if s_addr is INADDR_ANY. 32 */ 33 err = -EAFNOSUPPORT; 34 35 /* 接受AF_UNSPEC && s_addr=htonl(INADDR_ANY)的情况 */ 36 if (addr->sin_family != AF_UNSPEC || 37 addr->sin_addr.s_addr != htonl(INADDR_ANY)) 38 goto out; 39 } 40 41 tb_id = l3mdev_fib_table_by_index(net, sk->sk_bound_dev_if) ? : tb_id; 42 chk_addr_ret = inet_addr_type_table(net, addr->sin_addr.s_addr, tb_id); 43 44 /* Not specified by any standard per-se, however it breaks too 45 * many applications when removed. It is unfortunate since 46 * allowing applications to make a non-local bind solves 47 * several problems with systems using dynamic addressing. 48 * (ie. your servers still start up even if your ISDN link 49 * is temporarily down) 50 */ 51 err = -EADDRNOTAVAIL; 52 53 /* 合法性检查 */ 54 if (!net->ipv4.sysctl_ip_nonlocal_bind && 55 !(inet->freebind || inet->transparent) && 56 addr->sin_addr.s_addr != htonl(INADDR_ANY) && 57 chk_addr_ret != RTN_LOCAL && 58 chk_addr_ret != RTN_MULTICAST && 59 chk_addr_ret != RTN_BROADCAST) 60 goto out; 61 62 /* 源端口 */ 63 snum = ntohs(addr->sin_port); 64 err = -EACCES; 65 66 /* 绑定特权端口的权限检查 */ 67 if (snum && snum < inet_prot_sock(net) && 68 !ns_capable(net->user_ns, CAP_NET_BIND_SERVICE)) 69 goto out; 70 71 /* We keep a pair of addresses. rcv_saddr is the one 72 * used by hash lookups, and saddr is used for transmit. 73 * 74 * In the BSD API these are the same except where it 75 * would be illegal to use them (multicast/broadcast) in 76 * which case the sending device address is used. 77 */ 78 lock_sock(sk); 79 80 /* Check these errors (active socket, double bind). */ 81 err = -EINVAL; 82 83 /* 传输控制块的状态不是CLOSE || 存在本地端口 */ 84 if (sk->sk_state != TCP_CLOSE || inet->inet_num) 85 goto out_release_sock; 86 87 /* 设置源地址rcv_addr用作hash查找,saddr用作传输 */ 88 inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr; 89 90 /* 组播或者广播,使用设备地址 */ 91 if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) 92 inet->inet_saddr = 0; /* Use device */ 93 94 /* Make sure we are allowed to bind here. */ 95 96 /* 97 端口不为0,或者端口为0允许绑定 98 则使用协议的具体获取端口函数绑定端口 99 */ 100 if ((snum || !inet->bind_address_no_port) && 101 sk->sk_prot->get_port(sk, snum)) { 102 103 /* 绑定失败 */ 104 inet->inet_saddr = inet->inet_rcv_saddr = 0; 105 106 /* 端口在使用中 */ 107 err = -EADDRINUSE; 108 goto out_release_sock; 109 } 110 111 /* 传输控制块已经绑定本地地址或端口标志 */ 112 if (inet->inet_rcv_saddr) 113 sk->sk_userlocks |= SOCK_BINDADDR_LOCK; 114 if (snum) 115 sk->sk_userlocks |= SOCK_BINDPORT_LOCK; 116 117 /* 设置源端口 */ 118 inet->inet_sport = htons(inet->inet_num); 119 120 /* 设置目的地址和端口默认值 */ 121 inet->inet_daddr = 0; 122 inet->inet_dport = 0; 123 124 /* 设置路由默认值 */ 125 sk_dst_reset(sk); 126 err = 0; 127 out_release_sock: 128 release_sock(sk); 129 out: 130 return err; 131 } 132 EXPORT_SYMBOL(inet_bind);
get_port会调用具体协议的获取端口函数,比如tcp的inet_csk_get_port函数,具体流程会在阅读tcp代码时分析;