// struct sock->sk_prot字段 // struct proto为插口层到传输层的接口 4.1 struct proto raw_prot = { .name = "RAW", .owner = THIS_MODULE, .close = raw_close, .destroy = raw_destroy, .connect = ip4_datagram_connect, .disconnect = udp_disconnect, .ioctl = raw_ioctl, .init = raw_init, .setsockopt = raw_setsockopt, .getsockopt = raw_getsockopt, .sendmsg = raw_sendmsg, .recvmsg = raw_recvmsg, .bind = raw_bind, .backlog_rcv = raw_rcv_skb, .release_cb = ip4_datagram_release_cb, .hash = raw_hash_sk, .unhash = raw_unhash_sk, .obj_size = sizeof(struct raw_sock), .h.raw_hash = &raw_v4_hashinfo, }; // raw sock绑定地址到socket 4.1 static int raw_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct inet_sock *inet = inet_sk(sk); struct sockaddr_in *addr = (struct sockaddr_in *) uaddr; int ret = -EINVAL; int chk_addr_ret; //sk->sk_state!=TCP_CLOSE说明连接已经建立 if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in)) goto out; //检查绑定的地址类型是否合法 chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); ret = -EADDRNOTAVAIL; //合法的绑定地址类型:本地地址,多播地址,广播地址 if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) goto out; //多播,广播地址,源地址使用接口设备的地址 inet->inet_rcv_saddr = inet->inet_saddr = addr->sin_addr.s_addr; if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) inet->inet_saddr = 0; sk_dst_reset(sk); ret = 0; out: return ret; } // 建立连接 // 步骤: // 1.建立路由信息 // 2.更新sock->sk_state=TCP_ESTABLISHED表示建立了连接 4.2 int ip4_datagram_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len) { struct inet_sock *inet = inet_sk(sk); struct sockaddr_in *usin = (struct sockaddr_in *) uaddr; struct flowi4 *fl4; struct rtable *rt; __be32 saddr; int oif; int err; //重置inet的路由信息 sk_dst_reset(sk); lock_sock(sk); //sock绑定的设备(可通过setsockopt建立) oif = sk->sk_bound_dev_if; saddr = inet->inet_saddr; fl4 = &inet->cork.fl.u.ip4; //建立路由信息 rt = ip_route_connect(fl4, usin->sin_addr.s_addr, saddr, RT_CONN_FLAGS(sk), oif, sk->sk_protocol, inet->inet_sport, usin->sin_port, sk, true); ... inet->inet_daddr = fl4->daddr; inet->inet_dport = usin->sin_port; //更新sk->sk_state表示建立了连接 sk->sk_state = TCP_ESTABLISHED; inet->inet_id = jiffies; //设置sock路由缓存 sk_dst_set(sk, &rt->dst); err = 0; out: release_sock(sk); return err; } // 发送数据 // 步骤: // 1.获取目的地址 // 1.1 通过msghdr或inet_sock // 2.初始化flow4结构体 // 3.通过flow4查找路由表,获取路由信息 // 4.将数据报添加到sk->sk_write_queue // 5.没有设置MSG_MORE,通知ip层进程数据传输 4.3 static int raw_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len) { struct inet_sock *inet = inet_sk(sk); struct ipcm_cookie ipc; struct rtable *rt = NULL; struct flowi4 fl4; int free = 0; __be32 daddr; __be32 saddr; u8 tos; int err; struct ip_options_data opt_copy; ... ipc.addr = inet->inet_saddr; ipc.opt = NULL; ipc.tx_flags = 0; //使用bound的出口设备 ipc.oif = sk->sk_bound_dev_if; saddr = ipc.addr; ipc.addr = daddr; tos = RT_CONN_FLAGS(sk); //初始化flowi4结构 flowi4_init_output(&fl4, ipc.oif, sk->sk_mark, tos, RT_SCOPE_UNIVERSE, inet->hdrincl ? IPPROTO_RAW : sk->sk_protocol, inet_sk_flowi_flags(sk) | FLOWI_FLAG_CAN_SLEEP, daddr, saddr, 0, 0); //查找路由表,获得路由信息 rt = ip_route_output_flow(sock_net(sk), &fl4, sk); err = -EACCES; //路由结果为广播,但是套接字不允许发送广播报文,直接返回 if (rt->rt_flags & RTCF_BROADCAST && !sock_flag(sk, SOCK_BROADCAST)) goto done; //目的地址 if (!ipc.addr) ipc.addr = fl4.daddr; lock_sock(sk); //添加数据报到sock->sk_write_queue err = ip_append_data(sk, &fl4, ip_generic_getfrag, msg->msg_iov, len, 0, &ipc, &rt, msg->msg_flags); //出现错误,丢弃所有已经pending的ip报文 if (err) ip_flush_pending_frames(sk); //MSG_MORE表示接下来还有msg else if (!(msg->msg_flags & MSG_MORE)) { //将sk_write_queue上的数据发送出去 err = ip_push_pending_frames(sk, &fl4); if (err == -ENOBUFS && !inet->recverr) err = 0; release_sock(sk); } done: if (free) kfree(ipc.opt); //递减路由信息的引用计数 ip_rt_put(rt); out: if (err < 0) return err; return len; } // 接收数据 // 步骤: // 1.接收数据报 // 2.将数据报拷贝到iovec中 4.4 static int raw_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg, size_t len, int noblock, int flags, int *addr_len) { struct inet_sock *inet = inet_sk(sk); size_t copied = 0; int err = -EOPNOTSUPP; struct sockaddr_in *sin = (struct sockaddr_in *)msg->msg_name; struct sk_buff *skb; //接收数据报 skb = skb_recv_datagram(sk, flags, noblock, &err); if (!skb) goto out; //将数据从skb拷贝到iovec err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); if (err) goto done; //拷贝skb中的源地址 if (sin) { sin->sin_family = AF_INET; sin->sin_addr.s_addr = ip_hdr(skb)->saddr; sin->sin_port = 0; memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); } done: skb_free_datagram(sk, skb); out: if (err) return err; return copied; } // 接收数据报 // 步骤: // 1.获取允许的阻塞时间 // 2.如果sock->sk_receive_queue有接收到的skb,返回skb // 3.如果可阻塞等待,则阻塞,否则直接返回null 4.5 struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned int flags, int *peeked, int *off, int *err) { struct sk_buff *skb; long timeo; //计算等待到期时间 timeo = sock_rcvtimeo(sk, flags & MSG_DONTWAIT); do { //取下sock->sk_receive_queue接收到的skb unsigned long cpu_flags; struct sk_buff_head *queue = &sk->sk_receive_queue; spin_lock_irqsave(&queue->lock, cpu_flags); skb_queue_walk(queue, skb) { __skb_unlink(skb, queue); spin_unlock_irqrestore(&queue->lock, cpu_flags); return skb; } spin_unlock_irqrestore(&queue->lock, cpu_flags); error = -EAGAIN; if (!timeo) goto no_packet; //等待数据到来 } while (!wait_for_packet(sk, err, &timeo)); return NULL; no_packet: *err = error; return NULL; } // 在sock上等待数据到来 // 1. 创建wait块,指定wait_func // 2. 将wait块添加到sock->sk_wq上 // 3. 通过schedule_timeout阻塞 // 注: // 创建的wait块添加到sock->sk_wq用于在有事件发生时,唤醒阻塞线程, // 但是阻塞是通过schedule_timeout执行,而非wait块 4.6 static int wait_for_packet(struct sock *sk, int *err, long *timeo_p) { int error; //创建wait块 DEFINE_WAIT_FUNC(wait, receiver_wake_function); //将wait块添加到sock->sk_wq上 prepare_to_wait_exclusive(sk_sleep(sk), &wait, TASK_INTERRUPTIBLE); ... error = 0; //重调度 *timeo_p = schedule_timeout(*timeo_p); out: finish_wait(sk_sleep(sk), &wait); return error; }
时间: 2024-11-30 07:01:38