adjust planetlab patchset against RHEL kernel
[linux-2.6.git] / linux-2.6-510-ipod.patch
diff --git a/linux-2.6-510-ipod.patch b/linux-2.6-510-ipod.patch
new file mode 100644 (file)
index 0000000..0174ac7
--- /dev/null
@@ -0,0 +1,289 @@
+diff --git a/include/linux/sysctl.h b/include/linux/sysctl.h
+index 0344615..dc0f0d8 100644
+--- a/include/linux/sysctl.h
++++ b/include/linux/sysctl.h
+@@ -436,6 +436,13 @@ enum
+       NET_TCP_ALLOWED_CONG_CONTROL=123,
+       NET_TCP_MAX_SSTHRESH=124,
+       NET_TCP_FRTO_RESPONSE=125,
++#ifdef CONFIG_ICMP_IPOD
++      NET_IPV4_ICMP_IPOD_VERSION,
++      NET_IPV4_ICMP_IPOD_ENABLED,
++      NET_IPV4_ICMP_IPOD_HOST,
++      NET_IPV4_ICMP_IPOD_MASK,
++      NET_IPV4_ICMP_IPOD_KEY
++#endif
+ };
+ enum {
+diff --git a/include/net/icmp.h b/include/net/icmp.h
+index dfa72d4..55cdc47 100644
+--- a/include/net/icmp.h
++++ b/include/net/icmp.h
+@@ -59,4 +59,12 @@ static inline struct raw_sock *raw_sk(const struct sock *sk)
+       return (struct raw_sock *)sk;
+ }
++#ifdef CONFIG_ICMP_IPOD
++extern int sysctl_icmp_ipod_version;
++extern int sysctl_icmp_ipod_enabled;
++extern u32 sysctl_icmp_ipod_host;
++extern u32 sysctl_icmp_ipod_mask;
++extern char sysctl_icmp_ipod_key[32+1];
++#endif
++
+ #endif        /* _ICMP_H */
+diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig
+index 0c94a1a..31a67cc 100644
+--- a/net/ipv4/Kconfig
++++ b/net/ipv4/Kconfig
+@@ -627,3 +627,14 @@ config TCP_MD5SIG
+         If unsure, say N.
++#
++# Emulab special
++#
++
++config ICMP_IPOD
++      bool "ICMP: ICMP Ping-of-Death (Emulab)"
++      depends on INET && SYSCTL
++      ---help---
++          Support immediately rebooting upon receiving a specially
++        formed ICMP type 6 packet whose payload matches a string
++        configured by the administrator.
+diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c
+index 5bc13fe..5324406 100644
+--- a/net/ipv4/icmp.c
++++ b/net/ipv4/icmp.c
+@@ -960,6 +960,67 @@ static void icmp_address_reply(struct sk_buff *skb)
+ out:;
+ }
++#ifdef CONFIG_ICMP_IPOD
++#include <linux/reboot.h>
++
++int sysctl_icmp_ipod_version = 2;
++int sysctl_icmp_ipod_enabled = 0;
++u32 sysctl_icmp_ipod_host = 0xffffffff;
++u32 sysctl_icmp_ipod_mask = 0xffffffff;
++char sysctl_icmp_ipod_key[32+1] = { "SETMETOSOMETHINGTHIRTYTWOBYTES!!" };
++#define IPOD_CHECK_KEY \
++      (sysctl_icmp_ipod_key[0] != 0)
++#define IPOD_VALID_KEY(d) \
++      (strncmp(sysctl_icmp_ipod_key, (char *)(d), strlen(sysctl_icmp_ipod_key)) == 0)
++
++static void icmp_ping_of_death(struct sk_buff *skb)
++{
++      struct icmphdr *icmph = (struct icmphdr *)skb_transport_header(skb);
++      struct iphdr *iph = (struct iphdr *)skb_network_header(skb);
++      int doit = 0;
++
++#if 0
++      printk(KERN_INFO "IPOD: got type=6, code=%d, host=%u.%u.%u.%u\n", icmph->code, ntohs(iph->tot_len), NIPQUAD(iph->saddr));
++#endif
++
++      /*
++       * If IPOD not enabled or wrong ICMP code, ignore.
++       */
++      if (!sysctl_icmp_ipod_enabled || icmph->code != 6)
++              return;
++
++      /*
++       * First check the source address info.
++       * If host not set, ignore.
++       */
++      if (sysctl_icmp_ipod_host != 0xffffffff &&
++          (ntohl(iph->saddr) & sysctl_icmp_ipod_mask) == sysctl_icmp_ipod_host) {
++              /*
++               * Now check the key if enabled.
++               * If packet doesn't contain enough data or key
++               * is otherwise invalid, ignore.
++               */
++              if (IPOD_CHECK_KEY) {
++                      if (pskb_may_pull(skb, sizeof(sysctl_icmp_ipod_key)-1) &&
++                          IPOD_VALID_KEY(skb->data))
++                              doit = 1;
++              } else {
++                      doit = 1;
++              }
++      }
++
++      if (doit) {
++              sysctl_icmp_ipod_enabled = 0;
++              printk(KERN_CRIT "IPOD: reboot forced by %u.%u.%u.%u...\n",
++                     NIPQUAD(iph->saddr));
++              machine_restart(NULL);
++      } else {
++              printk(KERN_WARNING "IPOD: from %u.%u.%u.%u rejected\n",
++                     NIPQUAD(iph->saddr));
++      }
++}
++#endif
++
+ static void icmp_discard(struct sk_buff *skb)
+ {
+ }
+@@ -1083,10 +1144,17 @@ static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = {
+               .handler = icmp_redirect,
+               .error = 1,
+       },
++#ifdef CONFIG_ICMP_IPOD
++      [6] = {
++              .handler = icmp_ping_of_death,
++              .error = 1,
++      },
++#else
+       [6] = {
+               .handler = icmp_discard,
+               .error = 1,
+       },
++#endif
+       [7] = {
+               .handler = icmp_discard,
+               .error = 1,
+diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
+index 2dcf04d..2bcd5df 100644
+--- a/net/ipv4/sysctl_net_ipv4.c
++++ b/net/ipv4/sysctl_net_ipv4.c
+@@ -770,6 +770,49 @@ static struct ctl_table ipv4_net_table[] = {
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec
+       },
++#ifdef CONFIG_ICMP_IPOD
++      {
++              .ctl_name       = NET_IPV4_ICMP_IPOD_VERSION,
++              .procname       = "icmp_ipod_version",
++              .data           = &sysctl_icmp_ipod_version,
++              .maxlen         = sizeof(sysctl_icmp_ipod_version),
++              .mode           = 0444,
++              .proc_handler   = &proc_dointvec
++      },
++      {
++              .ctl_name       = NET_IPV4_ICMP_IPOD_ENABLED,
++              .procname       = "icmp_ipod_enabled",
++              .data           = &sysctl_icmp_ipod_enabled,
++              .maxlen         = sizeof(sysctl_icmp_ipod_enabled),
++              .mode           = 0644,
++              .proc_handler   = &proc_dointvec
++      },
++      {
++              .ctl_name       = NET_IPV4_ICMP_IPOD_HOST,
++              .procname       = "icmp_ipod_host",
++              .data           = &sysctl_icmp_ipod_host,
++              .maxlen         = sizeof(sysctl_icmp_ipod_host),
++              .mode           = 0644,
++              .proc_handler   = &proc_dointvec
++      },
++      {
++              .ctl_name       = NET_IPV4_ICMP_IPOD_MASK,
++              .procname       = "icmp_ipod_mask",
++              .data           = &sysctl_icmp_ipod_mask,
++              .maxlen         = sizeof(sysctl_icmp_ipod_mask),
++              .mode           = 0644,
++              .proc_handler   = &proc_dointvec
++      },
++      {
++              .ctl_name       = NET_IPV4_ICMP_IPOD_KEY,
++              .procname       = "icmp_ipod_key",
++              .data           = &sysctl_icmp_ipod_key,
++              .maxlen         = sizeof(sysctl_icmp_ipod_key),
++              .mode           = 0600,
++              .proc_handler   = &proc_dostring,
++              .strategy       = &sysctl_string
++      },
++#endif
+       {
+               .ctl_name       = NET_IPV4_ICMP_ERRORS_USE_INBOUND_IFADDR,
+               .procname       = "icmp_errors_use_inbound_ifaddr",
+diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
+index 59f9451..6bcf1f1 100644
+--- a/net/ipv4/udp.c
++++ b/net/ipv4/udp.c
+@@ -1282,6 +1282,75 @@ static inline int udp4_csum_init(struct sk_buff *skb, struct udphdr *uh,
+       return 0;
+ }
++/* XXX (mef) need to generalize the IPOD stuff.  Right now I am borrowing 
++   from the ICMP infrastructure. */
++#ifdef CONFIG_ICMP_IPOD
++#include <linux/reboot.h>
++
++extern int sysctl_icmp_ipod_version;
++extern int sysctl_icmp_ipod_enabled;
++extern u32 sysctl_icmp_ipod_host;
++extern u32 sysctl_icmp_ipod_mask;
++extern char sysctl_icmp_ipod_key[32+1];
++#define IPOD_CHECK_KEY \
++      (sysctl_icmp_ipod_key[0] != 0)
++#define IPOD_VALID_KEY(d) \
++      (strncmp(sysctl_icmp_ipod_key, (char *)(d), strlen(sysctl_icmp_ipod_key)) == 0)
++
++static void udp_ping_of_death(struct sk_buff *skb, struct udphdr *uh, u32 saddr)
++{
++      int doit = 0;
++
++      /*
++       * If IPOD not enabled or wrong UDP IPOD port, ignore.
++       */
++      if (!sysctl_icmp_ipod_enabled || (ntohs(uh->dest) != 664))
++              return;
++
++#if 0
++      printk(KERN_INFO "IPOD: got udp pod request, host=%u.%u.%u.%u\n", NIPQUAD(saddr));
++#endif
++
++
++      /*
++       * First check the source address info.
++       * If host not set, ignore.
++       */
++      if (sysctl_icmp_ipod_host != 0xffffffff &&
++          (ntohl(saddr) & sysctl_icmp_ipod_mask) == sysctl_icmp_ipod_host) {
++              /*
++               * Now check the key if enabled.
++               * If packet doesn't contain enough data or key
++               * is otherwise invalid, ignore.
++               */
++              if (IPOD_CHECK_KEY) {
++                      if (pskb_may_pull(skb, sizeof(sysctl_icmp_ipod_key)+sizeof(struct udphdr)-1)){
++#if 0
++                          int i;
++                          for (i=0;i<32+1;i++){
++                              printk("%c",((char*)skb->data)[i+sizeof(struct udphdr)]);
++                          }   
++                          printk("\n");
++#endif
++                          if (IPOD_VALID_KEY(skb->data+sizeof(struct udphdr)))
++                              doit = 1;
++                      }
++              } else {
++                      doit = 1;
++              }
++      }
++      if (doit) {
++              sysctl_icmp_ipod_enabled = 0;
++              printk(KERN_CRIT "IPOD: reboot forced by %u.%u.%u.%u...\n",
++                     NIPQUAD(saddr));
++              machine_restart(NULL);
++      } else {
++              printk(KERN_WARNING "IPOD: from %u.%u.%u.%u rejected\n",
++                     NIPQUAD(saddr));
++      }
++}
++#endif
++
+ /*
+  *    All we need to do is get the socket, and then do a checksum.
+  */
+@@ -1324,6 +1393,10 @@ int __udp4_lib_rcv(struct sk_buff *skb, struct udp_table *udptable,
+               return __udp4_lib_mcast_deliver(net, skb, uh,
+                               saddr, daddr, udptable);
++#ifdef CONFIG_ICMP_IPOD
++      udp_ping_of_death(skb, uh, saddr);
++#endif
++
+       sk = __udp4_lib_lookup_skb(skb, uh->source, uh->dest, udptable);
+       if (sk != NULL) {