3 Copyright 2002 Broadcom Corp. All Rights Reserved.
5 This program is free software; you can distribute it and/or modify it
6 under the terms of the GNU General Public License (Version 2) as
7 published by the Free Software Foundation.
9 This program is distributed in the hope it will be useful, but WITHOUT
10 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
19 /******************************************************************************
21 // Filename: ip_conntrack_proto_esp.c
22 // Author: Pavan Kumar
23 // Creation Date: 05/27/04
26 // Implements the ESP ALG connectiontracking.
28 *****************************************************************************/
29 #include <linux/types.h>
30 #include <linux/sched.h>
31 #include <linux/timer.h>
32 #include <linux/netfilter.h>
34 #ifdef CONFIG_MIPS_BRCM
37 #include <linux/netfilter_ipv4/ip_conntrack_protocol.h>
38 #include <linux/netfilter_ipv4/ip_conntrack_esp.h>
40 #define ESP_TIMEOUT (30*HZ)
41 #define ESP_STREAM_TIMEOUT (180*HZ)
43 #ifdef CONFIG_MIPS_BRCM
44 #define ESP_UNREPLIEDDNS_TIMEOUT (1*HZ)
50 #define TEMP_SPI_START 1500
62 static struct _esp_table esp_table[MAX_PORTS];
65 #define DEBUGP(format, args...) printk(__FILE__ ":" __FUNCTION__ ": " \
68 #define DEBUGP(format, args...)
71 static u_int16_t cur_spi = 0;
74 * Allocate a free IPSEC table entry.
76 struct _esp_table *alloc_esp_entry ( void )
79 struct _esp_table *esp_entry = esp_table;
81 for ( ; idx < MAX_PORTS; idx++ ) {
82 if ( esp_entry->inuse == IPSEC_FREE ) {
83 esp_entry->tspi = cur_spi = TEMP_SPI_START + idx;
84 esp_entry->inuse = IPSEC_INUSE;
85 //printk ( KERN_DEBUG "%s:%s New esp_entry at idx %d entry %p"
86 // " tspi %u cspi %u\n", __FILE__, __FUNCTION__, idx,
87 // esp_entry, esp_entry->tspi, cur_spi );
96 * Search an ESP table entry by the Security Parameter Identifier (SPI).
98 struct _esp_table *search_esp_entry_by_spi ( const struct esphdr *esph,
102 struct _esp_table *esp_entry = esp_table;
104 //printk ( KERN_DEBUG "%s:%s (0x%x) %u.%u.%u.%u\n", __FILE__, __FUNCTION__,
105 // ntohl(esph->spi), NIPQUAD(daddr));
106 for ( ; idx < MAX_PORTS; idx++, esp_entry++ ) {
107 if ( esp_entry->inuse == IPSEC_FREE ) {
110 /* If we have seen traffic both ways */
111 if ( esp_entry->l_spi != 0 && esp_entry->r_spi != 0 ) {
112 if ( esp_entry->l_spi == ntohl(esph->spi) ||
113 esp_entry->r_spi == ntohl(esph->spi) ) {
118 /* If we have seen traffic only one way */
119 if ( esp_entry->l_spi == 0 || esp_entry->r_spi == 0 ) {
120 /* We have traffic from local */
121 if ( esp_entry->l_spi ) {
122 if ( ntohl(esph->spi) == esp_entry->l_spi ) {
125 /* This must be the first packet from remote */
126 esp_entry->r_spi = ntohl(esph->spi);
127 esp_entry->r_ip = ntohl(daddr);
129 /* We have seen traffic only from remote */
130 } else if ( esp_entry->r_spi ) {
131 if ( ntohl(esph->spi) == esp_entry->r_spi ) {
134 /* This must be the first packet from local */
135 esp_entry->l_spi = ntohl(esph->spi);
143 static int esp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
144 struct ip_conntrack_tuple *tuple)
147 struct _esp_table *esp_entry;
149 if (skb_copy_bits(skb, dataoff, &esph, sizeof(esph)) != 0)
151 //printk ( KERN_DEBUG "%s:%s (0x%x) IP Pkt Hdr %u.%u.%u.%u <-> %u.%u.%u.%u\n",
152 // __FILE__, __FUNCTION__, ntohl(esph.spi),
153 // NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
154 //printk ( KERN_DEBUG "%s:%s (0x%x) %u.%u.%u.%u <-> %u.%u.%u.%u\n",
155 // __FILE__, __FUNCTION__, ntohl(esph.spi),
156 // NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip) );
158 if ( (esp_entry = search_esp_entry_by_spi ( &esph, tuple->dst.ip ) ) == NULL ) {
159 esp_entry = alloc_esp_entry();
160 if ( esp_entry == NULL ) {
163 esp_entry->l_spi = ntohl(esph.spi);
164 esp_entry->l_ip = ntohl(tuple->src.ip);
166 //printk ( KERN_DEBUG "%s:%s tspi %u cspi %u spi 0x%x seq 0x%x"
167 // " sip %u.%u.%u.%u dip %u.%u.%u.%u\n", __FILE__,
168 // __FUNCTION__, esp_entry->tspi, cur_spi,
169 // ntohl(esph.spi), ntohl(esph.seq),
170 // NIPQUAD(tuple->src.ip), NIPQUAD(tuple->dst.ip) );
171 tuple->dst.u.esp.spi = esp_entry->tspi;
172 tuple->src.u.esp.spi = esp_entry->tspi;
176 static int esp_invert_tuple(struct ip_conntrack_tuple *tuple,
177 const struct ip_conntrack_tuple *orig)
179 //printk ( KERN_DEBUG "%s:%s cspi 0x%x dspi 0x%x sspi 0x%x"
180 // " %u.%u.%u.%u <-> %u.%u.%u.%u\n",
181 // __FILE__, __FUNCTION__, cur_spi, orig->dst.u.esp.spi,
182 // orig->src.u.esp.spi, NIPQUAD(tuple->src.ip),
183 // NIPQUAD(tuple->dst.ip) );
184 tuple->src.u.esp.spi = orig->dst.u.esp.spi;
185 tuple->dst.u.esp.spi = orig->src.u.esp.spi;
189 /* Print out the per-protocol part of the tuple. */
190 static unsigned int esp_print_tuple(char *buffer,
191 const struct ip_conntrack_tuple *tuple)
193 return sprintf(buffer, "sport=%u dport=%u ",
194 ntohs(tuple->src.u.esp.spi), ntohs(tuple->dst.u.esp.spi));
197 /* Print out the private part of the conntrack. */
198 static unsigned int esp_print_conntrack(char *buffer,
199 const struct ip_conntrack *conntrack)
204 /* Returns verdict for packet, and may modify conntracktype */
205 static int esp_packet(struct ip_conntrack *conntrack,
206 const struct sk_buff *skb,
207 enum ip_conntrack_info conntrackinfo)
209 const struct iphdr *iph = skb->nh.iph;
210 const struct esphdr *esph = (void *)iph + iph->ihl*4;
211 struct _esp_table *esp_entry;
213 //printk ( KERN_DEBUG "%s:%s (0x%x) %u.%u.%u.%u <-> %u.%u.%u.%u %s\n",
214 // __FILE__, __FUNCTION__, ntohl(esph->spi),
215 // NIPQUAD(iph->saddr), NIPQUAD(iph->daddr),
216 // (conntrackinfo == IP_CT_NEW ) ? "CT_NEW" : "SEEN_REPLY" );
218 * This should not happen. We get into this routine only if there is
219 * an existing stream.
221 if (conntrackinfo == IP_CT_NEW ) {
222 //printk ( KERN_DEBUG "%s:%s IP_CT_NEW (0x%x) %u.%u.%u.%u <-> %u.%u.%u.%u\n",
223 // __FILE__, __FUNCTION__, esph->spi, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
224 if ( (esp_entry = search_esp_entry_by_spi ( esph,
225 iph->daddr ) ) == NULL ) {
226 esp_entry = alloc_esp_entry ();
227 if ( esp_entry == NULL ) {
228 /* All entries are currently in use */
229 //printk ( KERN_DEBUG "%s:%s All connections in use\n",
230 // __FILE__, __FUNCTION__);
233 esp_entry->l_spi = ntohl(esph->spi);
234 esp_entry->l_ip = ntohl(iph->saddr);
235 esp_entry->r_spi = 0;
238 /* If we've seen traffic both ways, this is some kind of UDP
239 stream. Extend timeout. */
240 if (conntrack->status & IPS_SEEN_REPLY) {
241 ip_ct_refresh(conntrack, ESP_STREAM_TIMEOUT);
242 /* Also, more likely to be important, and not a probe */
243 set_bit(IPS_ASSURED_BIT, &conntrack->status);
245 ip_ct_refresh(conntrack, ESP_TIMEOUT);
247 //esp_entry = search_esp_entry_by_spi ( esph, iph->daddr );
248 if ( esp_entry != NULL ) {
249 //printk ( KERN_DEBUG "%s:%s can modify this %u.%u.%u.%u"
250 // " with %u.%u.%u.%u\n",
251 // __FILE__, __FUNCTION__,
252 // NIPQUAD(conntrack->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip),
253 // NIPQUAD(esp_entry->l_ip) );
259 /* Called when a new connection for this protocol found. */
260 static int esp_new(struct ip_conntrack *conntrack, const struct sk_buff *skb)
262 const struct iphdr *iph = skb->nh.iph;
263 const struct esphdr *esph = (void *)iph + iph->ihl*4;
264 struct _esp_table *esp_entry;
265 //printk ( KERN_DEBUG "%s:%s (0x%x) %u.%u.%u.%u <-> %u.%u.%u.%u\n",
266 // __FILE__, __FUNCTION__, ntohl(esph->spi),
267 // NIPQUAD(iph->saddr), NIPQUAD(iph->daddr));
268 if ( (esp_entry = search_esp_entry_by_spi ( esph, iph->daddr ) ) == NULL ) {
270 * Check if this is the same LAN client creating another session.
271 * If this is true, then the LAN IP address will be the same with
272 * a new SPI value. This would indicate that the entire transaction
273 * using the previous value of SPI is now not required.
275 esp_entry = alloc_esp_entry ();
276 if ( esp_entry == NULL ) {
277 /* All entries are currently in use */
278 //printk ( KERN_DEBUG "%s:%s All connections in use\n",
279 // __FILE__, __FUNCTION__);
282 esp_entry->l_spi = ntohl(esph->spi);
283 esp_entry->l_ip = ntohl(iph->saddr);
284 esp_entry->r_spi = 0;
289 struct ip_conntrack_protocol ip_conntrack_protocol_esp
290 = { { NULL, NULL }, IPPROTO_ESP, "esp",
291 esp_pkt_to_tuple, esp_invert_tuple, esp_print_tuple, esp_print_conntrack,
292 esp_packet, esp_new, NULL };