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