1 /* $NetBSD: npf_state.c,v 1.6 2011/11/29 20:05:30 rmind Exp $ */ 2 3 /*- 4 * Copyright (c) 2010-2011 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This material is based upon work partially supported by The 8 * NetBSD Foundation under a contract with Mindaugas Rasiukevicius. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 /* 33 * NPF state engine to track sessions. 34 */ 35 36 #include <sys/cdefs.h> 37 __KERNEL_RCSID(0, "$NetBSD: npf_state.c,v 1.6 2011/11/29 20:05:30 rmind Exp $"); 38 39 #include <sys/param.h> 40 #include <sys/systm.h> 41 42 #include <sys/mutex.h> 43 44 #include "npf_impl.h" 45 46 /* 47 * Generic session states and timeout table. 48 * 49 * Note: used for connnection-less protocols. 50 */ 51 52 #define NPF_ANY_SESSION_CLOSED 0 53 #define NPF_ANY_SESSION_NEW 1 54 #define NPF_ANY_SESSION_ESTABLISHED 2 55 #define NPF_ANY_SESSION_NSTATES 3 56 57 static const int npf_generic_fsm[NPF_ANY_SESSION_NSTATES][2] __read_mostly = { 58 [NPF_ANY_SESSION_CLOSED] = { 59 [NPF_FLOW_FORW] = NPF_ANY_SESSION_NEW, 60 }, 61 [NPF_ANY_SESSION_NEW] = { 62 [NPF_FLOW_FORW] = NPF_ANY_SESSION_NEW, 63 [NPF_FLOW_BACK] = NPF_ANY_SESSION_ESTABLISHED, 64 }, 65 [NPF_ANY_SESSION_ESTABLISHED] = { 66 [NPF_FLOW_FORW] = NPF_ANY_SESSION_ESTABLISHED, 67 [NPF_FLOW_BACK] = NPF_ANY_SESSION_ESTABLISHED, 68 }, 69 }; 70 71 static const u_int npf_generic_timeout[] __read_mostly = { 72 [NPF_ANY_SESSION_CLOSED] = 0, 73 [NPF_ANY_SESSION_NEW] = 30, 74 [NPF_ANY_SESSION_ESTABLISHED] = 60, 75 }; 76 77 bool 78 npf_state_init(const npf_cache_t *npc, nbuf_t *nbuf, npf_state_t *nst) 79 { 80 const int proto = npf_cache_ipproto(npc); 81 bool ret; 82 83 KASSERT(npf_iscached(npc, NPC_IP46)); 84 KASSERT(npf_iscached(npc, NPC_LAYER4)); 85 86 memset(nst, 0, sizeof(npf_state_t)); 87 mutex_init(&nst->nst_lock, MUTEX_DEFAULT, IPL_SOFTNET); 88 89 switch (proto) { 90 case IPPROTO_TCP: 91 /* Pass to TCP state tracking engine. */ 92 ret = npf_state_tcp(npc, nbuf, nst, NPF_FLOW_FORW); 93 break; 94 case IPPROTO_UDP: 95 case IPPROTO_ICMP: 96 /* Generic. */ 97 nst->nst_state = npf_generic_fsm[nst->nst_state][NPF_FLOW_FORW]; 98 ret = true; 99 break; 100 default: 101 ret = false; 102 } 103 return ret; 104 } 105 106 void 107 npf_state_destroy(npf_state_t *nst) 108 { 109 110 nst->nst_state = 0; 111 mutex_destroy(&nst->nst_lock); 112 } 113 114 bool 115 npf_state_inspect(const npf_cache_t *npc, nbuf_t *nbuf, 116 npf_state_t *nst, const bool forw) 117 { 118 const int proto = npf_cache_ipproto(npc); 119 const int di = forw ? NPF_FLOW_FORW : NPF_FLOW_BACK; 120 bool ret; 121 122 mutex_enter(&nst->nst_lock); 123 switch (proto) { 124 case IPPROTO_TCP: 125 /* Pass to TCP state tracking engine. */ 126 ret = npf_state_tcp(npc, nbuf, nst, di); 127 break; 128 case IPPROTO_UDP: 129 case IPPROTO_ICMP: 130 /* Generic. */ 131 nst->nst_state = npf_generic_fsm[nst->nst_state][di]; 132 ret = true; 133 break; 134 default: 135 ret = false; 136 } 137 mutex_exit(&nst->nst_lock); 138 139 if (__predict_false(!ret)) { 140 npf_stats_inc(NPF_STAT_INVALID_STATE); 141 } 142 return ret; 143 } 144 145 /* 146 * npf_state_etime: return session expiration time according to the state. 147 */ 148 int 149 npf_state_etime(const npf_state_t *nst, const int proto) 150 { 151 const int state = nst->nst_state; 152 int timeout = 0; 153 154 switch (proto) { 155 case IPPROTO_TCP: 156 /* Pass to TCP state tracking engine. */ 157 timeout = npf_state_tcp_timeout(nst); 158 break; 159 case IPPROTO_UDP: 160 case IPPROTO_ICMP: 161 /* Generic. */ 162 timeout = npf_generic_timeout[state]; 163 break; 164 default: 165 KASSERT(false); 166 } 167 return timeout; 168 } 169 170 void 171 npf_state_dump(npf_state_t *nst) 172 { 173 #if defined(DDB) || defined(_NPF_TESTING) 174 npf_tcpstate_t *fst = &nst->nst_tcpst[0], *tst = &nst->nst_tcpst[1]; 175 176 printf("\tstate (%p) %d:\n\t\t" 177 "F { end %u maxend %u mwin %u wscale %u }\n\t\t" 178 "T { end %u maxend %u mwin %u wscale %u }\n", 179 nst, nst->nst_state, 180 fst->nst_end, fst->nst_maxend, fst->nst_maxwin, fst->nst_wscale, 181 tst->nst_end, tst->nst_maxend, tst->nst_maxwin, tst->nst_wscale 182 ); 183 #endif 184 } 185