Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
net
ipv4
ipcomp.c
Go to the documentation of this file.
1
/*
2
* IP Payload Compression Protocol (IPComp) - RFC3173.
3
*
4
* Copyright (c) 2003 James Morris <
[email protected]
>
5
*
6
* This program is free software; you can redistribute it and/or modify it
7
* under the terms of the GNU General Public License as published by the Free
8
* Software Foundation; either version 2 of the License, or (at your option)
9
* any later version.
10
*
11
* Todo:
12
* - Tunable compression parameters.
13
* - Compression stats.
14
* - Adaptive compression.
15
*/
16
#include <linux/module.h>
17
#include <
linux/err.h
>
18
#include <linux/rtnetlink.h>
19
#include <
net/ip.h
>
20
#include <
net/xfrm.h
>
21
#include <
net/icmp.h
>
22
#include <
net/ipcomp.h
>
23
#include <
net/protocol.h
>
24
#include <
net/sock.h
>
25
26
static
void
ipcomp4_err(
struct
sk_buff
*
skb
,
u32
info
)
27
{
28
struct
net
*
net
= dev_net(skb->
dev
);
29
__be32
spi
;
30
const
struct
iphdr
*iph = (
const
struct
iphdr
*)skb->
data
;
31
struct
ip_comp_hdr
*ipch = (
struct
ip_comp_hdr
*)(skb->
data
+(iph->ihl<<2));
32
struct
xfrm_state
*
x
;
33
34
switch
(icmp_hdr(skb)->type) {
35
case
ICMP_DEST_UNREACH
:
36
if
(icmp_hdr(skb)->code !=
ICMP_FRAG_NEEDED
)
37
return
;
38
case
ICMP_REDIRECT
:
39
break
;
40
default
:
41
return
;
42
}
43
44
spi =
htonl
(
ntohs
(ipch->cpi));
45
x =
xfrm_state_lookup
(net, skb->
mark
, (
const
xfrm_address_t
*)&iph->
daddr
,
46
spi,
IPPROTO_COMP
,
AF_INET
);
47
if
(!x)
48
return
;
49
50
if
(icmp_hdr(skb)->
type
==
ICMP_DEST_UNREACH
)
51
ipv4_update_pmtu
(skb, net, info, 0, 0,
IPPROTO_COMP
, 0);
52
else
53
ipv4_redirect
(skb, net, 0, 0,
IPPROTO_COMP
, 0);
54
xfrm_state_put(x);
55
}
56
57
/* We always hold one tunnel user reference to indicate a tunnel */
58
static
struct
xfrm_state
*ipcomp_tunnel_create(
struct
xfrm_state
*x)
59
{
60
struct
net *net = xs_net(x);
61
struct
xfrm_state
*
t
;
62
63
t =
xfrm_state_alloc
(net);
64
if
(t ==
NULL
)
65
goto
out
;
66
67
t->
id
.proto =
IPPROTO_IPIP
;
68
t->
id
.spi = x->
props
.saddr.a4;
69
t->
id
.daddr.a4 = x->
id
.daddr.a4;
70
memcpy
(&t->
sel
, &x->
sel
,
sizeof
(t->
sel
));
71
t->
props
.family =
AF_INET
;
72
t->
props
.mode = x->
props
.mode;
73
t->
props
.saddr.a4 = x->
props
.saddr.a4;
74
t->
props
.flags = x->
props
.flags;
75
memcpy
(&t->
mark
, &x->
mark
,
sizeof
(t->
mark
));
76
77
if
(
xfrm_init_state
(t))
78
goto
error
;
79
80
atomic_set
(&t->
tunnel_users
, 1);
81
out
:
82
return
t
;
83
84
error
:
85
t->
km
.state =
XFRM_STATE_DEAD
;
86
xfrm_state_put(t);
87
t =
NULL
;
88
goto
out
;
89
}
90
91
/*
92
* Must be protected by xfrm_cfg_mutex. State and tunnel user references are
93
* always incremented on success.
94
*/
95
static
int
ipcomp_tunnel_attach(
struct
xfrm_state
*x)
96
{
97
struct
net *net = xs_net(x);
98
int
err
= 0;
99
struct
xfrm_state
*
t
;
100
u32
mark
= x->
mark
.v & x->
mark
.m;
101
102
t =
xfrm_state_lookup
(net, mark, (
xfrm_address_t
*)&x->
id
.daddr.a4,
103
x->
props
.saddr.a4,
IPPROTO_IPIP
,
AF_INET
);
104
if
(!t) {
105
t = ipcomp_tunnel_create(x);
106
if
(!t) {
107
err = -
EINVAL
;
108
goto
out
;
109
}
110
xfrm_state_insert
(t);
111
xfrm_state_hold(t);
112
}
113
x->
tunnel
=
t
;
114
atomic_inc
(&t->
tunnel_users
);
115
out
:
116
return
err
;
117
}
118
119
static
int
ipcomp4_init_state(
struct
xfrm_state
*x)
120
{
121
int
err = -
EINVAL
;
122
123
x->
props
.header_len = 0;
124
switch
(x->
props
.mode) {
125
case
XFRM_MODE_TRANSPORT
:
126
break
;
127
case
XFRM_MODE_TUNNEL
:
128
x->
props
.header_len +=
sizeof
(
struct
iphdr
);
129
break
;
130
default
:
131
goto
out
;
132
}
133
134
err =
ipcomp_init_state
(x);
135
if
(err)
136
goto
out
;
137
138
if
(x->
props
.mode ==
XFRM_MODE_TUNNEL
) {
139
err = ipcomp_tunnel_attach(x);
140
if
(err)
141
goto
out
;
142
}
143
144
err = 0;
145
out
:
146
return
err
;
147
}
148
149
static
const
struct
xfrm_type
ipcomp_type = {
150
.description =
"IPCOMP4"
,
151
.owner =
THIS_MODULE
,
152
.proto =
IPPROTO_COMP
,
153
.init_state = ipcomp4_init_state,
154
.destructor =
ipcomp_destroy
,
155
.input =
ipcomp_input
,
156
.output =
ipcomp_output
157
};
158
159
static
const
struct
net_protocol
ipcomp4_protocol = {
160
.handler =
xfrm4_rcv
,
161
.err_handler = ipcomp4_err,
162
.no_policy = 1,
163
};
164
165
static
int
__init
ipcomp4_init(
void
)
166
{
167
if
(
xfrm_register_type
(&ipcomp_type,
AF_INET
) < 0) {
168
pr_info
(
"%s: can't add xfrm type\n"
, __func__);
169
return
-
EAGAIN
;
170
}
171
if
(
inet_add_protocol
(&ipcomp4_protocol,
IPPROTO_COMP
) < 0) {
172
pr_info
(
"%s: can't add protocol\n"
, __func__);
173
xfrm_unregister_type
(&ipcomp_type,
AF_INET
);
174
return
-
EAGAIN
;
175
}
176
return
0;
177
}
178
179
static
void
__exit
ipcomp4_fini(
void
)
180
{
181
if
(
inet_del_protocol
(&ipcomp4_protocol,
IPPROTO_COMP
) < 0)
182
pr_info
(
"%s: can't remove protocol\n"
, __func__);
183
if
(
xfrm_unregister_type
(&ipcomp_type,
AF_INET
) < 0)
184
pr_info
(
"%s: can't remove xfrm type\n"
, __func__);
185
}
186
187
module_init
(ipcomp4_init);
188
module_exit
(ipcomp4_fini);
189
190
MODULE_LICENSE
(
"GPL"
);
191
MODULE_DESCRIPTION
(
"IP Payload Compression Protocol (IPComp/IPv4) - RFC3173"
);
192
MODULE_AUTHOR
(
"James Morris <
[email protected]
>"
);
193
194
MODULE_ALIAS_XFRM_TYPE
(
AF_INET
,
XFRM_PROTO_COMP
);
Generated on Thu Jan 10 2013 14:58:31 for Linux Kernel by
1.8.2