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