[CCID3]: Separate most of the packet history code
[linux-2.6] / net / dccp / packet_history.c
1 /*
2  *  net/dccp/packet_history.h
3  *
4  *  Copyright (c) 2005 The University of Waikato, Hamilton, New Zealand.
5  *
6  *  An implementation of the DCCP protocol
7  *
8  *  This code has been developed by the University of Waikato WAND
9  *  research group. For further information please see http://www.wand.net.nz/
10  *  or e-mail Ian McDonald - iam4@cs.waikato.ac.nz
11  *
12  *  This code also uses code from Lulea University, rereleased as GPL by its
13  *  authors:
14  *  Copyright (c) 2003 Nils-Erik Mattsson, Joacim Haggmark, Magnus Erixzon
15  *
16  *  Changes to meet Linux coding standards, to make it meet latest ccid3 draft
17  *  and to make it work as a loadable module in the DCCP stack written by
18  *  Arnaldo Carvalho de Melo <acme@conectiva.com.br>.
19  *
20  *  Copyright (c) 2005 Arnaldo Carvalho de Melo <acme@conectiva.com.br>
21  *
22  *  This program is free software; you can redistribute it and/or modify
23  *  it under the terms of the GNU General Public License as published by
24  *  the Free Software Foundation; either version 2 of the License, or
25  *  (at your option) any later version.
26  *
27  *  This program is distributed in the hope that it will be useful,
28  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
29  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
30  *  GNU General Public License for more details.
31  *
32  *  You should have received a copy of the GNU General Public License
33  *  along with this program; if not, write to the Free Software
34  *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35  */
36
37 #include <linux/config.h>
38 #include <linux/string.h>
39
40 #include "packet_history.h"
41
42 struct dccp_rx_hist *dccp_rx_hist_new(const char *name)
43 {
44         struct dccp_rx_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
45         static const char dccp_rx_hist_mask[] = "rx_hist_%s";
46         char *slab_name;
47
48         if (hist == NULL)
49                 goto out;
50
51         slab_name = kmalloc(strlen(name) + sizeof(dccp_rx_hist_mask) - 1,
52                             GFP_ATOMIC);
53         if (slab_name == NULL)
54                 goto out_free_hist;
55
56         sprintf(slab_name, dccp_rx_hist_mask, name);
57         hist->dccprxh_slab = kmem_cache_create(slab_name,
58                                                sizeof(struct dccp_rx_hist_entry),
59                                                0, SLAB_HWCACHE_ALIGN,
60                                                NULL, NULL);
61         if (hist->dccprxh_slab == NULL)
62                 goto out_free_slab_name;
63 out:
64         return hist;
65 out_free_slab_name:
66         kfree(slab_name);
67 out_free_hist:
68         kfree(hist);
69         hist = NULL;
70         goto out;
71 }
72
73 EXPORT_SYMBOL_GPL(dccp_rx_hist_new);
74
75 void dccp_rx_hist_delete(struct dccp_rx_hist *hist)
76 {
77         const char* name = kmem_cache_name(hist->dccprxh_slab);
78
79         kmem_cache_destroy(hist->dccprxh_slab);
80         kfree(name);
81         kfree(hist);
82 }
83
84 EXPORT_SYMBOL_GPL(dccp_rx_hist_delete);
85
86 void dccp_rx_hist_purge(struct dccp_rx_hist *hist, struct list_head *list)
87 {
88         struct dccp_rx_hist_entry *entry, *next;
89
90         list_for_each_entry_safe(entry, next, list, dccphrx_node) {
91                 list_del_init(&entry->dccphrx_node);
92                 kmem_cache_free(hist->dccprxh_slab, entry);
93         }
94 }
95
96 EXPORT_SYMBOL_GPL(dccp_rx_hist_purge);
97
98 struct dccp_rx_hist_entry *
99                 dccp_rx_hist_find_data_packet(const struct list_head *list)
100 {
101         struct dccp_rx_hist_entry *entry, *packet = NULL;
102
103         list_for_each_entry(entry, list, dccphrx_node)
104                 if (entry->dccphrx_type == DCCP_PKT_DATA ||
105                     entry->dccphrx_type == DCCP_PKT_DATAACK) {
106                         packet = entry;
107                         break;
108                 }
109
110         return packet;
111 }
112
113 EXPORT_SYMBOL_GPL(dccp_rx_hist_find_data_packet);
114
115 struct dccp_tx_hist *dccp_tx_hist_new(const char *name)
116 {
117         struct dccp_tx_hist *hist = kmalloc(sizeof(*hist), GFP_ATOMIC);
118         static const char dccp_tx_hist_mask[] = "tx_hist_%s";
119         char *slab_name;
120
121         if (hist == NULL)
122                 goto out;
123
124         slab_name = kmalloc(strlen(name) + sizeof(dccp_tx_hist_mask) - 1,
125                             GFP_ATOMIC);
126         if (slab_name == NULL)
127                 goto out_free_hist;
128
129         sprintf(slab_name, dccp_tx_hist_mask, name);
130         hist->dccptxh_slab = kmem_cache_create(slab_name,
131                                                sizeof(struct dccp_tx_hist_entry),
132                                                0, SLAB_HWCACHE_ALIGN,
133                                                NULL, NULL);
134         if (hist->dccptxh_slab == NULL)
135                 goto out_free_slab_name;
136 out:
137         return hist;
138 out_free_slab_name:
139         kfree(slab_name);
140 out_free_hist:
141         kfree(hist);
142         hist = NULL;
143         goto out;
144 }
145
146 EXPORT_SYMBOL_GPL(dccp_tx_hist_new);
147
148 void dccp_tx_hist_delete(struct dccp_tx_hist *hist)
149 {
150         const char* name = kmem_cache_name(hist->dccptxh_slab);
151
152         kmem_cache_destroy(hist->dccptxh_slab);
153         kfree(name);
154         kfree(hist);
155 }
156
157 EXPORT_SYMBOL_GPL(dccp_tx_hist_delete);
158
159 struct dccp_tx_hist_entry *dccp_tx_hist_find_entry(const struct list_head *list,
160                                                    const u64 seq)
161 {
162         struct dccp_tx_hist_entry *packet = NULL, *entry;
163
164         list_for_each_entry(entry, list, dccphtx_node)
165                 if (entry->dccphtx_seqno == seq) {
166                         packet = entry;
167                         break;
168                 }
169
170         return packet;
171 }
172
173 EXPORT_SYMBOL_GPL(dccp_tx_hist_find_entry);
174
175 void dccp_tx_hist_purge_older(struct dccp_tx_hist *hist, struct list_head *list,
176                               struct dccp_tx_hist_entry *packet)
177 {
178         struct dccp_tx_hist_entry *next;
179
180         list_for_each_entry_safe_continue(packet, next, list, dccphtx_node) {
181                 list_del_init(&packet->dccphtx_node);
182                 dccp_tx_hist_entry_delete(hist, packet);
183         }
184 }
185
186 EXPORT_SYMBOL_GPL(dccp_tx_hist_purge_older);
187
188 void dccp_tx_hist_purge(struct dccp_tx_hist *hist, struct list_head *list)
189 {
190         struct dccp_tx_hist_entry *entry, *next;
191
192         list_for_each_entry_safe(entry, next, list, dccphtx_node) {
193                 list_del_init(&entry->dccphtx_node);
194                 dccp_tx_hist_entry_delete(hist, entry);
195         }
196 }
197
198 EXPORT_SYMBOL_GPL(dccp_tx_hist_purge);