1 /* Copyright (C) 2007-2012 Open Information Security Foundation
2 *
3 * You can copy, redistribute or modify this Program under the terms of
4 * the GNU General Public License version 2 as published by the Free
5 * Software Foundation.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * version 2 along with this program; if not, write to the Free Software
14 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
15 * 02110-1301, USA.
16 */
17
18 /**
19 * \file
20 *
21 * \author Victor Julien <victor@inliniac.net>
22 */
23
24 #include "suricata-common.h"
25 #include "defrag.h"
26 #include "defrag-hash.h"
27 #include "defrag-timeout.h"
28
29 /** \internal
30 * \brief See if we can really discard this tracker. Check use_cnt reference.
31 *
32 * \param dt tracker
33 * \param ts timestamp
34 *
35 * \retval 0 not timed out just yet
36 * \retval 1 fully timed out, lets kill it
37 */
DefragTrackerTimedOut(DefragTracker * dt,struct timeval * ts)38 static int DefragTrackerTimedOut(DefragTracker *dt, struct timeval *ts)
39 {
40 /** never prune a trackers that is used by a packet
41 * we are currently processing in one of the threads */
42 if (SC_ATOMIC_GET(dt->use_cnt) > 0) {
43 return 0;
44 }
45
46 /* retain if remove is not set and not timed out */
47 if (!dt->remove && timercmp(&dt->timeout, ts, >))
48 return 0;
49
50 return 1;
51 }
52
53 /**
54 * \internal
55 *
56 * \brief check all trackers in a hash row for timing out
57 *
58 * \param hb tracker hash row *LOCKED*
59 * \param dt last tracker in the hash row
60 * \param ts timestamp
61 *
62 * \retval cnt timed out tracker
63 */
DefragTrackerHashRowTimeout(DefragTrackerHashRow * hb,DefragTracker * dt,struct timeval * ts)64 static uint32_t DefragTrackerHashRowTimeout(DefragTrackerHashRow *hb, DefragTracker *dt, struct timeval *ts)
65 {
66 uint32_t cnt = 0;
67
68 do {
69 if (SCMutexTrylock(&dt->lock) != 0) {
70 dt = dt->hprev;
71 continue;
72 }
73
74 DefragTracker *next_dt = dt->hprev;
75
76 /* check if the tracker is fully timed out and
77 * ready to be discarded. */
78 if (DefragTrackerTimedOut(dt, ts) == 1) {
79 /* remove from the hash */
80 if (dt->hprev != NULL)
81 dt->hprev->hnext = dt->hnext;
82 if (dt->hnext != NULL)
83 dt->hnext->hprev = dt->hprev;
84 if (hb->head == dt)
85 hb->head = dt->hnext;
86 if (hb->tail == dt)
87 hb->tail = dt->hprev;
88
89 dt->hnext = NULL;
90 dt->hprev = NULL;
91
92 DefragTrackerClearMemory(dt);
93
94 /* no one is referring to this tracker, use_cnt 0, removed from hash
95 * so we can unlock it and move it back to the spare queue. */
96 SCMutexUnlock(&dt->lock);
97
98 /* move to spare list */
99 DefragTrackerMoveToSpare(dt);
100
101 cnt++;
102 } else {
103 SCMutexUnlock(&dt->lock);
104 }
105
106 dt = next_dt;
107 } while (dt != NULL);
108
109 return cnt;
110 }
111
112 /**
113 * \brief time out tracker from the hash
114 *
115 * \param ts timestamp
116 *
117 * \retval cnt number of timed out tracker
118 */
DefragTimeoutHash(struct timeval * ts)119 uint32_t DefragTimeoutHash(struct timeval *ts)
120 {
121 uint32_t idx = 0;
122 uint32_t cnt = 0;
123
124 for (idx = 0; idx < defrag_config.hash_size; idx++) {
125 DefragTrackerHashRow *hb = &defragtracker_hash[idx];
126
127 if (DRLOCK_TRYLOCK(hb) != 0)
128 continue;
129
130 /* defrag hash bucket is now locked */
131
132 if (hb->tail == NULL) {
133 DRLOCK_UNLOCK(hb);
134 continue;
135 }
136
137 /* we have a tracker, or more than one */
138 cnt += DefragTrackerHashRowTimeout(hb, hb->tail, ts);
139 DRLOCK_UNLOCK(hb);
140 }
141
142 return cnt;
143 }
144
145