4 bind()
对应到sys_socketcall中调用sys_bind()
4.1 sys_bind()
{
struct socket *sock;
char address[MAX_SOCK_ADDR];
int err, fput_needed;
sock = sockfd_lookup_light(fd, &err, &fput_needed); //fd来找到指定的sock指针, 4.2
if (sock) {
err = move_addr_to_kernel(umyaddr, addrlen, address); //用户空间的umyaddr放内核空间address 4.7
if (err >= 0) {
err = security_socket_bind(sock,
(struct sockaddr *)address,
addrlen);
if (!err)
//函数指针结构体的说明,会调用inet_bind
err = sock->ops->bind(sock,
(struct sockaddr *)
address, addrlen);
}
fput_light(sock->file, fput_needed);
}
return err;
}
4.2 sockfd_lookup_light
从fd找到其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); //从fd先找到file*
if (file) {
sock = sock_from_file(file, err); //从file找到socket* 4.6
if (sock)
return sock;
fput_light(file, *fput_needed);
}
return NULL;
}
4.3 fget_light
从fd找到file*
struct file fastcall *fget_light(unsigned int fd, int *fput_needed)
{
struct file *file;
struct files_struct *files = current->files; //当前进程的files
*fput_needed = 0;
if (likely((atomic_read(&files->count) == 1))) {
file = fcheck_files(files, fd); //从files和fd中查找到file 4.4
} else {
rcu_read_lock();
file = fcheck_files(files, fd);
if (file) {
if (atomic_inc_not_zero(&file->f_count))
*fput_needed = 1;
else
file = NULL;
}
rcu_read_unlock();
}
return file;
}
4.4 fcheck_files
从files和fd找到file
static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
{
struct file * file = NULL;
struct fdtable *fdt = files_fdtable(files); //从files中获取fdtable, 4.5
if (fd < fdt->max_fds)
file = rcu_dereference(fdt->fd[fd]); //从fdtable中获取file, 4.5
return file;
}
4.5 从files->fdtable->file
#define files_fdtable(files) (rcu_dereference((files)->fdt))
struct fdtable {
unsigned int max_fds;
struct file ** fd; //保持了file的数组,当传入fd后,就可以获取file*, fdt->fd[fd] ;
fd_set *close_on_exec;
fd_set *open_fds;
struct rcu_head rcu;
struct fdtable *next;
};
4.6 sock_from_file
static struct socket *sock_from_file(struct file *file, int *err)
{
if (file->f_op == &socket_file_ops)
return file->private_data; // 在 sock_map_fd 3.6中, socket*保持到了private_date中
*err = -ENOTSOCK;
return NULL;
}
4.7 move_addr_to_kernel
将用户空间的地址放入内核空间
int move_addr_to_kernel(void __user *uaddr, int ulen, void *kaddr)
{
if (ulen < 0 || ulen > MAX_SOCK_ADDR) //大小检查
return -EINVAL;
if (ulen == 0)
return 0;
if (copy_from_user(kaddr, uaddr, ulen)) //拷贝函数,把一段数据从用户空间拷贝到内核空间
return -EFAULT;
return audit_sockaddr(ulen, kaddr); //审核地址,先跳过把
}
4.2 inet_bind
检查地址类型,端口是否占用,如果没有就赋值到sk: struct sock* sk = sock->sk;
1int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
struct sockaddr_in *addr = (struct sockaddr_in *)uaddr;
struct sock *sk = sock->sk;
struct inet_sock *inet = inet_sk(sk);
unsigned short snum;
int chk_addr_ret;
int err;
//如果有自己定义的bind,就调用自己的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;
//检查地址类型:广播地址、组播地址、本地地址
chk_addr_ret = inet_addr_type(&init_net, addr->sin_addr.s_addr);
err = -EADDRNOTAVAIL;
//不是本地地址、也不是组播、广播、和全0xFF地址,则返回,报告地址错误
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;
//检查端口
snum = ntohs(addr->sin_port);
err = -EACCES;
//#define PROT_SOCK 1024 ,不允许用1024以下的端口
if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
goto out;
/* We keep a pair of addresses. rcv_saddr is the one
* used by hash lookups, and saddr is used for transmit.
*
* In the BSD API these are the same except where it
* would be illegal to use them (multicast/broadcast) in
* which case the sending device address is used.
*/
lock_sock(sk);
/* Check these errors (active socket, double bind). */
err = -EINVAL;
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 */
/* Make sure we are allowed to bind here. */
if (sk->sk_prot->get_port(sk, snum)) {
inet->saddr = inet->rcv_saddr = 0;
err = -EADDRINUSE;
goto out_release_sock;
}
if (inet->rcv_saddr)
sk->sk_userlocks |= SOCK_BINDADDR_LOCK;
if (snum)
sk->sk_userlocks |= SOCK_BINDPORT_LOCK;
inet->sport = htons(inet->num);
inet->daddr = 0;
inet->dport = 0;
sk_dst_reset(sk);
err = 0;
out_release_sock:
release_sock(sk);
out:
return err;
}
根据地址,判断地址类型:广播地址、多播地址、本地地址
unsigned int inet_addr_type(struct net *net, __be32 addr)
{
return __inet_dev_addr_type(net, NULL, addr);
}
static inline unsigned __inet_dev_addr_type(struct net *net,
const struct net_device *dev,
__be32 addr)
{
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = addr } } };
struct fib_result res;
unsigned ret = RTN_BROADCAST;
struct fib_table *local_table;
if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
return RTN_BROADCAST;
if (ipv4_is_multicast(addr))
return RTN_MULTICAST;
#ifdef CONFIG_IP_MULTIPLE_TABLES
res.r = NULL;
#endif
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;
}
static inline bool ipv4_is_loopback(__be32 addr)
{
return (addr & htonl(0xff000000)) == htonl(0x7f000000);
}
static inline bool ipv4_is_multicast(__be32 addr)
{
return (addr & htonl(0xf0000000)) == htonl(0xe0000000);
}
static inline bool ipv4_is_local_multicast(__be32 addr)
{
return (addr & htonl(0xffffff00)) == htonl(0xe0000000);
}
static inline bool ipv4_is_lbcast(__be32 addr)
{
/* limited broadcast */
return addr == htonl(INADDR_BROADCAST);
}
static inline bool ipv4_is_zeronet(__be32 addr)
{
return (addr & htonl(0xff000000)) == htonl(0x00000000);
}
从本地的表中取出本地地址
static inline struct fib_table *fib_get_table(struct net *net, u32 id)
{
struct hlist_head *ptr;
ptr = id == RT_TABLE_LOCAL ?
&net->ipv4.fib_table_hash[TABLE_LOCAL_INDEX] :
&net->ipv4.fib_table_hash[TABLE_MAIN_INDEX];
return hlist_entry(ptr->first, struct fib_table, tb_hlist);
}
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
返回包含fib_table的指针
struct hlist_node tb_hlist;
u32 tb_id;
unsigned tb_stamp;
int tb_default;
int (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res);
int (*tb_insert)(struct fib_table *, struct fib_config *);
int (*tb_delete)(struct fib_table *, struct fib_config *);
int (*tb_dump)(struct fib_table *table, struct sk_buff *skb,
struct netlink_callback *cb);
int (*tb_flush)(struct fib_table *table);
void (*tb_select_default)(struct fib_table *table,
const struct flowi *flp, struct fib_result *res);
unsigned char tb_data[0];
}