adjust planetlab patchset against RHEL kernel
[linux-2.6.git] / linux-2.6-510-ipod.patch
1 diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
2 index 0344615..dc0f0d8 100644
3 --- a/include/linux/sysctl.h
4 +++ b/include/linux/sysctl.h
5 @@ -436,6 +436,13 @@ enum
6         NET_TCP_ALLOWED_CONG_CONTROL=123,
7         NET_TCP_MAX_SSTHRESH=124,
8         NET_TCP_FRTO_RESPONSE=125,
9 +#ifdef CONFIG_ICMP_IPOD
10 +       NET_IPV4_ICMP_IPOD_VERSION,
11 +       NET_IPV4_ICMP_IPOD_ENABLED,
12 +       NET_IPV4_ICMP_IPOD_HOST,
13 +       NET_IPV4_ICMP_IPOD_MASK,
14 +       NET_IPV4_ICMP_IPOD_KEY
15 +#endif
16  };
17  
18  enum {
19 diff --git a/include/net/icmp.h b/include/net/icmp.h
20 index dfa72d4..55cdc47 100644
21 --- a/include/net/icmp.h
22 +++ b/include/net/icmp.h
23 @@ -59,4 +59,12 @@ static inline struct raw_sock *raw_sk(const struct sock *sk)
24         return (struct raw_sock *)sk;
25  }
26  
27 +#ifdef CONFIG_ICMP_IPOD
28 +extern int sysctl_icmp_ipod_version;
29 +extern int sysctl_icmp_ipod_enabled;
30 +extern u32 sysctl_icmp_ipod_host;
31 +extern u32 sysctl_icmp_ipod_mask;
32 +extern char sysctl_icmp_ipod_key[32+1];
33 +#endif
34 +
35  #endif /* _ICMP_H */
36 diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
37 index 0c94a1a..31a67cc 100644
38 --- a/net/ipv4/Kconfig
39 +++ b/net/ipv4/Kconfig
40 @@ -627,3 +627,14 @@ config TCP_MD5SIG
41  
42           If unsure, say N.
43  
44 +#
45 +# Emulab special
46 +#
47 +
48 +config ICMP_IPOD
49 +       bool "ICMP: ICMP Ping-of-Death (Emulab)"
50 +       depends on INET && SYSCTL
51 +       ---help---
52 +          Support immediately rebooting upon receiving a specially
53 +         formed ICMP type 6 packet whose payload matches a string
54 +         configured by the administrator.
55 diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
56 index 5bc13fe..5324406 100644
57 --- a/net/ipv4/icmp.c
58 +++ b/net/ipv4/icmp.c
59 @@ -960,6 +960,67 @@ static void icmp_address_reply(struct sk_buff *skb)
60  out:;
61  }
62  
63 +#ifdef CONFIG_ICMP_IPOD
64 +#include <linux/reboot.h>
65 +
66 +int sysctl_icmp_ipod_version = 2;
67 +int sysctl_icmp_ipod_enabled = 0;
68 +u32 sysctl_icmp_ipod_host = 0xffffffff;
69 +u32 sysctl_icmp_ipod_mask = 0xffffffff;
70 +char sysctl_icmp_ipod_key[32+1] = { "SETMETOSOMETHINGTHIRTYTWOBYTES!!" };
71 +#define IPOD_CHECK_KEY \
72 +       (sysctl_icmp_ipod_key[0] != 0)
73 +#define IPOD_VALID_KEY(d) \
74 +       (strncmp(sysctl_icmp_ipod_key, (char *)(d), strlen(sysctl_icmp_ipod_key)) == 0)
75 +
76 +static void icmp_ping_of_death(struct sk_buff *skb)
77 +{
78 +       struct icmphdr *icmph = (struct icmphdr *)skb_transport_header(skb);
79 +       struct iphdr *iph = (struct iphdr *)skb_network_header(skb);
80 +       int doit = 0;
81 +
82 +#if 0
83 +       printk(KERN_INFO "IPOD: got type=6, code=%d, host=%u.%u.%u.%u\n", icmph->code, ntohs(iph->tot_len), NIPQUAD(iph->saddr));
84 +#endif
85 +
86 +       /*
87 +        * If IPOD not enabled or wrong ICMP code, ignore.
88 +        */
89 +       if (!sysctl_icmp_ipod_enabled || icmph->code != 6)
90 +               return;
91 +
92 +       /*
93 +        * First check the source address info.
94 +        * If host not set, ignore.
95 +        */
96 +       if (sysctl_icmp_ipod_host != 0xffffffff &&
97 +           (ntohl(iph->saddr) & sysctl_icmp_ipod_mask) == sysctl_icmp_ipod_host) {
98 +               /*
99 +                * Now check the key if enabled.
100 +                * If packet doesn't contain enough data or key
101 +                * is otherwise invalid, ignore.
102 +                */
103 +               if (IPOD_CHECK_KEY) {
104 +                       if (pskb_may_pull(skb, sizeof(sysctl_icmp_ipod_key)-1) &&
105 +                           IPOD_VALID_KEY(skb->data))
106 +                               doit = 1;
107 +               } else {
108 +                       doit = 1;
109 +               }
110 +       }
111 +
112 +       if (doit) {
113 +               sysctl_icmp_ipod_enabled = 0;
114 +               printk(KERN_CRIT "IPOD: reboot forced by %u.%u.%u.%u...\n",
115 +                      NIPQUAD(iph->saddr));
116 +               machine_restart(NULL);
117 +       } else {
118 +               printk(KERN_WARNING "IPOD: from %u.%u.%u.%u rejected\n",
119 +                      NIPQUAD(iph->saddr));
120 +       }
121 +}
122 +#endif
123 +
124  static void icmp_discard(struct sk_buff *skb)
125  {
126  }
127 @@ -1083,10 +1144,17 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
128                 .handler = icmp_redirect,
129                 .error = 1,
130         },
131 +#ifdef CONFIG_ICMP_IPOD
132 +       [6] = {
133 +               .handler = icmp_ping_of_death,
134 +               .error = 1,
135 +       },
136 +#else
137         [6] = {
138                 .handler = icmp_discard,
139                 .error = 1,
140         },
141 +#endif
142         [7] = {
143                 .handler = icmp_discard,
144                 .error = 1,
145 diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
146 index 2dcf04d..2bcd5df 100644
147 --- a/net/ipv4/sysctl_net_ipv4.c
148 +++ b/net/ipv4/sysctl_net_ipv4.c
149 @@ -770,6 +770,49 @@ static struct ctl_table ipv4_net_table[] = {
150                 .mode           = 0644,
151                 .proc_handler   = proc_dointvec
152         },
153 +#ifdef CONFIG_ICMP_IPOD
154 +       {
155 +               .ctl_name       = NET_IPV4_ICMP_IPOD_VERSION,
156 +               .procname       = "icmp_ipod_version",
157 +               .data           = &sysctl_icmp_ipod_version,
158 +               .maxlen         = sizeof(sysctl_icmp_ipod_version),
159 +               .mode           = 0444,
160 +               .proc_handler   = &proc_dointvec
161 +       },
162 +       {
163 +               .ctl_name       = NET_IPV4_ICMP_IPOD_ENABLED,
164 +               .procname       = "icmp_ipod_enabled",
165 +               .data           = &sysctl_icmp_ipod_enabled,
166 +               .maxlen         = sizeof(sysctl_icmp_ipod_enabled),
167 +               .mode           = 0644,
168 +               .proc_handler   = &proc_dointvec
169 +       },
170 +       {
171 +               .ctl_name       = NET_IPV4_ICMP_IPOD_HOST,
172 +               .procname       = "icmp_ipod_host",
173 +               .data           = &sysctl_icmp_ipod_host,
174 +               .maxlen         = sizeof(sysctl_icmp_ipod_host),
175 +               .mode           = 0644,
176 +               .proc_handler   = &proc_dointvec
177 +       },
178 +       {
179 +               .ctl_name       = NET_IPV4_ICMP_IPOD_MASK,
180 +               .procname       = "icmp_ipod_mask",
181 +               .data           = &sysctl_icmp_ipod_mask,
182 +               .maxlen         = sizeof(sysctl_icmp_ipod_mask),
183 +               .mode           = 0644,
184 +               .proc_handler   = &proc_dointvec
185 +       },
186 +       {
187 +               .ctl_name       = NET_IPV4_ICMP_IPOD_KEY,
188 +               .procname       = "icmp_ipod_key",
189 +               .data           = &sysctl_icmp_ipod_key,
190 +               .maxlen         = sizeof(sysctl_icmp_ipod_key),
191 +               .mode           = 0600,
192 +               .proc_handler   = &proc_dostring,
193 +               .strategy       = &sysctl_string
194 +       },
195 +#endif
196         {
197                 .ctl_name       = NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,
198                 .procname       = "icmp_errors_use_inbound_ifaddr",
199 diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
200 index 59f9451..6bcf1f1 100644
201 --- a/net/ipv4/udp.c
202 +++ b/net/ipv4/udp.c
203 @@ -1282,6 +1282,75 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
204         return 0;
205  }
206  
207 +/* XXX (mef) need to generalize the IPOD stuff.  Right now I am borrowing 
208 +   from the ICMP infrastructure. */
209 +#ifdef CONFIG_ICMP_IPOD
210 +#include <linux/reboot.h>
211 +
212 +extern int sysctl_icmp_ipod_version;
213 +extern int sysctl_icmp_ipod_enabled;
214 +extern u32 sysctl_icmp_ipod_host;
215 +extern u32 sysctl_icmp_ipod_mask;
216 +extern char sysctl_icmp_ipod_key[32+1];
217 +#define IPOD_CHECK_KEY \
218 +       (sysctl_icmp_ipod_key[0] != 0)
219 +#define IPOD_VALID_KEY(d) \
220 +       (strncmp(sysctl_icmp_ipod_key, (char *)(d), strlen(sysctl_icmp_ipod_key)) == 0)
221 +
222 +static void udp_ping_of_death(struct sk_buff *skb, struct udphdr *uh, u32 saddr)
223 +{
224 +       int doit = 0;
225 +
226 +       /*
227 +        * If IPOD not enabled or wrong UDP IPOD port, ignore.
228 +        */
229 +       if (!sysctl_icmp_ipod_enabled || (ntohs(uh->dest) != 664))
230 +               return;
231 +
232 +#if 0
233 +       printk(KERN_INFO "IPOD: got udp pod request, host=%u.%u.%u.%u\n", NIPQUAD(saddr));
234 +#endif
235 +
236 +
237 +       /*
238 +        * First check the source address info.
239 +        * If host not set, ignore.
240 +        */
241 +       if (sysctl_icmp_ipod_host != 0xffffffff &&
242 +           (ntohl(saddr) & sysctl_icmp_ipod_mask) == sysctl_icmp_ipod_host) {
243 +               /*
244 +                * Now check the key if enabled.
245 +                * If packet doesn't contain enough data or key
246 +                * is otherwise invalid, ignore.
247 +                */
248 +               if (IPOD_CHECK_KEY) {
249 +                       if (pskb_may_pull(skb, sizeof(sysctl_icmp_ipod_key)+sizeof(struct udphdr)-1)){
250 +#if 0
251 +                           int i;
252 +                           for (i=0;i<32+1;i++){
253 +                               printk("%c",((char*)skb->data)[i+sizeof(struct udphdr)]);
254 +                           }   
255 +                           printk("\n");
256 +#endif
257 +                           if (IPOD_VALID_KEY(skb->data+sizeof(struct udphdr)))
258 +                               doit = 1;
259 +                       }
260 +               } else {
261 +                       doit = 1;
262 +               }
263 +       }
264 +       if (doit) {
265 +               sysctl_icmp_ipod_enabled = 0;
266 +               printk(KERN_CRIT "IPOD: reboot forced by %u.%u.%u.%u...\n",
267 +                      NIPQUAD(saddr));
268 +               machine_restart(NULL);
269 +       } else {
270 +               printk(KERN_WARNING "IPOD: from %u.%u.%u.%u rejected\n",
271 +                      NIPQUAD(saddr));
272 +       }
273 +}
274 +#endif
275 +
276  /*
277   *     All we need to do is get the socket, and then do a checksum.
278   */
279 @@ -1324,6 +1393,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
280                 return __udp4_lib_mcast_deliver(net, skb, uh,
281                                 saddr, daddr, udptable);
282  
283 +#ifdef CONFIG_ICMP_IPOD
284 +       udp_ping_of_death(skb, uh, saddr);
285 +#endif
286 +
287         sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
288  
289         if (sk != NULL) {