pre-2.3.4..
[davej-history.git] / net / ipv4 / ip_masq_vdolive.c
blob4724e3b934185ac71f273f8d1d4140f18888ee18
1 /*
2 * IP_MASQ_VDOLIVE - VDO Live masquerading module
5 * Version: @(#)$Id: ip_masq_vdolive.c,v 1.4 1998/10/06 04:49:07 davem Exp $
7 * Author: Nigel Metheringham <Nigel.Metheringham@ThePLAnet.net>
8 * PLAnet Online Ltd
10 * Fixes: Minor changes for 2.1 by
11 * Steven Clarke <Steven.Clarke@ThePlanet.Net>, Planet Online Ltd
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version
16 * 2 of the License, or (at your option) any later version.
18 * Thanks:
19 * Thank you to VDOnet Corporation for allowing me access to
20 * a protocol description without an NDA. This means that
21 * this module can be distributed as source - a great help!
25 #include <linux/config.h>
26 #include <linux/module.h>
27 #include <linux/types.h>
28 #include <linux/kernel.h>
29 #include <asm/system.h>
30 #include <linux/skbuff.h>
31 #include <linux/in.h>
32 #include <linux/ip.h>
33 #include <linux/init.h>
34 #include <net/protocol.h>
35 #include <net/tcp.h>
36 #include <net/ip_masq.h>
38 struct vdolive_priv_data {
39 /* Ports used */
40 unsigned short origport;
41 unsigned short masqport;
42 /* State of decode */
43 unsigned short state;
46 /*
47 * List of ports (up to MAX_MASQ_APP_PORTS) to be handled by helper
48 * First port is set to the default port.
50 static int ports[MAX_MASQ_APP_PORTS] = {7000}; /* I rely on the trailing items being set to zero */
51 struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
54 * Debug level
56 #ifdef CONFIG_IP_MASQ_DEBUG
57 static int debug=0;
58 MODULE_PARM(debug, "i");
59 #endif
61 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
63 static int
64 masq_vdolive_init_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
66 MOD_INC_USE_COUNT;
67 if ((ms->app_data = kmalloc(sizeof(struct vdolive_priv_data),
68 GFP_ATOMIC)) == NULL)
69 IP_MASQ_DEBUG(1-debug, "VDOlive: No memory for application data\n");
70 else
72 struct vdolive_priv_data *priv =
73 (struct vdolive_priv_data *)ms->app_data;
74 priv->origport = 0;
75 priv->masqport = 0;
76 priv->state = 0;
78 return 0;
81 static int
82 masq_vdolive_done_1 (struct ip_masq_app *mapp, struct ip_masq *ms)
84 MOD_DEC_USE_COUNT;
85 if (ms->app_data)
86 kfree_s(ms->app_data, sizeof(struct vdolive_priv_data));
87 return 0;
90 int
91 masq_vdolive_out (struct ip_masq_app *mapp, struct ip_masq *ms, struct sk_buff **skb_p, __u32 maddr)
93 struct sk_buff *skb;
94 struct iphdr *iph;
95 struct tcphdr *th;
96 char *data, *data_limit;
97 unsigned int tagval; /* This should be a 32 bit quantity */
98 struct ip_masq *n_ms;
99 struct vdolive_priv_data *priv =
100 (struct vdolive_priv_data *)ms->app_data;
102 /* This doesn't work at all if no priv data was allocated on startup */
103 if (!priv)
104 return 0;
106 /* Everything running correctly already */
107 if (priv->state == 3)
108 return 0;
110 skb = *skb_p;
111 iph = skb->nh.iph;
112 th = (struct tcphdr *)&(((char *)iph)[iph->ihl*4]);
113 data = (char *)&th[1];
115 data_limit = skb->h.raw + skb->len;
117 if (data+8 > data_limit) {
118 IP_MASQ_DEBUG(1-debug, "VDOlive: packet too short for ID %p %p\n", data, data_limit);
119 return 0;
121 memcpy(&tagval, data+4, 4);
122 IP_MASQ_DEBUG(1-debug, "VDOlive: packet seen, tag %ld, in initial state %d\n", ntohl(tagval), priv->state);
124 /* Check for leading packet ID */
125 if ((ntohl(tagval) != 6) && (ntohl(tagval) != 1)) {
126 IP_MASQ_DEBUG(1-debug, "VDOlive: unrecognised tag %ld, in initial state %d\n", ntohl(tagval), priv->state);
127 return 0;
131 /* Check packet is long enough for data - ignore if not */
132 if ((ntohl(tagval) == 6) && (data+36 > data_limit)) {
133 IP_MASQ_DEBUG(1-debug, "VDOlive: initial packet too short %p %p\n", data, data_limit);
134 return 0;
135 } else if ((ntohl(tagval) == 1) && (data+20 > data_limit)) {
136 IP_MASQ_DEBUG(1-debug,"VDOlive: secondary packet too short %p %p\n", data, data_limit);
137 return 0;
140 /* Adjust data pointers */
142 * I could check the complete protocol version tag
143 * in here however I am just going to look for the
144 * "VDO Live" tag in the hope that this part will
145 * remain constant even if the version changes
147 if (ntohl(tagval) == 6) {
148 data += 24;
149 IP_MASQ_DEBUG(1-debug, "VDOlive: initial packet found\n");
150 } else {
151 data += 8;
152 IP_MASQ_DEBUG(1-debug, "VDOlive: secondary packet found\n");
155 if (memcmp(data, "VDO Live", 8) != 0) {
156 IP_MASQ_DEBUG(1-debug,"VDOlive: did not find tag\n");
157 return 0;
160 * The port number is the next word after the tag.
161 * VDOlive encodes all of these values
162 * in 32 bit words, so in this case I am
163 * skipping the first 2 bytes of the next
164 * word to get to the relevant 16 bits
166 data += 10;
169 * If we have not seen the port already,
170 * set the masquerading tunnel up
172 if (!priv->origport) {
173 memcpy(&priv->origport, data, 2);
174 IP_MASQ_DEBUG(1-debug, "VDOlive: found port %d\n", ntohs(priv->origport));
176 /* Open up a tunnel */
177 n_ms = ip_masq_new(IPPROTO_UDP,
178 maddr, 0,
179 ms->saddr, priv->origport,
180 ms->daddr, 0,
181 IP_MASQ_F_NO_DPORT);
183 if (n_ms==NULL) {
184 ip_masq_put(n_ms);
185 IP_MASQ_DEBUG(1-debug, "VDOlive: unable to build UDP tunnel for %x:%x\n", ms->saddr, priv->origport);
186 /* Leave state as unset */
187 priv->origport = 0;
188 return 0;
190 ip_masq_listen(n_ms);
192 ip_masq_put(ms);
193 priv->masqport = n_ms->mport;
194 } else if (memcmp(data, &(priv->origport), 2)) {
195 IP_MASQ_DEBUG(1-debug, "VDOlive: ports do not match\n");
196 /* Write the port in anyhow!!! */
200 * Write masq port into packet
202 memcpy(data, &(priv->masqport), 2);
203 IP_MASQ_DEBUG(1-debug, "VDOlive: rewrote port %d to %d, server %08X\n", ntohs(priv->origport), ntohs(priv->masqport), ms->saddr);
206 * Set state bit to make which bit has been done
209 priv->state |= (ntohl(tagval) == 6) ? 1 : 2;
211 return 0;
215 struct ip_masq_app ip_masq_vdolive = {
216 NULL, /* next */
217 "VDOlive", /* name */
218 0, /* type */
219 0, /* n_attach */
220 masq_vdolive_init_1, /* ip_masq_init_1 */
221 masq_vdolive_done_1, /* ip_masq_done_1 */
222 masq_vdolive_out, /* pkt_out */
223 NULL /* pkt_in */
227 * ip_masq_vdolive initialization
230 __initfunc(int ip_masq_vdolive_init(void))
232 int i, j;
234 for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
235 if (ports[i]) {
236 if ((masq_incarnations[i] = kmalloc(sizeof(struct ip_masq_app),
237 GFP_KERNEL)) == NULL)
238 return -ENOMEM;
239 memcpy(masq_incarnations[i], &ip_masq_vdolive, sizeof(struct ip_masq_app));
240 if ((j = register_ip_masq_app(masq_incarnations[i],
241 IPPROTO_TCP,
242 ports[i]))) {
243 return j;
245 IP_MASQ_DEBUG(1-debug, "RealAudio: loaded support on port[%d] = %d\n", i, ports[i]);
246 } else {
247 /* To be safe, force the incarnation table entry to NULL */
248 masq_incarnations[i] = NULL;
251 return 0;
255 * ip_masq_vdolive fin.
258 int ip_masq_vdolive_done(void)
260 int i, j, k;
262 k=0;
263 for (i=0; (i<MAX_MASQ_APP_PORTS); i++) {
264 if (masq_incarnations[i]) {
265 if ((j = unregister_ip_masq_app(masq_incarnations[i]))) {
266 k = j;
267 } else {
268 kfree(masq_incarnations[i]);
269 masq_incarnations[i] = NULL;
270 IP_MASQ_DEBUG(1-debug,"VDOlive: unloaded support on port[%d] = %d\n", i, ports[i]);
274 return k;
278 #ifdef MODULE
279 EXPORT_NO_SYMBOLS;
281 int init_module(void)
283 if (ip_masq_vdolive_init() != 0)
284 return -EIO;
285 return 0;
288 void cleanup_module(void)
290 if (ip_masq_vdolive_done() != 0)
291 IP_MASQ_DEBUG(1-debug, "ip_masq_vdolive: can't remove module");
294 #endif /* MODULE */