Merge from vendor branch GCC:
[dragonfly.git] / sys / netinet / ip_demux.c
1 /*
2  * Copyright (c) 2003 Jeffrey Hsu
3  * All rights reserved.
4  *
5  * $DragonFly: src/sys/netinet/ip_demux.c,v 1.22 2004/04/24 06:55:57 hsu Exp $
6  */
7
8 #include "opt_inet.h"
9
10 #include <sys/param.h>
11 #include <sys/systm.h>
12 #include <sys/kernel.h>
13 #include <sys/socket.h>
14 #include <sys/socketvar.h>
15 #include <sys/thread.h>
16 #include <sys/sysctl.h>
17 #include <sys/globaldata.h>
18
19 #include <net/if.h>
20 #include <net/netisr.h>
21
22 #include <netinet/in_systm.h>
23 #include <netinet/in.h>
24 #include <netinet/in_var.h>
25 #include <netinet/in_pcb.h>
26 #include <netinet/ip.h>
27 #include <netinet/ip_var.h>
28 #include <netinet/tcp.h>
29 #include <netinet/tcpip.h>
30 #include <netinet/tcp_var.h>
31 #include <netinet/udp.h>
32 #include <netinet/udp_var.h>
33
34 extern struct thread netisr_cpu[];
35
36 static struct thread tcp_thread[MAXCPU];
37 static struct thread udp_thread[MAXCPU];
38
39 static __inline int
40 INP_MPORT_HASH(in_addr_t faddr, in_addr_t laddr,
41                in_port_t fport, in_port_t lport)
42 {
43         /*
44          * Use low order bytes.
45          */
46
47 #if (BYTE_ORDER == LITTLE_ENDIAN)
48         KASSERT(ncpus2 < 256, ("need different hash function"));  /* XXX JH */
49         return (((faddr >> 24) ^ (fport >> 8) ^ (laddr >> 24) ^ (lport >> 8)) &
50                 ncpus2_mask);
51 #else
52         return ((faddr ^ fport ^ laddr ^ lport) & ncpus2_mask);
53 #endif
54 }
55
56 /*
57  * Map a packet to a protocol processing thread.
58  */
59 lwkt_port_t
60 ip_mport(struct mbuf *m)
61 {
62         struct ip *ip;
63         int iphlen;
64         struct tcphdr *th;
65         struct udphdr *uh;
66         int thoff;                              /* TCP data offset */
67         lwkt_port_t port;
68         int cpu;
69
70         if (m->m_pkthdr.len < sizeof(struct ip)) {
71                 ipstat.ips_tooshort++;
72                 return (NULL);
73         }
74
75         if (m->m_len < sizeof(struct ip) &&
76             (m = m_pullup(m, sizeof(struct ip))) == NULL) {
77                 ipstat.ips_toosmall++;
78                 return (NULL);
79         }
80
81         ip = mtod(m, struct ip *);
82
83         /*
84          * XXX generic packet handling defrag on CPU 0 for now.
85          */
86         if (ntohs(ip->ip_off) & (IP_MF | IP_OFFMASK))
87                 return (&netisr_cpu[0].td_msgport);
88
89         iphlen = ip->ip_hl << 2;
90         if (iphlen < sizeof(struct ip)) {       /* minimum header length */
91                 ipstat.ips_badhlen++;
92                 return (NULL);
93         }
94
95         switch (ip->ip_p) {
96         case IPPROTO_TCP:
97                 if (m->m_len < iphlen + sizeof(struct tcphdr) &&
98                     (m = m_pullup(m, iphlen + sizeof(struct tcphdr))) == NULL) {
99                         tcpstat.tcps_rcvshort++;
100                         return (NULL);
101                 }
102                 th = (struct tcphdr *)((caddr_t)ip + iphlen);
103                 thoff = th->th_off << 2;
104                 if (thoff < sizeof(struct tcphdr) ||
105                     thoff > ntohs(ip->ip_len)) {
106                         tcpstat.tcps_rcvbadoff++;
107                         return (NULL);
108                 }
109                 if (m->m_len < iphlen + thoff) {
110                         m = m_pullup(m, iphlen + thoff);
111                         if (m == NULL) {
112                                 tcpstat.tcps_rcvshort++;
113                                 return (NULL);
114                         }
115                         ip = mtod(m, struct ip *);
116                         th = (struct tcphdr *)((caddr_t)ip + iphlen);
117                 }
118
119                 cpu = INP_MPORT_HASH(ip->ip_src.s_addr, ip->ip_dst.s_addr,
120                     th->th_sport, th->th_dport);
121                 port = &tcp_thread[cpu].td_msgport;
122                 break;
123         case IPPROTO_UDP:
124                 if (m->m_len < iphlen + sizeof(struct udphdr)) {
125                         m = m_pullup(m, iphlen + sizeof(struct udphdr));
126                         if (m == NULL) {
127                                 udpstat.udps_hdrops++;
128                                 return (NULL);
129                         }
130                         ip = mtod(m, struct ip *);
131                 }
132                 uh = (struct udphdr *)((caddr_t)ip + iphlen);
133
134                 if (IN_MULTICAST(ntohl(ip->ip_dst.s_addr)) ||
135                     in_broadcast(ip->ip_dst, m->m_pkthdr.rcvif)) {
136                         cpu = 0;
137                 } else {
138                         cpu = INP_MPORT_HASH(ip->ip_src.s_addr,
139                             ip->ip_dst.s_addr, uh->uh_sport, uh->uh_dport);
140                 }
141                 port = &udp_thread[cpu].td_msgport;
142                 break;
143         default:
144                 if (m->m_len < iphlen && (m = m_pullup(m, iphlen)) == NULL) {
145                         ipstat.ips_badhlen++;
146                         return (NULL);
147                 }
148                 port = &netisr_cpu[0].td_msgport;
149                 break;
150         }
151         KKASSERT(port->mp_putport != NULL);
152
153         return (port);
154 }
155
156 /*
157  * Map a TCP socket to a protocol processing thread.
158  */
159 lwkt_port_t
160 tcp_soport(struct socket *so, struct sockaddr *nam, int req)
161 {
162         struct inpcb *inp;
163
164         /* The following processing all take place on Protocol Thread 0. */
165         if (req == PRU_BIND || req == PRU_CONNECT || req == PRU_ATTACH ||
166             req == PRU_LISTEN)
167                 return (&tcp_thread[0].td_msgport);
168
169         inp = sotoinpcb(so);
170         if (!inp)               /* connection reset by peer */
171                 return (&tcp_thread[0].td_msgport);
172
173         /*
174          * Already bound and connected or listening.  For TCP connections,
175          * the (faddr, fport, laddr, lport) association cannot change now.
176          *
177          * Note: T/TCP code needs some reorganization to fit into
178          * this model.  XXX JH
179          *
180          * Rely on type-stable memory and check in protocol handler
181          * to fix race condition here w/ deallocation of inp.  XXX JH
182          */
183         return (&tcp_thread[INP_MPORT_HASH(inp->inp_faddr.s_addr,
184             inp->inp_laddr.s_addr, inp->inp_fport, inp->inp_lport)].td_msgport);
185 }
186
187 lwkt_port_t
188 tcp_addrport(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport)
189 {
190         return (&tcp_thread[tcp_addrcpu(faddr, fport,
191                                         laddr, lport)].td_msgport);
192 }
193
194 /*
195  * Map a UDP socket to a protocol processing thread.
196  */
197 lwkt_port_t
198 udp_soport(struct socket *so, struct sockaddr *nam, int req)
199 {
200         struct inpcb *inp;
201
202         /*
203          * The following processing all take place on Protocol Thread 0:
204          *   only bind() and connect() have a non-null nam parameter
205          *   attach() has a null socket parameter
206          *   Fast and slow timeouts pass in two NULLs
207          */
208         if (nam != NULL || so == NULL)
209                 return (&udp_thread[0].td_msgport);
210
211         inp = sotoinpcb(so);
212
213         if (IN_MULTICAST(ntohl(inp->inp_laddr.s_addr)))
214                 return (&udp_thread[0].td_msgport);
215
216         /*
217          * Rely on type-stable memory and check in protocol handler
218          * to fix race condition here w/ deallocation of inp.  XXX JH
219          */
220
221         return (&udp_thread[INP_MPORT_HASH(inp->inp_faddr.s_addr,
222             inp->inp_laddr.s_addr, inp->inp_fport, inp->inp_lport)].td_msgport);
223 }
224
225 /*
226  * Map a network address to a processor.
227  */
228 int
229 tcp_addrcpu(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport)
230 {
231         return (INP_MPORT_HASH(faddr, laddr, fport, lport));
232 }
233
234 int
235 udp_addrcpu(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport)
236 {
237         if (IN_MULTICAST(ntohl(laddr)))
238                 return (0);
239         else
240                 return (INP_MPORT_HASH(faddr, laddr, fport, lport));
241 }
242
243 /*
244  * Return LWKT port for cpu.
245  */
246 lwkt_port_t
247 tcp_cport(int cpu)
248 {
249         return (&tcp_thread[cpu].td_msgport);
250 }
251
252 void
253 tcp_thread_init(void)
254 {
255         int cpu;
256
257         for (cpu = 0; cpu < ncpus2; cpu++) {
258                 lwkt_create(netmsg_service_loop, NULL, NULL, 
259                         &tcp_thread[cpu], 0, cpu, "tcp_thread %d", cpu);
260                 tcp_thread[cpu].td_msgport.mp_putport = netmsg_put_port;
261         }
262 }
263
264 void
265 udp_thread_init(void)
266 {
267         int cpu;
268
269         for (cpu = 0; cpu < ncpus2; cpu++) {
270                 lwkt_create(netmsg_service_loop, NULL, NULL,
271                         &udp_thread[cpu], 0, cpu, "udp_thread %d", cpu);
272                 udp_thread[cpu].td_msgport.mp_putport = netmsg_put_port;
273         }
274 }