148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy/*
248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy * Copyright (c) 2013 Patrick McHardy <kaber@trash.net>
348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy *
448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy * This program is free software; you can redistribute it and/or modify
548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy * it under the terms of the GNU General Public License version 2 as
648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy * published by the Free Software Foundation.
748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy */
848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <linux/module.h>
1048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <linux/skbuff.h>
1148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <asm/unaligned.h>
1248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <net/tcp.h>
1348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <net/netns/generic.h>
1448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
1548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <linux/netfilter_ipv4/ip_tables.h>
1648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <linux/netfilter/x_tables.h>
1748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <linux/netfilter/xt_tcpudp.h>
1848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <linux/netfilter/xt_SYNPROXY.h>
1948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <net/netfilter/nf_conntrack.h>
2048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <net/netfilter/nf_conntrack_extend.h>
2148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <net/netfilter/nf_conntrack_seqadj.h>
2248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#include <net/netfilter/nf_conntrack_synproxy.h>
2348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
2448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyint synproxy_net_id;
2548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyEXPORT_SYMBOL_GPL(synproxy_net_id);
2648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
27f4a87e7bd2eaef26a3ca25437ce8b807de2966adPatrick McHardybool
2848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardysynproxy_parse_options(const struct sk_buff *skb, unsigned int doff,
2948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		       const struct tcphdr *th, struct synproxy_options *opts)
3048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
3148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	int length = (th->doff * 4) - sizeof(*th);
3248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	u8 buf[40], *ptr;
3348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
3448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	ptr = skb_header_pointer(skb, doff + sizeof(*th), length, buf);
35f4a87e7bd2eaef26a3ca25437ce8b807de2966adPatrick McHardy	if (ptr == NULL)
36f4a87e7bd2eaef26a3ca25437ce8b807de2966adPatrick McHardy		return false;
3748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
3848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	opts->options = 0;
3948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	while (length > 0) {
4048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		int opcode = *ptr++;
4148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		int opsize;
4248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
4348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		switch (opcode) {
4448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		case TCPOPT_EOL:
45f4a87e7bd2eaef26a3ca25437ce8b807de2966adPatrick McHardy			return true;
4648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		case TCPOPT_NOP:
4748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			length--;
4848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			continue;
4948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		default:
5048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			opsize = *ptr++;
5148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			if (opsize < 2)
52f4a87e7bd2eaef26a3ca25437ce8b807de2966adPatrick McHardy				return true;
5348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			if (opsize > length)
54f4a87e7bd2eaef26a3ca25437ce8b807de2966adPatrick McHardy				return true;
5548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
5648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			switch (opcode) {
5748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			case TCPOPT_MSS:
5848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				if (opsize == TCPOLEN_MSS) {
5948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					opts->mss = get_unaligned_be16(ptr);
6048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					opts->options |= XT_SYNPROXY_OPT_MSS;
6148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				}
6248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				break;
6348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			case TCPOPT_WINDOW:
6448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				if (opsize == TCPOLEN_WINDOW) {
6548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					opts->wscale = *ptr;
6648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					if (opts->wscale > 14)
6748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy						opts->wscale = 14;
6848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					opts->options |= XT_SYNPROXY_OPT_WSCALE;
6948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				}
7048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				break;
7148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			case TCPOPT_TIMESTAMP:
7248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				if (opsize == TCPOLEN_TIMESTAMP) {
7348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					opts->tsval = get_unaligned_be32(ptr);
7448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					opts->tsecr = get_unaligned_be32(ptr + 4);
7548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					opts->options |= XT_SYNPROXY_OPT_TIMESTAMP;
7648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				}
7748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				break;
7848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			case TCPOPT_SACK_PERM:
7948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				if (opsize == TCPOLEN_SACK_PERM)
8048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					opts->options |= XT_SYNPROXY_OPT_SACK_PERM;
8148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				break;
8248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			}
8348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
8448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			ptr += opsize - 2;
8548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			length -= opsize;
8648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		}
8748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	}
88f4a87e7bd2eaef26a3ca25437ce8b807de2966adPatrick McHardy	return true;
8948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
9048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyEXPORT_SYMBOL_GPL(synproxy_parse_options);
9148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
9248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyunsigned int synproxy_options_size(const struct synproxy_options *opts)
9348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
9448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	unsigned int size = 0;
9548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
9648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (opts->options & XT_SYNPROXY_OPT_MSS)
9748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		size += TCPOLEN_MSS_ALIGNED;
9848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (opts->options & XT_SYNPROXY_OPT_TIMESTAMP)
9948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		size += TCPOLEN_TSTAMP_ALIGNED;
10048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	else if (opts->options & XT_SYNPROXY_OPT_SACK_PERM)
10148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		size += TCPOLEN_SACKPERM_ALIGNED;
10248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (opts->options & XT_SYNPROXY_OPT_WSCALE)
10348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		size += TCPOLEN_WSCALE_ALIGNED;
10448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
10548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return size;
10648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
10748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyEXPORT_SYMBOL_GPL(synproxy_options_size);
10848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
10948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyvoid
11048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardysynproxy_build_options(struct tcphdr *th, const struct synproxy_options *opts)
11148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
11248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	__be32 *ptr = (__be32 *)(th + 1);
11348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	u8 options = opts->options;
11448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
11548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (options & XT_SYNPROXY_OPT_MSS)
11648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		*ptr++ = htonl((TCPOPT_MSS << 24) |
11748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			       (TCPOLEN_MSS << 16) |
11848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			       opts->mss);
11948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
12048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (options & XT_SYNPROXY_OPT_TIMESTAMP) {
12148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		if (options & XT_SYNPROXY_OPT_SACK_PERM)
12248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			*ptr++ = htonl((TCPOPT_SACK_PERM << 24) |
12348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				       (TCPOLEN_SACK_PERM << 16) |
12448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				       (TCPOPT_TIMESTAMP << 8) |
12548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				       TCPOLEN_TIMESTAMP);
12648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		else
12748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			*ptr++ = htonl((TCPOPT_NOP << 24) |
12848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				       (TCPOPT_NOP << 16) |
12948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				       (TCPOPT_TIMESTAMP << 8) |
13048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				       TCPOLEN_TIMESTAMP);
13148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
13248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		*ptr++ = htonl(opts->tsval);
13348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		*ptr++ = htonl(opts->tsecr);
13448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	} else if (options & XT_SYNPROXY_OPT_SACK_PERM)
13548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		*ptr++ = htonl((TCPOPT_NOP << 24) |
13648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			       (TCPOPT_NOP << 16) |
13748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			       (TCPOPT_SACK_PERM << 8) |
13848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			       TCPOLEN_SACK_PERM);
13948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
14048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (options & XT_SYNPROXY_OPT_WSCALE)
14148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		*ptr++ = htonl((TCPOPT_NOP << 24) |
14248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			       (TCPOPT_WINDOW << 16) |
14348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			       (TCPOLEN_WINDOW << 8) |
14448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			       opts->wscale);
14548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
14648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyEXPORT_SYMBOL_GPL(synproxy_build_options);
14748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
14848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyvoid synproxy_init_timestamp_cookie(const struct xt_synproxy_info *info,
14948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				    struct synproxy_options *opts)
15048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
15148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	opts->tsecr = opts->tsval;
15248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	opts->tsval = tcp_time_stamp & ~0x3f;
15348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
154c1898c4c295b735c05af4c09664993fd8f257c2bMartin Topholm	if (opts->options & XT_SYNPROXY_OPT_WSCALE) {
155c1898c4c295b735c05af4c09664993fd8f257c2bMartin Topholm		opts->tsval |= opts->wscale;
156c1898c4c295b735c05af4c09664993fd8f257c2bMartin Topholm		opts->wscale = info->wscale;
157c1898c4c295b735c05af4c09664993fd8f257c2bMartin Topholm	} else
15848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		opts->tsval |= 0xf;
15948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
16048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (opts->options & XT_SYNPROXY_OPT_SACK_PERM)
16148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		opts->tsval |= 1 << 4;
16248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
16348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (opts->options & XT_SYNPROXY_OPT_ECN)
16448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		opts->tsval |= 1 << 5;
16548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
16648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyEXPORT_SYMBOL_GPL(synproxy_init_timestamp_cookie);
16748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
16848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyvoid synproxy_check_timestamp_cookie(struct synproxy_options *opts)
16948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
17048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	opts->wscale = opts->tsecr & 0xf;
17148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (opts->wscale != 0xf)
17248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		opts->options |= XT_SYNPROXY_OPT_WSCALE;
17348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
17448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	opts->options |= opts->tsecr & (1 << 4) ? XT_SYNPROXY_OPT_SACK_PERM : 0;
17548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
17648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	opts->options |= opts->tsecr & (1 << 5) ? XT_SYNPROXY_OPT_ECN : 0;
17748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
17848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyEXPORT_SYMBOL_GPL(synproxy_check_timestamp_cookie);
17948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
18048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyunsigned int synproxy_tstamp_adjust(struct sk_buff *skb,
18148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				    unsigned int protoff,
18248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				    struct tcphdr *th,
18348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				    struct nf_conn *ct,
18448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				    enum ip_conntrack_info ctinfo,
18548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				    const struct nf_conn_synproxy *synproxy)
18648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
18748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	unsigned int optoff, optend;
18848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	u32 *ptr, old;
18948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
19048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (synproxy->tsoff == 0)
19148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		return 1;
19248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
19348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	optoff = protoff + sizeof(struct tcphdr);
19448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	optend = protoff + th->doff * 4;
19548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
19648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (!skb_make_writable(skb, optend))
19748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		return 0;
19848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
19948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	while (optoff < optend) {
20048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		unsigned char *op = skb->data + optoff;
20148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
20248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		switch (op[0]) {
20348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		case TCPOPT_EOL:
20448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			return 1;
20548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		case TCPOPT_NOP:
20648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			optoff++;
20748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			continue;
20848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		default:
20948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			if (optoff + 1 == optend ||
21048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			    optoff + op[1] > optend ||
21148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			    op[1] < 2)
21248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				return 0;
21348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			if (op[0] == TCPOPT_TIMESTAMP &&
21448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			    op[1] == TCPOLEN_TIMESTAMP) {
21548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) {
21648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					ptr = (u32 *)&op[2];
21748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					old = *ptr;
21848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					*ptr = htonl(ntohl(*ptr) -
21948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy						     synproxy->tsoff);
22048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				} else {
22148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					ptr = (u32 *)&op[6];
22248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					old = *ptr;
22348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy					*ptr = htonl(ntohl(*ptr) +
22448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy						     synproxy->tsoff);
22548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				}
22648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				inet_proto_csum_replace4(&th->check, skb,
22748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy							 old, *ptr, 0);
22848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				return 1;
22948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			}
23048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			optoff += op[1];
23148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		}
23248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	}
23348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return 1;
23448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
23548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyEXPORT_SYMBOL_GPL(synproxy_tstamp_adjust);
23648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
23748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic struct nf_ct_ext_type nf_ct_synproxy_extend __read_mostly = {
23848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.len		= sizeof(struct nf_conn_synproxy),
23948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.align		= __alignof__(struct nf_conn_synproxy),
24048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.id		= NF_CT_EXT_SYNPROXY,
24148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy};
24248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
24348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#ifdef CONFIG_PROC_FS
24448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic void *synproxy_cpu_seq_start(struct seq_file *seq, loff_t *pos)
24548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
24648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	struct synproxy_net *snet = synproxy_pernet(seq_file_net(seq));
24748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	int cpu;
24848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
24948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (*pos == 0)
25048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		return SEQ_START_TOKEN;
25148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
25248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	for (cpu = *pos - 1; cpu < nr_cpu_ids; cpu++) {
25348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		if (!cpu_possible(cpu))
25448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			continue;
25548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		*pos = cpu + 1;
25648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		return per_cpu_ptr(snet->stats, cpu);
25748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	}
25848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
25948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return NULL;
26048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
26148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
26248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic void *synproxy_cpu_seq_next(struct seq_file *seq, void *v, loff_t *pos)
26348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
26448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	struct synproxy_net *snet = synproxy_pernet(seq_file_net(seq));
26548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	int cpu;
26648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
26748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	for (cpu = *pos; cpu < nr_cpu_ids; cpu++) {
26848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		if (!cpu_possible(cpu))
26948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			continue;
27048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		*pos = cpu + 1;
27148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		return per_cpu_ptr(snet->stats, cpu);
27248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	}
27348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
27448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return NULL;
27548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
27648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
27748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic void synproxy_cpu_seq_stop(struct seq_file *seq, void *v)
27848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
27948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return;
28048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
28148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
28248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic int synproxy_cpu_seq_show(struct seq_file *seq, void *v)
28348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
28448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	struct synproxy_stats *stats = v;
28548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
28648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (v == SEQ_START_TOKEN) {
28748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		seq_printf(seq, "entries\t\tsyn_received\t"
28848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				"cookie_invalid\tcookie_valid\t"
28948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy				"cookie_retrans\tconn_reopened\n");
29048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		return 0;
29148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	}
29248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
29348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	seq_printf(seq, "%08x\t%08x\t%08x\t%08x\t%08x\t%08x\n", 0,
29448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		   stats->syn_received,
29548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		   stats->cookie_invalid,
29648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		   stats->cookie_valid,
29748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		   stats->cookie_retrans,
29848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		   stats->conn_reopened);
29948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
30048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return 0;
30148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
30248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
30348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic const struct seq_operations synproxy_cpu_seq_ops = {
30448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.start		= synproxy_cpu_seq_start,
30548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.next		= synproxy_cpu_seq_next,
30648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.stop		= synproxy_cpu_seq_stop,
30748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.show		= synproxy_cpu_seq_show,
30848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy};
30948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
31048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic int synproxy_cpu_seq_open(struct inode *inode, struct file *file)
31148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
31248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return seq_open_net(inode, file, &synproxy_cpu_seq_ops,
31348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			    sizeof(struct seq_net_private));
31448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
31548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
31648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic const struct file_operations synproxy_cpu_seq_fops = {
31748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.owner		= THIS_MODULE,
31848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.open		= synproxy_cpu_seq_open,
31948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.read		= seq_read,
32048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.llseek		= seq_lseek,
32148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.release	= seq_release_net,
32248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy};
32348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
32448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic int __net_init synproxy_proc_init(struct net *net)
32548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
32648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (!proc_create("synproxy", S_IRUGO, net->proc_net_stat,
32748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy			 &synproxy_cpu_seq_fops))
32848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		return -ENOMEM;
32948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return 0;
33048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
33148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
33248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic void __net_exit synproxy_proc_exit(struct net *net)
33348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
33448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	remove_proc_entry("synproxy", net->proc_net_stat);
33548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
33648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#else
33748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic int __net_init synproxy_proc_init(struct net *net)
33848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
33948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return 0;
34048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
34148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
34248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic void __net_exit synproxy_proc_exit(struct net *net)
34348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
34448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return;
34548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
34648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy#endif /* CONFIG_PROC_FS */
34748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
34848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic int __net_init synproxy_net_init(struct net *net)
34948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
35048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	struct synproxy_net *snet = synproxy_pernet(net);
35148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	struct nf_conntrack_tuple t;
35248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	struct nf_conn *ct;
35348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	int err = -ENOMEM;
35448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
35548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	memset(&t, 0, sizeof(t));
35648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	ct = nf_conntrack_alloc(net, 0, &t, &t, GFP_KERNEL);
35748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (IS_ERR(ct)) {
35848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		err = PTR_ERR(ct);
35948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		goto err1;
36048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	}
36148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
36248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (!nfct_seqadj_ext_add(ct))
36348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		goto err2;
36448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (!nfct_synproxy_ext_add(ct))
36548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		goto err2;
36648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
367e53376bef2cd97d3e3f61fdc677fb8da7d03d0daPablo Neira Ayuso	nf_conntrack_tmpl_insert(net, ct);
36848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	snet->tmpl = ct;
36948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
37048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	snet->stats = alloc_percpu(struct synproxy_stats);
37148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (snet->stats == NULL)
37248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		goto err2;
37348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
37448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	err = synproxy_proc_init(net);
37548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (err < 0)
37648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		goto err3;
37748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
37848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return 0;
37948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
38048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyerr3:
38148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	free_percpu(snet->stats);
38248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyerr2:
38348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	nf_conntrack_free(ct);
38448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyerr1:
38548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return err;
38648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
38748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
38848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic void __net_exit synproxy_net_exit(struct net *net)
38948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
39048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	struct synproxy_net *snet = synproxy_pernet(net);
39148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
392e53376bef2cd97d3e3f61fdc677fb8da7d03d0daPablo Neira Ayuso	nf_ct_put(snet->tmpl);
39348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	synproxy_proc_exit(net);
39448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	free_percpu(snet->stats);
39548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
39648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
39748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic struct pernet_operations synproxy_net_ops = {
39848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.init		= synproxy_net_init,
39948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.exit		= synproxy_net_exit,
40048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.id		= &synproxy_net_id,
40148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	.size		= sizeof(struct synproxy_net),
40248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy};
40348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
40448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic int __init synproxy_core_init(void)
40548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
40648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	int err;
40748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
40848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	err = nf_ct_extend_register(&nf_ct_synproxy_extend);
40948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (err < 0)
41048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		goto err1;
41148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
41248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	err = register_pernet_subsys(&synproxy_net_ops);
41348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	if (err < 0)
41448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy		goto err2;
41548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
41648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return 0;
41748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
41848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyerr2:
41948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	nf_ct_extend_unregister(&nf_ct_synproxy_extend);
42048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyerr1:
42148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	return err;
42248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
42348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
42448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardystatic void __exit synproxy_core_exit(void)
42548b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy{
42648b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	unregister_pernet_subsys(&synproxy_net_ops);
42748b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy	nf_ct_extend_unregister(&nf_ct_synproxy_extend);
42848b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy}
42948b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
43048b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardymodule_init(synproxy_core_init);
43148b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardymodule_exit(synproxy_core_exit);
43248b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardy
43348b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyMODULE_LICENSE("GPL");
43448b1de4c110a7afa4b85862f6c75af817db26fadPatrick McHardyMODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
435