Socket Kernel Source Chapter04 bind

4 bind()

对应到sys_socketcall中调用sys_bind()

4.1 sys_bind()

 

asmlinkage long sys_bind(int fd, struct sockaddr __user *umyaddr, int addrlen)
{
        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];
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值