xref: /dragonfly/sys/netinet/ip_demux.c (revision 8a93af2a)
1bf82f9b7SMatthew Dillon /*
2380d2ea3SJeffrey Hsu  * Copyright (c) 2003, 2004 Jeffrey M. Hsu.  All rights reserved.
3380d2ea3SJeffrey Hsu  * Copyright (c) 2003, 2004 The DragonFly Project.  All rights reserved.
4bf82f9b7SMatthew Dillon  *
5380d2ea3SJeffrey Hsu  * This code is derived from software contributed to The DragonFly Project
6380d2ea3SJeffrey Hsu  * by Jeffrey M. Hsu.
7380d2ea3SJeffrey Hsu  *
8380d2ea3SJeffrey Hsu  * Redistribution and use in source and binary forms, with or without
9380d2ea3SJeffrey Hsu  * modification, are permitted provided that the following conditions
10380d2ea3SJeffrey Hsu  * are met:
11380d2ea3SJeffrey Hsu  * 1. Redistributions of source code must retain the above copyright
12380d2ea3SJeffrey Hsu  *    notice, this list of conditions and the following disclaimer.
13380d2ea3SJeffrey Hsu  * 2. Redistributions in binary form must reproduce the above copyright
14380d2ea3SJeffrey Hsu  *    notice, this list of conditions and the following disclaimer in the
15380d2ea3SJeffrey Hsu  *    documentation and/or other materials provided with the distribution.
16380d2ea3SJeffrey Hsu  * 3. Neither the name of The DragonFly Project nor the names of its
17380d2ea3SJeffrey Hsu  *    contributors may be used to endorse or promote products derived
18380d2ea3SJeffrey Hsu  *    from this software without specific, prior written permission.
19380d2ea3SJeffrey Hsu  *
20380d2ea3SJeffrey Hsu  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21380d2ea3SJeffrey Hsu  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22380d2ea3SJeffrey Hsu  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23380d2ea3SJeffrey Hsu  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
24380d2ea3SJeffrey Hsu  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25380d2ea3SJeffrey Hsu  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
26380d2ea3SJeffrey Hsu  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
27380d2ea3SJeffrey Hsu  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28380d2ea3SJeffrey Hsu  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29380d2ea3SJeffrey Hsu  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30380d2ea3SJeffrey Hsu  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31380d2ea3SJeffrey Hsu  * SUCH DAMAGE.
32bf82f9b7SMatthew Dillon  */
33bf82f9b7SMatthew Dillon 
34bf82f9b7SMatthew Dillon #include "opt_inet.h"
35e99d9a39SSepherosa Ziehau #include "opt_rss.h"
36bf82f9b7SMatthew Dillon 
37bf82f9b7SMatthew Dillon #include <sys/param.h>
38bf82f9b7SMatthew Dillon #include <sys/systm.h>
39bf82f9b7SMatthew Dillon #include <sys/kernel.h>
40bf82f9b7SMatthew Dillon #include <sys/socket.h>
41bf82f9b7SMatthew Dillon #include <sys/socketvar.h>
42bf82f9b7SMatthew Dillon #include <sys/thread.h>
43bf82f9b7SMatthew Dillon #include <sys/sysctl.h>
442b57d013SMatthew Dillon #include <sys/globaldata.h>
45bf82f9b7SMatthew Dillon 
46bf82f9b7SMatthew Dillon #include <net/if.h>
475337421cSSepherosa Ziehau #include <net/netisr2.h>
486d5eef1eSSepherosa Ziehau #include <net/toeplitz2.h>
49bf82f9b7SMatthew Dillon 
50bf82f9b7SMatthew Dillon #include <netinet/in_systm.h>
51bf82f9b7SMatthew Dillon #include <netinet/in.h>
52bf82f9b7SMatthew Dillon #include <netinet/in_var.h>
53bf82f9b7SMatthew Dillon #include <netinet/in_pcb.h>
54bf82f9b7SMatthew Dillon #include <netinet/ip.h>
55bf82f9b7SMatthew Dillon #include <netinet/ip_var.h>
56bf82f9b7SMatthew Dillon #include <netinet/tcp.h>
57bf82f9b7SMatthew Dillon #include <netinet/tcpip.h>
58bf82f9b7SMatthew Dillon #include <netinet/tcp_var.h>
59bf82f9b7SMatthew Dillon #include <netinet/udp.h>
60bf82f9b7SMatthew Dillon #include <netinet/udp_var.h>
61bf82f9b7SMatthew Dillon 
625cbeb1a5SSepherosa Ziehau struct initport_index {
635cbeb1a5SSepherosa Ziehau 	uint32_t	port_index;
645cbeb1a5SSepherosa Ziehau } __cachealign;
655cbeb1a5SSepherosa Ziehau static struct initport_index	initport_indices[MAXCPU];
665cbeb1a5SSepherosa Ziehau 
67c3c96e44SMatthew Dillon /*
68c3c96e44SMatthew Dillon  * Toeplitz hash functions - the idea is to match the hardware.
69c3c96e44SMatthew Dillon  */
70f861aec9SSepherosa Ziehau static __inline int
INP_MPORT_HASH_UDP(in_addr_t faddr,in_addr_t laddr,in_port_t fport,in_port_t lport)71f861aec9SSepherosa Ziehau INP_MPORT_HASH_UDP(in_addr_t faddr, in_addr_t laddr,
72f861aec9SSepherosa Ziehau 		   in_port_t fport, in_port_t lport)
73f861aec9SSepherosa Ziehau {
74e2bf2ed2SSepherosa Ziehau 	/*
75e2bf2ed2SSepherosa Ziehau 	 * NOTE: laddr could be multicast, since UDP socket could be
76e2bf2ed2SSepherosa Ziehau 	 * bound to multicast address.
77e2bf2ed2SSepherosa Ziehau 	 */
78e2bf2ed2SSepherosa Ziehau 	if (IN_MULTICAST(ntohl(faddr)) || IN_MULTICAST(ntohl(laddr))) {
79e2bf2ed2SSepherosa Ziehau 		/* XXX handle multicast on CPU0 for now */
80e2bf2ed2SSepherosa Ziehau 		return 0;
81e2bf2ed2SSepherosa Ziehau 	}
82b73d4152SSepherosa Ziehau 	return toeplitz_hash(toeplitz_rawhash_addr(faddr, laddr));
83f861aec9SSepherosa Ziehau }
84f861aec9SSepherosa Ziehau 
85f861aec9SSepherosa Ziehau static __inline int
INP_MPORT_HASH_TCP(in_addr_t faddr,in_addr_t laddr,in_port_t fport,in_port_t lport)86f861aec9SSepherosa Ziehau INP_MPORT_HASH_TCP(in_addr_t faddr, in_addr_t laddr,
87f861aec9SSepherosa Ziehau 		   in_port_t fport, in_port_t lport)
88f861aec9SSepherosa Ziehau {
89b73d4152SSepherosa Ziehau 	return toeplitz_hash(
90b73d4152SSepherosa Ziehau 	       toeplitz_rawhash_addrport(faddr, laddr, fport, lport));
91f861aec9SSepherosa Ziehau }
92f861aec9SSepherosa Ziehau 
93e9f5b82fSSepherosa Ziehau /*
9476a9ffcaSSepherosa Ziehau  * Hash for the network address.
9576a9ffcaSSepherosa Ziehau  */
9676a9ffcaSSepherosa Ziehau int
tcp_addrhash(in_addr_t faddr,in_port_t fport,in_addr_t laddr,in_port_t lport)9776a9ffcaSSepherosa Ziehau tcp_addrhash(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport)
9876a9ffcaSSepherosa Ziehau {
9976a9ffcaSSepherosa Ziehau 	return (INP_MPORT_HASH_TCP(faddr, laddr, fport, lport));
10076a9ffcaSSepherosa Ziehau }
10176a9ffcaSSepherosa Ziehau 
10276a9ffcaSSepherosa Ziehau int
udp_addrhash(in_addr_t faddr,in_port_t fport,in_addr_t laddr,in_port_t lport)10376a9ffcaSSepherosa Ziehau udp_addrhash(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport)
10476a9ffcaSSepherosa Ziehau {
10576a9ffcaSSepherosa Ziehau 	return (INP_MPORT_HASH_UDP(faddr, laddr, fport, lport));
10676a9ffcaSSepherosa Ziehau }
10776a9ffcaSSepherosa Ziehau 
10876a9ffcaSSepherosa Ziehau /*
109c3c96e44SMatthew Dillon  * Map a network address to a processor.
110c3c96e44SMatthew Dillon  */
111c3c96e44SMatthew Dillon int
tcp_addrcpu(in_addr_t faddr,in_port_t fport,in_addr_t laddr,in_port_t lport)112c3c96e44SMatthew Dillon tcp_addrcpu(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport)
113c3c96e44SMatthew Dillon {
11487561f8fSSepherosa Ziehau 	return (netisr_hashcpu(INP_MPORT_HASH_TCP(faddr, laddr, fport, lport)));
115c3c96e44SMatthew Dillon }
116c3c96e44SMatthew Dillon 
117c3c96e44SMatthew Dillon int
udp_addrcpu(in_addr_t faddr,in_port_t fport,in_addr_t laddr,in_port_t lport)118c3c96e44SMatthew Dillon udp_addrcpu(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport)
119c3c96e44SMatthew Dillon {
1201fe8db06SSepherosa Ziehau 	return (netisr_hashcpu(INP_MPORT_HASH_UDP(faddr, laddr, fport, lport)));
1211fe8db06SSepherosa Ziehau }
1221fe8db06SSepherosa Ziehau 
123c3c96e44SMatthew Dillon /*
124e9f5b82fSSepherosa Ziehau  * If the packet is a valid IP datagram, upon returning of this function
125e9f5b82fSSepherosa Ziehau  * following things are promised:
126e9f5b82fSSepherosa Ziehau  *
127dc6a6a0eSSepherosa Ziehau  * o  IP header (including any possible IP options) and any data preceding
128dc6a6a0eSSepherosa Ziehau  *    IP header (usually linker layer header) are in one mbuf (m_len).
129e9f5b82fSSepherosa Ziehau  * o  IP header length is not less than the minimum (sizeof(struct ip)).
130e9f5b82fSSepherosa Ziehau  * o  IP total length is not less than IP header length.
1319b161cc2SSepherosa Ziehau  * o  IP datagram resides completely in the mbuf chain,
1329b161cc2SSepherosa Ziehau  *    i.e. pkthdr.len >= IP total length.
133e9f5b82fSSepherosa Ziehau  *
134e9f5b82fSSepherosa Ziehau  * If the packet is a UDP datagram,
135e9f5b82fSSepherosa Ziehau  * o  IP header (including any possible IP options) and UDP header are in
136e9f5b82fSSepherosa Ziehau  *    one mbuf (m_len).
137e9f5b82fSSepherosa Ziehau  * o  IP total length is not less than (IP header length + UDP header length).
138e9f5b82fSSepherosa Ziehau  *
139e9f5b82fSSepherosa Ziehau  * If the packet is a TCP segment,
140e9f5b82fSSepherosa Ziehau  * o  IP header (including any possible IP options) and TCP header (including
141e9f5b82fSSepherosa Ziehau  *    any possible TCP options) are in one mbuf (m_len).
142e9f5b82fSSepherosa Ziehau  * o  TCP header length is not less than the minimum (sizeof(struct tcphdr)).
143e9f5b82fSSepherosa Ziehau  * o  IP total length is not less than (IP header length + TCP header length).
144e9f5b82fSSepherosa Ziehau  */
1451e316d14SJeffrey Hsu boolean_t
ip_lengthcheck(struct mbuf ** mp,int hoff)146c3c96e44SMatthew Dillon ip_lengthcheck(struct mbuf **mp, int hoff)
147bf82f9b7SMatthew Dillon {
1481e316d14SJeffrey Hsu 	struct mbuf *m = *mp;
14955d829f8SJeffrey Hsu 	struct ip *ip;
150c3c96e44SMatthew Dillon 	int len, iphlen, iplen;
151bf82f9b7SMatthew Dillon 	struct tcphdr *th;
15255d829f8SJeffrey Hsu 	int thoff;				/* TCP data offset */
153bf82f9b7SMatthew Dillon 
154c3c96e44SMatthew Dillon 	len = hoff + sizeof(struct ip);
155c3c96e44SMatthew Dillon 
156ead1d3cbSJeffrey Hsu 	/* The packet must be at least the size of an IP header. */
157c3c96e44SMatthew Dillon 	if (m->m_pkthdr.len < len) {
15855d829f8SJeffrey Hsu 		ipstat.ips_tooshort++;
159dd4df7e9SSepherosa Ziehau 		goto fail;
16055d829f8SJeffrey Hsu 	}
16155d829f8SJeffrey Hsu 
162ead1d3cbSJeffrey Hsu 	/* The fixed IP header must reside completely in the first mbuf. */
163c3c96e44SMatthew Dillon 	if (m->m_len < len) {
164c3c96e44SMatthew Dillon 		m = m_pullup(m, len);
165ead1d3cbSJeffrey Hsu 		if (m == NULL) {
166bf82f9b7SMatthew Dillon 			ipstat.ips_toosmall++;
167dd4df7e9SSepherosa Ziehau 			goto fail;
168bf82f9b7SMatthew Dillon 		}
169ead1d3cbSJeffrey Hsu 	}
170ead1d3cbSJeffrey Hsu 
171c3c96e44SMatthew Dillon 	ip = mtodoff(m, struct ip *, hoff);
17255d829f8SJeffrey Hsu 
173ead1d3cbSJeffrey Hsu 	/* Bound check the packet's stated IP header length. */
1749eeaa8a9SJeffrey Hsu 	iphlen = ip->ip_hl << 2;
1759babcab8SJeffrey Hsu 	if (iphlen < sizeof(struct ip)) {	/* minimum header length */
1769babcab8SJeffrey Hsu 		ipstat.ips_badhlen++;
177dd4df7e9SSepherosa Ziehau 		goto fail;
1789babcab8SJeffrey Hsu 	}
179ead1d3cbSJeffrey Hsu 
180ead1d3cbSJeffrey Hsu 	/* The full IP header must reside completely in the one mbuf. */
181c3c96e44SMatthew Dillon 	if (m->m_len < hoff + iphlen) {
182c3c96e44SMatthew Dillon 		m = m_pullup(m, hoff + iphlen);
183b01ae44aSMatthew Dillon 		if (m == NULL) {
184b01ae44aSMatthew Dillon 			ipstat.ips_badhlen++;
185dd4df7e9SSepherosa Ziehau 			goto fail;
186b01ae44aSMatthew Dillon 		}
187c3c96e44SMatthew Dillon 		ip = mtodoff(m, struct ip *, hoff);
188b01ae44aSMatthew Dillon 	}
189b01ae44aSMatthew Dillon 
190ead1d3cbSJeffrey Hsu 	iplen = ntohs(ip->ip_len);
191ead1d3cbSJeffrey Hsu 
192ead1d3cbSJeffrey Hsu 	/*
1939b161cc2SSepherosa Ziehau 	 * Check that the amount of data in the buffers is as
1949b161cc2SSepherosa Ziehau 	 * at least much as the IP header would have us expect.
1959b161cc2SSepherosa Ziehau 	 */
196c3c96e44SMatthew Dillon 	if (m->m_pkthdr.len < hoff + iplen) {
1979b161cc2SSepherosa Ziehau 		ipstat.ips_tooshort++;
1989b161cc2SSepherosa Ziehau 		goto fail;
1999b161cc2SSepherosa Ziehau 	}
2009b161cc2SSepherosa Ziehau 
2019b161cc2SSepherosa Ziehau 	/*
202ead1d3cbSJeffrey Hsu 	 * Fragments other than the first fragment don't have much
203ead1d3cbSJeffrey Hsu 	 * length information.
204ead1d3cbSJeffrey Hsu 	 */
205*8a93af2aSMatthew Dillon 	if (ip->ip_off & htons(IP_OFFMASK))
206ead1d3cbSJeffrey Hsu 		goto ipcheckonly;
207ead1d3cbSJeffrey Hsu 
208b01ae44aSMatthew Dillon 	/*
209b01ae44aSMatthew Dillon 	 * The TCP/IP or UDP/IP header must be entirely contained within
210b01ae44aSMatthew Dillon 	 * the first fragment of a packet.  Packet filters will break if they
211b01ae44aSMatthew Dillon 	 * aren't.
212ee7990a0SMatthew Dillon 	 *
213ee7990a0SMatthew Dillon 	 * Since the packet will be trimmed to ip_len we must also make sure
214ee7990a0SMatthew Dillon 	 * the potentially trimmed down length is still sufficient to hold
215ee7990a0SMatthew Dillon 	 * the header(s).
216b01ae44aSMatthew Dillon 	 */
217b01ae44aSMatthew Dillon 	switch (ip->ip_p) {
218b01ae44aSMatthew Dillon 	case IPPROTO_TCP:
219ee7990a0SMatthew Dillon 		if (iplen < iphlen + sizeof(struct tcphdr)) {
220ee7990a0SMatthew Dillon 			++tcpstat.tcps_rcvshort;
221dd4df7e9SSepherosa Ziehau 			goto fail;
222ee7990a0SMatthew Dillon 		}
223c3c96e44SMatthew Dillon 		if (m->m_len < hoff + iphlen + sizeof(struct tcphdr)) {
224c3c96e44SMatthew Dillon 			m = m_pullup(m, hoff + iphlen + sizeof(struct tcphdr));
225b01ae44aSMatthew Dillon 			if (m == NULL) {
226b01ae44aSMatthew Dillon 				tcpstat.tcps_rcvshort++;
227dd4df7e9SSepherosa Ziehau 				goto fail;
228b01ae44aSMatthew Dillon 			}
229c3c96e44SMatthew Dillon 			ip = mtodoff(m, struct ip *, hoff);
230b01ae44aSMatthew Dillon 		}
2319eeaa8a9SJeffrey Hsu 		th = (struct tcphdr *)((caddr_t)ip + iphlen);
23255d829f8SJeffrey Hsu 		thoff = th->th_off << 2;
233096deca3SJeffrey Hsu 		if (thoff < sizeof(struct tcphdr) ||
234cd5e5855SMatthew Dillon 		    thoff + iphlen > ntohs(ip->ip_len)) {
2359eeaa8a9SJeffrey Hsu 			tcpstat.tcps_rcvbadoff++;
236dd4df7e9SSepherosa Ziehau 			goto fail;
2379eeaa8a9SJeffrey Hsu 		}
238c3c96e44SMatthew Dillon 		if (m->m_len < hoff + iphlen + thoff) {
239c3c96e44SMatthew Dillon 			m = m_pullup(m, hoff + iphlen + thoff);
2409eeaa8a9SJeffrey Hsu 			if (m == NULL) {
2419eeaa8a9SJeffrey Hsu 				tcpstat.tcps_rcvshort++;
242dd4df7e9SSepherosa Ziehau 				goto fail;
2431e316d14SJeffrey Hsu 			}
2441e316d14SJeffrey Hsu 		}
2451e316d14SJeffrey Hsu 		break;
246ead1d3cbSJeffrey Hsu 	case IPPROTO_UDP:
247ead1d3cbSJeffrey Hsu 		if (iplen < iphlen + sizeof(struct udphdr)) {
2486e78e7feSSepherosa Ziehau 			++udp_stat.udps_hdrops;
249dd4df7e9SSepherosa Ziehau 			goto fail;
250ead1d3cbSJeffrey Hsu 		}
251c3c96e44SMatthew Dillon 		if (m->m_len < hoff + iphlen + sizeof(struct udphdr)) {
252c3c96e44SMatthew Dillon 			m = m_pullup(m, hoff + iphlen + sizeof(struct udphdr));
253ead1d3cbSJeffrey Hsu 			if (m == NULL) {
2546e78e7feSSepherosa Ziehau 				udp_stat.udps_hdrops++;
255dd4df7e9SSepherosa Ziehau 				goto fail;
256ead1d3cbSJeffrey Hsu 			}
257ead1d3cbSJeffrey Hsu 		}
258ead1d3cbSJeffrey Hsu 		break;
259ead1d3cbSJeffrey Hsu 	default:
260ead1d3cbSJeffrey Hsu ipcheckonly:
261ead1d3cbSJeffrey Hsu 		if (iplen < iphlen) {
262ead1d3cbSJeffrey Hsu 			++ipstat.ips_badlen;
263dd4df7e9SSepherosa Ziehau 			goto fail;
264ead1d3cbSJeffrey Hsu 		}
265ead1d3cbSJeffrey Hsu 		break;
2661e316d14SJeffrey Hsu 	}
2671e316d14SJeffrey Hsu 
2688697599bSSepherosa Ziehau 	m->m_flags |= M_LENCHECKED;
2691e316d14SJeffrey Hsu 	*mp = m;
2701e316d14SJeffrey Hsu 	return TRUE;
271dd4df7e9SSepherosa Ziehau 
272dd4df7e9SSepherosa Ziehau fail:
273dd4df7e9SSepherosa Ziehau 	if (m != NULL)
274dd4df7e9SSepherosa Ziehau 		m_freem(m);
275dd4df7e9SSepherosa Ziehau 	*mp = NULL;
276dd4df7e9SSepherosa Ziehau 	return FALSE;
2771e316d14SJeffrey Hsu }
2781e316d14SJeffrey Hsu 
2791e316d14SJeffrey Hsu /*
280c3c96e44SMatthew Dillon  * Assign a protocol processing thread to a packet.  The IP header is at
281c3c96e44SMatthew Dillon  * offset (hoff) in the packet (i.e. the mac header might still be intact).
282c3c96e44SMatthew Dillon  *
283c3c96e44SMatthew Dillon  * This function can blow away the mbuf if the packet is malformed.
2841e316d14SJeffrey Hsu  */
285c3c96e44SMatthew Dillon void
ip_hashfn(struct mbuf ** mptr,int hoff)286b6615c82SSepherosa Ziehau ip_hashfn(struct mbuf **mptr, int hoff)
2871e316d14SJeffrey Hsu {
2881e316d14SJeffrey Hsu 	struct ip *ip;
2891e316d14SJeffrey Hsu 	int iphlen;
2901e316d14SJeffrey Hsu 	struct tcphdr *th;
2911e316d14SJeffrey Hsu 	struct udphdr *uh;
2921e316d14SJeffrey Hsu 	struct mbuf *m;
29387561f8fSSepherosa Ziehau 	int hash;
2941e316d14SJeffrey Hsu 
295be0bea4aSSepherosa Ziehau 	if (((*mptr)->m_flags & M_LENCHECKED) == 0) {
296c3c96e44SMatthew Dillon 		if (!ip_lengthcheck(mptr, hoff))
297c3c96e44SMatthew Dillon 			return;
298be0bea4aSSepherosa Ziehau 	}
299bf82f9b7SMatthew Dillon 
3001e316d14SJeffrey Hsu 	m = *mptr;
301c3c96e44SMatthew Dillon 	ip = mtodoff(m, struct ip *, hoff);
3021e316d14SJeffrey Hsu 	iphlen = ip->ip_hl << 2;
3031e316d14SJeffrey Hsu 
304*8a93af2aSMatthew Dillon 	if (ip->ip_off & htons(IP_MF | IP_OFFMASK)) {
305aecff6d1SMatthew Dillon 		hash = toeplitz_hash(toeplitz_rawhash_addr(
306aecff6d1SMatthew Dillon 			    ip->ip_src.s_addr, ip->ip_dst.s_addr));
30797a43e72SSepherosa Ziehau 		goto back;
30897a43e72SSepherosa Ziehau 	}
3091e316d14SJeffrey Hsu 
3101e316d14SJeffrey Hsu 	switch (ip->ip_p) {
3111e316d14SJeffrey Hsu 	case IPPROTO_TCP:
3121e316d14SJeffrey Hsu 		th = (struct tcphdr *)((caddr_t)ip + iphlen);
31387561f8fSSepherosa Ziehau 		hash = INP_MPORT_HASH_TCP(ip->ip_src.s_addr, ip->ip_dst.s_addr,
31487561f8fSSepherosa Ziehau 		    th->th_sport, th->th_dport);
315bf82f9b7SMatthew Dillon 		break;
316f861aec9SSepherosa Ziehau 
317bf82f9b7SMatthew Dillon 	case IPPROTO_UDP:
3189eeaa8a9SJeffrey Hsu 		uh = (struct udphdr *)((caddr_t)ip + iphlen);
31987561f8fSSepherosa Ziehau 		hash = INP_MPORT_HASH_UDP(ip->ip_src.s_addr, ip->ip_dst.s_addr,
32087561f8fSSepherosa Ziehau 		    uh->uh_sport, uh->uh_dport);
321bf82f9b7SMatthew Dillon 		break;
322f861aec9SSepherosa Ziehau 
323bf82f9b7SMatthew Dillon 	default:
32487561f8fSSepherosa Ziehau 		hash = 0;
325bf82f9b7SMatthew Dillon 		break;
326bf82f9b7SMatthew Dillon 	}
32797a43e72SSepherosa Ziehau back:
3287558541bSSepherosa Ziehau 	m_sethash(m, hash);
329bf82f9b7SMatthew Dillon }
330bf82f9b7SMatthew Dillon 
3319eeaa8a9SJeffrey Hsu /*
332e6f77b88SSepherosa Ziehau  * Verify and adjust the hash value of the packet.
333e6f77b88SSepherosa Ziehau  *
334ca86d83eSSepherosa Ziehau  * Unlike ip_hashfn(), the packet content is not accessed.  The packet info
335e6f77b88SSepherosa Ziehau  * (pi) and the hash of the packet (m_pkthdr.hash) is used instead.
3368a5c0ed6SSepherosa Ziehau  *
3378a5c0ed6SSepherosa Ziehau  * Caller has already made sure that m_pkthdr.hash is valid, i.e. m_flags
3388a5c0ed6SSepherosa Ziehau  * has M_HASH set.
3398a5c0ed6SSepherosa Ziehau  */
340e6f77b88SSepherosa Ziehau void
ip_hashcheck(struct mbuf * m,const struct pktinfo * pi)341e6f77b88SSepherosa Ziehau ip_hashcheck(struct mbuf *m, const struct pktinfo *pi)
3428a5c0ed6SSepherosa Ziehau {
343ed20d0e3SSascha Wildner 	KASSERT((m->m_flags & M_HASH), ("no valid packet hash"));
3448a5c0ed6SSepherosa Ziehau 
3458a5c0ed6SSepherosa Ziehau 	switch (pi->pi_l3proto) {
3468a5c0ed6SSepherosa Ziehau 	case IPPROTO_TCP:
3478a5c0ed6SSepherosa Ziehau 	case IPPROTO_UDP:
3488a5c0ed6SSepherosa Ziehau 		break;
3498a5c0ed6SSepherosa Ziehau 
3508a5c0ed6SSepherosa Ziehau 	default:
351e6f77b88SSepherosa Ziehau 		/* Let software calculate the hash */
352e6f77b88SSepherosa Ziehau 		m->m_flags &= ~M_HASH;
3538a5c0ed6SSepherosa Ziehau 		break;
3548a5c0ed6SSepherosa Ziehau 	}
3558a5c0ed6SSepherosa Ziehau }
3568a5c0ed6SSepherosa Ziehau 
3578a5c0ed6SSepherosa Ziehau /*
35848e7b118SMatthew Dillon  * This is used to map a socket to a message port for sendmsg() and friends.
35948e7b118SMatthew Dillon  * It is not called for any other purpose.  In the case of TCP we just return
36048e7b118SMatthew Dillon  * the port already installed in the socket.
3619eeaa8a9SJeffrey Hsu  */
36248e7b118SMatthew Dillon lwkt_port_t
tcp_soport(struct socket * so,struct sockaddr * nam,struct mbuf ** dummy __unused)36348e7b118SMatthew Dillon tcp_soport(struct socket *so, struct sockaddr *nam,
36448e7b118SMatthew Dillon 	   struct mbuf **dummy __unused)
36548e7b118SMatthew Dillon {
36648e7b118SMatthew Dillon 	return(so->so_port);
367bf82f9b7SMatthew Dillon }
368bf82f9b7SMatthew Dillon 
369e3873585SSepherosa Ziehau /*
370e3873585SSepherosa Ziehau  * Used to route icmp messages to the proper protocol thread for ctlinput
371e3873585SSepherosa Ziehau  * operation.
372e3873585SSepherosa Ziehau  */
373e3873585SSepherosa Ziehau lwkt_port_t
tcp_ctlport(int cmd,struct sockaddr * sa,void * vip,int * cpuid)374130b7902SSepherosa Ziehau tcp_ctlport(int cmd, struct sockaddr *sa, void *vip, int *cpuid)
375e3873585SSepherosa Ziehau {
376e3873585SSepherosa Ziehau 	struct ip *ip = vip;
377ffb15150SSepherosa Ziehau 	inp_notify_t notify;
378130b7902SSepherosa Ziehau 	int arg;
379e3873585SSepherosa Ziehau 
380130b7902SSepherosa Ziehau 	notify = tcp_get_inpnotify(cmd, sa, &arg, &ip, cpuid);
381ffb15150SSepherosa Ziehau 	if (notify == NULL)
382ffb15150SSepherosa Ziehau 		return NULL;
383ffb15150SSepherosa Ziehau 
38443dbcc2aSSepherosa Ziehau 	if (*cpuid == netisr_ncpus) {
38514572273SSepherosa Ziehau 		/*
38643dbcc2aSSepherosa Ziehau 		 * Go through all effective netisr CPUs.
387ffb15150SSepherosa Ziehau 		 *
3888e0ec33bSSepherosa Ziehau 		 * A new message will be allocated later to save necessary
3898e0ec33bSSepherosa Ziehau 		 * information and will be forwarded to all network protocol
3908e0ec33bSSepherosa Ziehau 		 * threads in the following way:
39114572273SSepherosa Ziehau 		 *
3928e0ec33bSSepherosa Ziehau 		 * (the the thread owns the msgport that we return here)
3938e0ec33bSSepherosa Ziehau 		 * netisr0 <--+
39414572273SSepherosa Ziehau 		 *    |       |
39514572273SSepherosa Ziehau 		 *    |       |
3968e0ec33bSSepherosa Ziehau 		 *    |       |
3978e0ec33bSSepherosa Ziehau 		 *    +-------+
3988e0ec33bSSepherosa Ziehau 		 *     sendmsg
3998e0ec33bSSepherosa Ziehau 		 *     [msg is kmalloc()ed]
4008e0ec33bSSepherosa Ziehau 		 *
4018e0ec33bSSepherosa Ziehau 		 *
4028e0ec33bSSepherosa Ziehau 		 * Later on, when the msg is received by netisr0:
4038e0ec33bSSepherosa Ziehau 		 *
4048e0ec33bSSepherosa Ziehau 		 *         forwardmsg         forwardmsg
4058e0ec33bSSepherosa Ziehau 		 * netisr0 ---------> netisr1 ---------> netisrN
4068e0ec33bSSepherosa Ziehau 		 *                                       [msg is kfree()ed]
40714572273SSepherosa Ziehau 		 */
408130b7902SSepherosa Ziehau 		return netisr_cpuport(0);
409e3873585SSepherosa Ziehau 	} else {
410130b7902SSepherosa Ziehau 		return netisr_cpuport(*cpuid);
411e3873585SSepherosa Ziehau 	}
412e3873585SSepherosa Ziehau }
413e3873585SSepherosa Ziehau 
4147fe56515SJeffrey Hsu lwkt_port_t
tcp_addrport(in_addr_t faddr,in_port_t fport,in_addr_t laddr,in_port_t lport)4157fe56515SJeffrey Hsu tcp_addrport(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport)
4167fe56515SJeffrey Hsu {
417ec7f7fc8SSepherosa Ziehau 	return(netisr_cpuport(tcp_addrcpu(faddr, fport, laddr, lport)));
4187fe56515SJeffrey Hsu }
4197fe56515SJeffrey Hsu 
42065f3e756SMatthew Dillon lwkt_port_t
tcp_addrport0(void)42165f3e756SMatthew Dillon tcp_addrport0(void)
42265f3e756SMatthew Dillon {
423ec7f7fc8SSepherosa Ziehau 	return(netisr_cpuport(0));
42465f3e756SMatthew Dillon }
42565f3e756SMatthew Dillon 
42648e7b118SMatthew Dillon lwkt_port_t
udp_addrport(in_addr_t faddr,in_port_t fport,in_addr_t laddr,in_port_t lport)42748e7b118SMatthew Dillon udp_addrport(in_addr_t faddr, in_port_t fport, in_addr_t laddr, in_port_t lport)
42848e7b118SMatthew Dillon {
429ec7f7fc8SSepherosa Ziehau 	return(netisr_cpuport(udp_addrcpu(faddr, fport, laddr, lport)));
43048e7b118SMatthew Dillon }
43148e7b118SMatthew Dillon 
4329eeaa8a9SJeffrey Hsu /*
433e3873585SSepherosa Ziehau  * Used to route icmp messages to the proper protocol thread for ctlinput
434e3873585SSepherosa Ziehau  * operation.
435e3873585SSepherosa Ziehau  */
436e3873585SSepherosa Ziehau lwkt_port_t
udp_ctlport(int cmd,struct sockaddr * sa,void * vip,int * cpuid)437130b7902SSepherosa Ziehau udp_ctlport(int cmd, struct sockaddr *sa, void *vip, int *cpuid)
438e3873585SSepherosa Ziehau {
439e3873585SSepherosa Ziehau 	struct ip *ip = vip;
440dfa15443SSepherosa Ziehau 	inp_notify_t notify;
441e3873585SSepherosa Ziehau 
442130b7902SSepherosa Ziehau 	notify = udp_get_inpnotify(cmd, sa, &ip, cpuid);
443dfa15443SSepherosa Ziehau 	if (notify == NULL)
444dfa15443SSepherosa Ziehau 		return NULL;
445dfa15443SSepherosa Ziehau 
44643dbcc2aSSepherosa Ziehau 	if (*cpuid == netisr_ncpus) {
44714572273SSepherosa Ziehau 		/*
44843dbcc2aSSepherosa Ziehau 		 * Go through all effective netisr CPUs.
449dfa15443SSepherosa Ziehau 		 *
450c8d29187SSepherosa Ziehau 		 * See the comment in tcp_ctlport.
45114572273SSepherosa Ziehau 		 */
452130b7902SSepherosa Ziehau 		return netisr_cpuport(0);
453e3873585SSepherosa Ziehau 	} else {
454130b7902SSepherosa Ziehau 		return netisr_cpuport(*cpuid);
455e3873585SSepherosa Ziehau 	}
456bf82f9b7SMatthew Dillon }
457ee0be9caSSepherosa Ziehau 
4585cbeb1a5SSepherosa Ziehau static __inline struct lwkt_port *
inp_initport(void)459bb36fa2fSSepherosa Ziehau inp_initport(void)
4605cbeb1a5SSepherosa Ziehau {
4615cbeb1a5SSepherosa Ziehau 	int cpu = mycpuid;
4625cbeb1a5SSepherosa Ziehau 
463bb36fa2fSSepherosa Ziehau 	if (cpu < netisr_ncpus) {
4645cbeb1a5SSepherosa Ziehau 		return netisr_cpuport(cpu);
4655cbeb1a5SSepherosa Ziehau 	} else {
4665cbeb1a5SSepherosa Ziehau 		return netisr_cpuport(
467bb36fa2fSSepherosa Ziehau 		    ((initport_indices[cpu].port_index++) + (uint32_t)cpu) %
468bb36fa2fSSepherosa Ziehau 		    netisr_ncpus);
4695cbeb1a5SSepherosa Ziehau 	}
4705cbeb1a5SSepherosa Ziehau }
4715cbeb1a5SSepherosa Ziehau 
472ee0be9caSSepherosa Ziehau struct lwkt_port *
tcp_initport(void)473ee0be9caSSepherosa Ziehau tcp_initport(void)
474ee0be9caSSepherosa Ziehau {
475bb36fa2fSSepherosa Ziehau 	return inp_initport();
476ee0be9caSSepherosa Ziehau }
477be4519a2SSepherosa Ziehau 
478be4519a2SSepherosa Ziehau struct lwkt_port *
udp_initport(void)479be4519a2SSepherosa Ziehau udp_initport(void)
480be4519a2SSepherosa Ziehau {
481bb36fa2fSSepherosa Ziehau 	return inp_initport();
482be4519a2SSepherosa Ziehau }
483