📄 af_inet.c
字号:
break; schedule(); current->state = TASK_INTERRUPTIBLE; } current->state = TASK_RUNNING; remove_wait_queue(sk->sleep, &wait);}/* * Connect to a remote host. There is regrettably still a little * TCP 'magic' in here. */int inet_stream_connect(struct socket *sock, struct sockaddr * uaddr, int addr_len, int flags){ struct sock *sk=sock->sk; int err; if(sock->state != SS_UNCONNECTED && sock->state != SS_CONNECTING) { if(sock->state == SS_CONNECTED) return -EISCONN; return -EINVAL; } if(sock->state == SS_CONNECTING) { /* Note: tcp_connected contains SYN_RECV, which may cause bogus results here. -AK */ if(tcp_connected(sk->state)) { sock->state = SS_CONNECTED; return 0; } if (sk->zapped || sk->err) goto sock_error; if (flags & O_NONBLOCK) return -EALREADY; } else { if (sk->prot->connect == NULL) return(-EOPNOTSUPP); /* We may need to bind the socket. */ if (inet_autobind(sk) != 0) return(-EAGAIN); err = sk->prot->connect(sk, uaddr, addr_len); /* Note: there is a theoretical race here when an wake up occurred before inet_wait_for_connect is entered. In 2.3 the wait queue setup should be moved before the low level connect call. -AK*/ if (err < 0) return(err); sock->state = SS_CONNECTING; } if (sk->state > TCP_FIN_WAIT2 && sock->state == SS_CONNECTING) goto sock_error; if (sk->state != TCP_ESTABLISHED && (flags & O_NONBLOCK)) return (-EINPROGRESS); if (sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) { inet_wait_for_connect(sk); if (signal_pending(current)) return -ERESTARTSYS; } sock->state = SS_CONNECTED; if ((sk->state != TCP_ESTABLISHED) && sk->err) goto sock_error; return(0);sock_error: /* This is ugly but needed to fix a race in the ICMP error handler */ if (sk->zapped && sk->state != TCP_CLOSE) { lock_sock(sk); tcp_set_state(sk, TCP_CLOSE); release_sock(sk); sk->zapped = 0; } sock->state = SS_UNCONNECTED; return sock_error(sk);}/* * Accept a pending connection. The TCP layer now gives BSD semantics. */int inet_accept(struct socket *sock, struct socket *newsock, int flags){ struct sock *sk1 = sock->sk, *sk2; struct sock *newsk = newsock->sk; int err = -EINVAL; if (sock->state != SS_UNCONNECTED || !(sock->flags & SO_ACCEPTCON)) goto do_err; err = -EOPNOTSUPP; if (sk1->prot->accept == NULL) goto do_err; if((sk2 = sk1->prot->accept(sk1,flags)) == NULL) goto do_sk1_err; /* * We've been passed an extra socket. * We need to free it up because the tcp module creates * its own when it accepts one. */ sk2->sleep = newsk->sleep; newsock->sk = sk2; sk2->socket = newsock; newsk->socket = NULL; if (flags & O_NONBLOCK) goto do_half_success; if(sk2->state == TCP_ESTABLISHED) goto do_full_success; if(sk2->err > 0) goto do_connect_err; err = -ECONNABORTED; if (sk2->state == TCP_CLOSE) goto do_bad_connection;do_full_success: destroy_sock(newsk); newsock->state = SS_CONNECTED; return 0;do_half_success: destroy_sock(newsk); return(0);do_connect_err: err = sock_error(sk2);do_bad_connection: sk2->sleep = NULL; sk2->socket = NULL; destroy_sock(sk2); newsock->sk = newsk; newsk->socket = newsock; return err;do_sk1_err: err = sock_error(sk1);do_err: return err;}/* * This does both peername and sockname. */static int inet_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer){ struct sock *sk = sock->sk; struct sockaddr_in *sin = (struct sockaddr_in *)uaddr; sin->sin_family = AF_INET; if (peer) { if (!tcp_connected(sk->state)) return(-ENOTCONN); sin->sin_port = sk->dport; sin->sin_addr.s_addr = sk->daddr; } else { __u32 addr = sk->rcv_saddr; if (!addr) addr = sk->saddr; sin->sin_port = sk->sport; sin->sin_addr.s_addr = addr; } *uaddr_len = sizeof(*sin); return(0);}int inet_recvmsg(struct socket *sock, struct msghdr *msg, int size, int flags, struct scm_cookie *scm){ struct sock *sk = sock->sk; int addr_len = 0; int err; if (sock->flags & SO_ACCEPTCON) return(-EINVAL); if (sk->prot->recvmsg == NULL) return(-EOPNOTSUPP); /* We may need to bind the socket. */ if (inet_autobind(sk) != 0) return(-EAGAIN); err = sk->prot->recvmsg(sk, msg, size, flags&MSG_DONTWAIT, flags&~MSG_DONTWAIT, &addr_len); if (err >= 0) msg->msg_namelen = addr_len; return err;}int inet_sendmsg(struct socket *sock, struct msghdr *msg, int size, struct scm_cookie *scm){ struct sock *sk = sock->sk; if (sk->shutdown & SEND_SHUTDOWN) { if (!(msg->msg_flags&MSG_NOSIGNAL)) send_sig(SIGPIPE, current, 1); return(-EPIPE); } if (sk->prot->sendmsg == NULL) return(-EOPNOTSUPP); if(sk->err) return sock_error(sk); /* We may need to bind the socket. */ if (inet_autobind(sk) != 0) return -EAGAIN; return sk->prot->sendmsg(sk, msg, size);}int inet_shutdown(struct socket *sock, int how){ struct sock *sk = sock->sk; /* This should really check to make sure * the socket is a TCP socket. (WHY AC...) */ how++; /* maps 0->1 has the advantage of making bit 1 rcvs and 1->2 bit 2 snds. 2->3 */ if ((how & ~SHUTDOWN_MASK) || how==0) /* MAXINT->0 */ return(-EINVAL); if (!sk) return(-ENOTCONN); if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) sock->state = SS_CONNECTED; if (!tcp_connected(sk->state)) return(-ENOTCONN); sk->shutdown |= how; if (sk->prot->shutdown) sk->prot->shutdown(sk, how); /* Wake up anyone sleeping in poll. */ sk->state_change(sk); return(0);}unsigned int inet_poll(struct file * file, struct socket *sock, poll_table *wait){ struct sock *sk = sock->sk; if (sk->prot->poll == NULL) return(0); return sk->prot->poll(file, sock, wait);}#ifdef _HURD_#define inet_ioctl 0#else/* * ioctl() calls you can issue on an INET socket. Most of these are * device configuration and stuff and very rarely used. Some ioctls * pass on to the socket itself. * * NOTE: I like the idea of a module for the config stuff. ie ifconfig * loads the devconfigure module does its configuring and unloads it. * There's a good 20K of config code hanging around the kernel. */static int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct sock *sk = sock->sk; int err; int pid; switch(cmd) { case FIOSETOWN: case SIOCSPGRP: err = get_user(pid, (int *) arg); if (err) return err; if (current->pid != pid && current->pgrp != -pid && !capable(CAP_NET_ADMIN)) return -EPERM; sk->proc = pid; return(0); case FIOGETOWN: case SIOCGPGRP: return put_user(sk->proc, (int *)arg); case SIOCGSTAMP: if(sk->stamp.tv_sec==0) return -ENOENT; err = copy_to_user((void *)arg,&sk->stamp,sizeof(struct timeval)); if (err) err = -EFAULT; return err; case SIOCADDRT: case SIOCDELRT: case SIOCRTMSG: return(ip_rt_ioctl(cmd,(void *) arg)); case SIOCDARP: case SIOCGARP: case SIOCSARP: return(arp_ioctl(cmd,(void *) arg)); case SIOCDRARP: case SIOCGRARP: case SIOCSRARP:#ifdef CONFIG_KMOD if (rarp_ioctl_hook == NULL) request_module("rarp");#endif if (rarp_ioctl_hook != NULL) return(rarp_ioctl_hook(cmd,(void *) arg)); case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCSIFPFLAGS: case SIOCGIFPFLAGS: case SIOCSIFFLAGS: return(devinet_ioctl(cmd,(void *) arg)); case SIOCGIFBR: case SIOCSIFBR:#ifdef CONFIG_BRIDGE return(br_ioctl(cmd,(void *) arg));#else return -ENOPKG;#endif case SIOCADDDLCI: case SIOCDELDLCI:#ifdef CONFIG_DLCI return(dlci_ioctl(cmd, (void *) arg));#endif#ifdef CONFIG_DLCI_MODULE#ifdef CONFIG_KMOD if (dlci_ioctl_hook == NULL) request_module("dlci");#endif if (dlci_ioctl_hook) return((*dlci_ioctl_hook)(cmd, (void *) arg));#endif return -ENOPKG; default: if ((cmd >= SIOCDEVPRIVATE) && (cmd <= (SIOCDEVPRIVATE + 15))) return(dev_ioctl(cmd,(void *) arg));#ifdef CONFIG_NET_RADIO if((cmd >= SIOCIWFIRST) && (cmd <= SIOCIWLAST)) return(dev_ioctl(cmd,(void *) arg));#endif if (sk->prot->ioctl==NULL || (err=sk->prot->ioctl(sk, cmd, arg))==-ENOIOCTLCMD) return(dev_ioctl(cmd,(void *) arg)); return err; } /*NOTREACHED*/ return(0);}#endifstruct proto_ops inet_stream_ops = { PF_INET, sock_no_dup, inet_release, inet_bind, inet_stream_connect, sock_no_socketpair, inet_accept, inet_getname, inet_poll, inet_ioctl, inet_listen, inet_shutdown, inet_setsockopt, inet_getsockopt, sock_no_fcntl, inet_sendmsg, inet_recvmsg};struct proto_ops inet_dgram_ops = { PF_INET, sock_no_dup, inet_release, inet_bind, inet_dgram_connect, sock_no_socketpair, sock_no_accept, inet_getname, datagram_poll, inet_ioctl, sock_no_listen, inet_shutdown, inet_setsockopt, inet_getsockopt, sock_no_fcntl, inet_sendmsg, inet_recvmsg};struct net_proto_family inet_family_ops = { PF_INET, inet_create};#ifdef CONFIG_PROC_FS#ifdef CONFIG_INET_RARPstatic struct proc_dir_entry proc_net_rarp = { PROC_NET_RARP, 4, "rarp", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, rarp_get_info};#endif /* RARP */static struct proc_dir_entry proc_net_raw = { PROC_NET_RAW, 3, "raw", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, raw_get_info};static struct proc_dir_entry proc_net_netstat = { PROC_NET_NETSTAT, 7, "netstat", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, netstat_get_info};static struct proc_dir_entry proc_net_snmp = { PROC_NET_SNMP, 4, "snmp", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, snmp_get_info};static struct proc_dir_entry proc_net_sockstat = { PROC_NET_SOCKSTAT, 8, "sockstat", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, afinet_get_info};static struct proc_dir_entry proc_net_tcp = { PROC_NET_TCP, 3, "tcp", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, tcp_get_info};static struct proc_dir_entry proc_net_udp = { PROC_NET_UDP, 3, "udp", S_IFREG | S_IRUGO, 1, 0, 0, 0, &proc_net_inode_operations, udp_get_info};#endif /* CONFIG_PROC_FS */extern void tcp_init(void);extern void tcp_v4_init(struct net_proto_family *);/* * Called by socket.c on kernel startup. */__initfunc(void inet_proto_init(struct net_proto *pro)){ struct sk_buff *dummy_skb; struct inet_protocol *p; printk(KERN_INFO "NET4: Linux TCP/IP 1.0 for NET4.0\n"); if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) { printk(KERN_CRIT "inet_proto_init: panic\n"); return; } /* * Tell SOCKET that we are alive... */ (void) sock_register(&inet_family_ops); /* * Add all the protocols. */ printk(KERN_INFO "IP Protocols: "); for(p = inet_protocol_base; p != NULL;) { struct inet_protocol *tmp = (struct inet_protocol *) p->next; inet_add_protocol(p); printk("%s%s",p->name,tmp?", ":"\n"); p = tmp; } /* * Set the ARP module up */ arp_init(); /* * Set the IP module up */ ip_init(); tcp_v4_init(&inet_family_ops); /* Setup TCP slab cache for open requests. */ tcp_init(); /* * Set the ICMP layer up */ icmp_init(&inet_family_ops); /* I wish inet_add_protocol had no constructor hook... I had to move IPIP from net/ipv4/protocol.c :-( --ANK */#ifdef CONFIG_NET_IPIP ipip_init();#endif#ifdef CONFIG_NET_IPGRE ipgre_init();#endif /* * Set the firewalling up */#if defined(CONFIG_IP_FIREWALL) ip_fw_init();#endif#ifdef CONFIG_IP_MASQUERADE ip_masq_init();#endif /* * Initialise the multicast router */#if defined(CONFIG_IP_MROUTE) ip_mr_init();#endif#ifdef CONFIG_INET_RARP rarp_ioctl_hook = rarp_ioctl;#endif /* * Create all the /proc entries. */#ifdef CONFIG_PROC_FS#ifdef CONFIG_INET_RARP proc_net_register(&proc_net_rarp);#endif /* RARP */ proc_net_register(&proc_net_raw); proc_net_register(&proc_net_snmp); proc_net_register(&proc_net_netstat); proc_net_register(&proc_net_sockstat); proc_net_register(&proc_net_tcp); proc_net_register(&proc_net_udp);#endif /* CONFIG_PROC_FS */}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -