📄 af_inet.c
字号:
goto out;}/* * 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; int err = -EINVAL; struct sock *sk2 = sk1->sk_prot->accept(sk1, flags, &err); if (!sk2) goto do_err; lock_sock(sk2); BUG_TRAP((1 << sk2->sk_state) & (TCPF_ESTABLISHED | TCPF_CLOSE_WAIT | TCPF_CLOSE)); sock_graft(sk2, newsock); newsock->state = SS_CONNECTED; err = 0; release_sock(sk2);do_err: return err;}/* * This does both peername and sockname. */int inet_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_len, int peer){ struct sock *sk = sock->sk; struct inet_opt *inet = inet_sk(sk); struct sockaddr_in *sin = (struct sockaddr_in *)uaddr; sin->sin_family = AF_INET; if (peer) { if (!inet->dport || (((1 << sk->sk_state) & (TCPF_CLOSE | TCPF_SYN_SENT)) && peer == 1)) return -ENOTCONN; sin->sin_port = inet->dport; sin->sin_addr.s_addr = inet->daddr; } else { __u32 addr = inet->rcv_saddr; if (!addr) addr = inet->saddr; sin->sin_port = inet->sport; sin->sin_addr.s_addr = addr; } memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); *uaddr_len = sizeof(*sin); return 0;}int inet_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size){ struct sock *sk = sock->sk; /* We may need to bind the socket. */ if (!inet_sk(sk)->num && inet_autobind(sk)) return -EAGAIN; return sk->sk_prot->sendmsg(iocb, sk, msg, size);}ssize_t inet_sendpage(struct socket *sock, struct page *page, int offset, size_t size, int flags){ struct sock *sk = sock->sk; /* We may need to bind the socket. */ if (!inet_sk(sk)->num && inet_autobind(sk)) return -EAGAIN; if (sk->sk_prot->sendpage) return sk->sk_prot->sendpage(sk, page, offset, size, flags); return sock_no_sendpage(sock, page, offset, size, flags);}int inet_shutdown(struct socket *sock, int how){ struct sock *sk = sock->sk; int err = 0; /* 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) /* MAXINT->0 */ return -EINVAL; lock_sock(sk); if (sock->state == SS_CONNECTING) { if ((1 << sk->sk_state) & (TCPF_SYN_SENT | TCPF_SYN_RECV | TCPF_CLOSE)) sock->state = SS_DISCONNECTING; else sock->state = SS_CONNECTED; } switch (sk->sk_state) { case TCP_CLOSE: err = -ENOTCONN; /* Hack to wake up other listeners, who can poll for POLLHUP, even on eg. unconnected UDP sockets -- RR */ default: sk->sk_shutdown |= how; if (sk->sk_prot->shutdown) sk->sk_prot->shutdown(sk, how); break; /* Remaining two branches are temporary solution for missing * close() in multithreaded environment. It is _not_ a good idea, * but we have no choice until close() is repaired at VFS level. */ case TCP_LISTEN: if (!(how & RCV_SHUTDOWN)) break; /* Fall through */ case TCP_SYN_SENT: err = sk->sk_prot->disconnect(sk, O_NONBLOCK); sock->state = err ? SS_DISCONNECTING : SS_UNCONNECTED; break; } /* Wake up anyone sleeping in poll. */ sk->sk_state_change(sk); release_sock(sk); return err;}/* * 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. */int inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg){ struct sock *sk = sock->sk; int err = 0; switch (cmd) { case SIOCGSTAMP: err = sock_get_timestamp(sk, (struct timeval __user *)arg); break; case SIOCADDRT: case SIOCDELRT: case SIOCRTMSG: err = ip_rt_ioctl(cmd, (void __user *)arg); break; case SIOCDARP: case SIOCGARP: case SIOCSARP: err = arp_ioctl(cmd, (void __user *)arg); break; case SIOCGIFADDR: case SIOCSIFADDR: case SIOCGIFBRDADDR: case SIOCSIFBRDADDR: case SIOCGIFNETMASK: case SIOCSIFNETMASK: case SIOCGIFDSTADDR: case SIOCSIFDSTADDR: case SIOCSIFPFLAGS: case SIOCGIFPFLAGS: case SIOCSIFFLAGS: err = devinet_ioctl(cmd, (void __user *)arg); break; default: if (!sk->sk_prot->ioctl || (err = sk->sk_prot->ioctl(sk, cmd, arg)) == -ENOIOCTLCMD) err = dev_ioctl(cmd, (void __user *)arg); break; } return err;}struct proto_ops inet_stream_ops = { .family = PF_INET, .owner = THIS_MODULE, .release = inet_release, .bind = inet_bind, .connect = inet_stream_connect, .socketpair = sock_no_socketpair, .accept = inet_accept, .getname = inet_getname, .poll = tcp_poll, .ioctl = inet_ioctl, .listen = inet_listen, .shutdown = inet_shutdown, .setsockopt = sock_common_setsockopt, .getsockopt = sock_common_getsockopt, .sendmsg = inet_sendmsg, .recvmsg = sock_common_recvmsg, .mmap = sock_no_mmap, .sendpage = tcp_sendpage};struct proto_ops inet_dgram_ops = { .family = PF_INET, .owner = THIS_MODULE, .release = inet_release, .bind = inet_bind, .connect = inet_dgram_connect, .socketpair = sock_no_socketpair, .accept = sock_no_accept, .getname = inet_getname, .poll = datagram_poll, .ioctl = inet_ioctl, .listen = sock_no_listen, .shutdown = inet_shutdown, .setsockopt = sock_common_setsockopt, .getsockopt = sock_common_getsockopt, .sendmsg = inet_sendmsg, .recvmsg = sock_common_recvmsg, .mmap = sock_no_mmap, .sendpage = inet_sendpage,};static struct net_proto_family inet_family_ops = { .family = PF_INET, .create = inet_create, .owner = THIS_MODULE,};extern void tcp_init(void);extern void tcp_v4_init(struct net_proto_family *);/* Upon startup we insert all the elements in inetsw_array[] into * the linked list inetsw. */static struct inet_protosw inetsw_array[] ={ { .type = SOCK_STREAM, .protocol = IPPROTO_TCP, .prot = &tcp_prot, .ops = &inet_stream_ops, .capability = -1, .no_check = 0, .flags = INET_PROTOSW_PERMANENT, }, { .type = SOCK_DGRAM, .protocol = IPPROTO_UDP, .prot = &udp_prot, .ops = &inet_dgram_ops, .capability = -1, .no_check = UDP_CSUM_DEFAULT, .flags = INET_PROTOSW_PERMANENT, }, { .type = SOCK_RAW, .protocol = IPPROTO_IP, /* wild card */ .prot = &raw_prot, .ops = &inet_dgram_ops, .capability = CAP_NET_RAW, .no_check = UDP_CSUM_DEFAULT, .flags = INET_PROTOSW_REUSE, }};#define INETSW_ARRAY_LEN (sizeof(inetsw_array) / sizeof(struct inet_protosw))void inet_register_protosw(struct inet_protosw *p){ struct list_head *lh; struct inet_protosw *answer; int protocol = p->protocol; struct list_head *last_perm; spin_lock_bh(&inetsw_lock); if (p->type >= SOCK_MAX) goto out_illegal; /* If we are trying to override a permanent protocol, bail. */ answer = NULL; last_perm = &inetsw[p->type]; list_for_each(lh, &inetsw[p->type]) { answer = list_entry(lh, struct inet_protosw, list); /* Check only the non-wild match. */ if (INET_PROTOSW_PERMANENT & answer->flags) { if (protocol == answer->protocol) break; last_perm = lh; } answer = NULL; } if (answer) goto out_permanent; /* Add the new entry after the last permanent entry if any, so that * the new entry does not override a permanent entry when matched with * a wild-card protocol. But it is allowed to override any existing * non-permanent entry. This means that when we remove this entry, the * system automatically returns to the old behavior. */ list_add_rcu(&p->list, last_perm);out: spin_unlock_bh(&inetsw_lock); synchronize_net(); return;out_permanent: printk(KERN_ERR "Attempt to override permanent protocol %d.\n", protocol); goto out;out_illegal: printk(KERN_ERR "Ignoring attempt to register invalid socket type %d.\n", p->type); goto out;}void inet_unregister_protosw(struct inet_protosw *p){ if (INET_PROTOSW_PERMANENT & p->flags) { printk(KERN_ERR "Attempt to unregister permanent protocol %d.\n", p->protocol); } else { spin_lock_bh(&inetsw_lock); list_del_rcu(&p->list); spin_unlock_bh(&inetsw_lock); synchronize_net(); }}#ifdef CONFIG_IP_MULTICASTstatic struct net_protocol igmp_protocol = { .handler = igmp_rcv,};#endifstatic struct net_protocol tcp_protocol = { .handler = tcp_v4_rcv, .err_handler = tcp_v4_err, .no_policy = 1,};static struct net_protocol udp_protocol = { .handler = udp_rcv, .err_handler = udp_err, .no_policy = 1,};static struct net_protocol icmp_protocol = { .handler = icmp_rcv,};static int __init init_ipv4_mibs(void){ net_statistics[0] = alloc_percpu(struct linux_mib); net_statistics[1] = alloc_percpu(struct linux_mib); ip_statistics[0] = alloc_percpu(struct ipstats_mib); ip_statistics[1] = alloc_percpu(struct ipstats_mib); icmp_statistics[0] = alloc_percpu(struct icmp_mib); icmp_statistics[1] = alloc_percpu(struct icmp_mib); tcp_statistics[0] = alloc_percpu(struct tcp_mib); tcp_statistics[1] = alloc_percpu(struct tcp_mib); udp_statistics[0] = alloc_percpu(struct udp_mib); udp_statistics[1] = alloc_percpu(struct udp_mib); if (! (net_statistics[0] && net_statistics[1] && ip_statistics[0] && ip_statistics[1] && tcp_statistics[0] && tcp_statistics[1] && udp_statistics[0] && udp_statistics[1])) return -ENOMEM; (void) tcp_mib_init(); return 0;}int ipv4_proc_init(void);extern void ipfrag_init(void);static int __init inet_init(void){ struct sk_buff *dummy_skb; struct inet_protosw *q; struct list_head *r; int rc = -EINVAL; if (sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb)) { printk(KERN_CRIT "%s: panic\n", __FUNCTION__); goto out; } rc = sk_alloc_slab(&tcp_prot, "tcp_sock"); if (rc) { sk_alloc_slab_error(&tcp_prot); goto out; } rc = sk_alloc_slab(&udp_prot, "udp_sock"); if (rc) { sk_alloc_slab_error(&udp_prot); goto out_tcp_free_slab; } rc = sk_alloc_slab(&raw_prot, "raw_sock"); if (rc) { sk_alloc_slab_error(&raw_prot); goto out_udp_free_slab; } /* * Tell SOCKET that we are alive... */ (void)sock_register(&inet_family_ops); /* * Add all the base protocols. */ if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0) printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n"); if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0) printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n"); if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0) printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");#ifdef CONFIG_IP_MULTICAST if (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0) printk(KERN_CRIT "inet_init: Cannot add IGMP protocol\n");#endif /* Register the socket-side information for inet_create. */ for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r) INIT_LIST_HEAD(r); for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q) inet_register_protosw(q); /* * 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); /* * Initialise the multicast router */#if defined(CONFIG_IP_MROUTE) ip_mr_init();#endif /* * Initialise per-cpu ipv4 mibs */ if(init_ipv4_mibs()) printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n"); ; ipv4_proc_init(); ipfrag_init(); rc = 0;out: return rc;out_tcp_free_slab: sk_free_slab(&tcp_prot);out_udp_free_slab: sk_free_slab(&udp_prot); goto out;}module_init(inet_init);/* ------------------------------------------------------------------------ */#ifdef CONFIG_PROC_FSextern int fib_proc_init(void);extern void fib_proc_exit(void);extern int ip_misc_proc_init(void);extern int raw_proc_init(void);extern void raw_proc_exit(void);extern int tcp4_proc_init(void);extern void tcp4_proc_exit(void);extern int udp4_proc_init(void);extern void udp4_proc_exit(void);int __init ipv4_proc_init(void){ int rc = 0; if (raw_proc_init()) goto out_raw; if (tcp4_proc_init()) goto out_tcp; if (udp4_proc_init()) goto out_udp; if (fib_proc_init()) goto out_fib; if (ip_misc_proc_init()) goto out_misc;out: return rc;out_misc: fib_proc_exit();out_fib: udp4_proc_exit();out_udp: tcp4_proc_exit();out_tcp: raw_proc_exit();out_raw: rc = -ENOMEM; goto out;}#else /* CONFIG_PROC_FS */int __init ipv4_proc_init(void){ return 0;}#endif /* CONFIG_PROC_FS */MODULE_ALIAS_NETPROTO(PF_INET);EXPORT_SYMBOL(inet_accept);EXPORT_SYMBOL(inet_bind);EXPORT_SYMBOL(inet_dgram_connect);EXPORT_SYMBOL(inet_dgram_ops);EXPORT_SYMBOL(inet_getname);EXPORT_SYMBOL(inet_ioctl);EXPORT_SYMBOL(inet_listen);EXPORT_SYMBOL(inet_register_protosw);EXPORT_SYMBOL(inet_release);EXPORT_SYMBOL(inet_sendmsg);EXPORT_SYMBOL(inet_shutdown);EXPORT_SYMBOL(inet_sock_destruct);EXPORT_SYMBOL(inet_stream_connect);EXPORT_SYMBOL(inet_stream_ops);EXPORT_SYMBOL(inet_unregister_protosw);EXPORT_SYMBOL(net_statistics);EXPORT_SYMBOL(tcp_protocol);EXPORT_SYMBOL(udp_protocol);#ifdef INET_REFCNT_DEBUGEXPORT_SYMBOL(inet_sock_nr);#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -