Setting tag linux-2.6-27-38
[linux-2.6.git] / linux-2.6-510-ipod.patch
1 Index: linux-2.6.27.y/include/linux/sysctl.h
2 ===================================================================
3 --- linux-2.6.27.y.orig/include/linux/sysctl.h
4 +++ linux-2.6.27.y/include/linux/sysctl.h
5 @@ -437,6 +437,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 Index: linux-2.6.27.y/include/net/icmp.h
20 ===================================================================
21 --- linux-2.6.27.y.orig/include/net/icmp.h
22 +++ linux-2.6.27.y/include/net/icmp.h
23 @@ -59,4 +59,12 @@ static inline struct raw_sock *raw_sk(co
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 Index: linux-2.6.27.y/net/ipv4/icmp.c
37 ===================================================================
38 --- linux-2.6.27.y.orig/net/ipv4/icmp.c
39 +++ linux-2.6.27.y/net/ipv4/icmp.c
40 @@ -962,6 +962,67 @@ static void icmp_address_reply(struct sk
41  out:;
42  }
43  
44 +#ifdef CONFIG_ICMP_IPOD
45 +#include <linux/reboot.h>
46 +
47 +int sysctl_icmp_ipod_version = 2;
48 +int sysctl_icmp_ipod_enabled = 0;
49 +u32 sysctl_icmp_ipod_host = 0xffffffff;
50 +u32 sysctl_icmp_ipod_mask = 0xffffffff;
51 +char sysctl_icmp_ipod_key[32+1] = { "SETMETOSOMETHINGTHIRTYTWOBYTES!!" };
52 +#define IPOD_CHECK_KEY \
53 +       (sysctl_icmp_ipod_key[0] != 0)
54 +#define IPOD_VALID_KEY(d) \
55 +       (strncmp(sysctl_icmp_ipod_key, (char *)(d), strlen(sysctl_icmp_ipod_key)) == 0)
56 +
57 +static void icmp_ping_of_death(struct sk_buff *skb)
58 +{
59 +       struct icmphdr *icmph = (struct icmphdr *)skb_transport_header(skb);
60 +       struct iphdr *iph = (struct iphdr *)skb_network_header(skb);
61 +       int doit = 0;
62 +
63 +#if 0
64 +       printk(KERN_INFO "IPOD: got type=6, code=%d, host=%u.%u.%u.%u\n", icmph->code, ntohs(iph->tot_len), NIPQUAD(iph->saddr));
65 +#endif
66 +
67 +       /*
68 +        * If IPOD not enabled or wrong ICMP code, ignore.
69 +        */
70 +       if (!sysctl_icmp_ipod_enabled || icmph->code != 6)
71 +               return;
72 +
73 +       /*
74 +        * First check the source address info.
75 +        * If host not set, ignore.
76 +        */
77 +       if (sysctl_icmp_ipod_host != 0xffffffff &&
78 +           (ntohl(iph->saddr) & sysctl_icmp_ipod_mask) == sysctl_icmp_ipod_host) {
79 +               /*
80 +                * Now check the key if enabled.
81 +                * If packet doesn't contain enough data or key
82 +                * is otherwise invalid, ignore.
83 +                */
84 +               if (IPOD_CHECK_KEY) {
85 +                       if (pskb_may_pull(skb, sizeof(sysctl_icmp_ipod_key)-1) &&
86 +                           IPOD_VALID_KEY(skb->data))
87 +                               doit = 1;
88 +               } else {
89 +                       doit = 1;
90 +               }
91 +       }
92 +
93 +       if (doit) {
94 +               sysctl_icmp_ipod_enabled = 0;
95 +               printk(KERN_CRIT "IPOD: reboot forced by %u.%u.%u.%u...\n",
96 +                      NIPQUAD(iph->saddr));
97 +               machine_restart(NULL);
98 +       } else {
99 +               printk(KERN_WARNING "IPOD: from %u.%u.%u.%u rejected\n",
100 +                      NIPQUAD(iph->saddr));
101 +       }
102 +}
103 +#endif
104 +
105  static void icmp_discard(struct sk_buff *skb)
106  {
107  }
108 @@ -1084,10 +1145,17 @@ static const struct icmp_control icmp_po
109                 .handler = icmp_redirect,
110                 .error = 1,
111         },
112 +#ifdef CONFIG_ICMP_IPOD
113 +       [6] = {
114 +               .handler = icmp_ping_of_death,
115 +               .error = 1,
116 +       },
117 +#else
118         [6] = {
119                 .handler = icmp_discard,
120                 .error = 1,
121         },
122 +#endif
123         [7] = {
124                 .handler = icmp_discard,
125                 .error = 1,
126 Index: linux-2.6.27.y/net/ipv4/Kconfig
127 ===================================================================
128 --- linux-2.6.27.y.orig/net/ipv4/Kconfig
129 +++ linux-2.6.27.y/net/ipv4/Kconfig
130 @@ -632,3 +632,14 @@ config TCP_MD5SIG
131  
132  source "net/ipv4/ipvs/Kconfig"
133  
134 +#
135 +# Emulab special
136 +#
137 +
138 +config ICMP_IPOD
139 +       bool "ICMP: ICMP Ping-of-Death (Emulab)"
140 +       depends on INET && SYSCTL
141 +       ---help---
142 +          Support immediately rebooting upon receiving a specially
143 +         formed ICMP type 6 packet whose payload matches a string
144 +         configured by the administrator.
145 Index: linux-2.6.27.y/net/ipv4/sysctl_net_ipv4.c
146 ===================================================================
147 --- linux-2.6.27.y.orig/net/ipv4/sysctl_net_ipv4.c
148 +++ linux-2.6.27.y/net/ipv4/sysctl_net_ipv4.c
149 @@ -773,6 +773,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 Index: linux-2.6.27.y/net/ipv4/udp.c
200 ===================================================================
201 --- linux-2.6.27.y.orig/net/ipv4/udp.c
202 +++ linux-2.6.27.y/net/ipv4/udp.c
203 @@ -1173,6 +1173,75 @@ static inline int udp4_csum_init(struct 
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 @@ -1213,6 +1282,9 @@ int __udp4_lib_rcv(struct sk_buff *skb, 
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         sk = __udp4_lib_lookup(net, saddr, uh->source, daddr,
287                         uh->dest, inet_iif(skb), udptable);
288