PERFORCE change 91447 for review

Rob Deker deker at FreeBSD.org
Thu Feb 9 19:13:25 GMT 2006


http://perforce.freebsd.org/chv.cgi?CH=91447

Change 91447 by deker at deker_build1.columbia.sparta.com on 2006/02/09 19:12:59

	per millert:
	
	"Make kernel-dump-to-server work properly; from plovell"
	
	Submitted by: millert

Affected files ...

.. //depot/projects/trustedbsd/sedarwin7/src/darwin/xnu/osfmk/kdp/kdp_udp.c#3 edit

Differences ...

==== //depot/projects/trustedbsd/sedarwin7/src/darwin/xnu/osfmk/kdp/kdp_udp.c#3 (text+ko) ====

@@ -23,6 +23,19 @@
  * Copyright (c) 1982, 1986, 1993
  *      The Regents of the University of California.  All rights reserved.
  */
+/*
+ * NOTICE: This file was modified by SPARTA, Inc. in 2006 to introduce
+ * support for mandatory and extensible security protections.  This notice
+ * is included in support of clause 2.2 (b) of the Apple Public License,
+ * Version 2.0.
+ */
+/*
+ * changes 2005/6 plovell
+ *    ARP for MAC address of panicd server (boot-arg _panicd_ip )
+ *    ARP for MAC address of router (boot-arg  _router_ip )
+ *    dump name includes minor version (rdar://3735061)
+ */
+
 
 /*
  * Kernel Debugging Protocol UDP implementation.
@@ -46,11 +59,40 @@
 
 #include <string.h>
 
+/* external-visible prototypes (move to external header sometime) */
+void kdp_set_interface(void *ifp);
+void *kdp_get_interface(void);
+void kdp_set_ip_and_mac_addresses(struct in_addr *ipaddr, struct ether_addr	*macaddr);
+void kdp_set_gateway_mac(void *gatewaymac);
+int kdp_send_panic_packets(unsigned int request, char *corename, unsigned int length, unsigned int txstart);
+
+/* local prototypes  - keep compiler happy :) */
+static void enaddr_copy(void *src, void	*dst);
+static unsigned short ip_sum(unsigned char*c, unsigned inthlen);
+static void kdp_reply(unsigned short reply_port);
+static void kdp_send(unsigned short remote_port);
+static int  create_arp_request(struct in_addr* ipaddr);
+static void kdp_handle_arp(void);
+static void kdp_arp_respond(void);
+static void kdp_handle_arp_reply(void);
+static void kdp_poll(void);
+static void kdp_handler(void *saved_state);
+static void kdp_connection_wait(void);
+static void kdp_send_exception(unsigned intexception, unsigned int code,  unsigned int subcode);
+static int kdp_arp_request (struct in_addr *ipaddr, struct ether_addr *macaddr);
+static int isdigit(char c);
+static int kdp_get_xnu_version(char *versionbuf);
+
+
 #define DO_ALIGN	1	/* align all packet data accesses */
 
 extern int kdp_getc(void);
 extern int reattach_wait;
+extern void kdp_call(void);
+extern unsigned int	disableConsoleOutput;
+extern boolean_t kdp_call_kdb(void);
 
+
 static u_short ip_id;                          /* ip packet ctr, for ids */
 
 /*	@(#)udp_usrreq.c	2.2 88/05/23 4.0NFSSRC SMI;	from UCB 7.1 6/5/86	*/
@@ -101,39 +143,48 @@
 static struct ether_addr kdp_current_mac_address = {{0, 0, 0, 0, 0, 0}};
 static void *kdp_current_ifp = 0;
 
-static void kdp_handler( void *);
-
 static unsigned int panic_server_ip = 0; 
 static unsigned int parsed_router_ip = 0;
 static unsigned int router_ip = 0;
 static unsigned int panicd_specified = 0;
 static unsigned int router_specified = 0;
 
+static unsigned int arp_ip = 0; 
+static struct ether_addr arp_mac = {{0, 0, 0 , 0, 0, 0}};
+
 static struct ether_addr router_mac = {{0, 0, 0 , 0, 0, 0}};
+static struct ether_addr server_mac = {{0, 0, 0 , 0, 0, 0}};
+static struct ether_addr target_mac = {{0, 0, 0 , 0, 0, 0}};
 
 static u_char flag_panic_dump_in_progress = 0;
 static u_char flag_router_mac_initialized = 0;
+static u_char flag_have_arp = 0;
 
 static unsigned int panic_timeout = 100000;
 static unsigned int last_panic_port = CORE_REMOTE_PORT;
 
 unsigned int SEGSIZE = 512;
 
-static unsigned int PANIC_PKTSIZE = 518;
+/* static unsigned int PANIC_PKTSIZE = 518; */
 static char panicd_ip_str[20];
 static char router_ip_str[20];
 
 static unsigned int panic_block = 0;
 static volatile unsigned int kdp_trigger_core_dump = 0;
+static volatile unsigned int flag_kdp_trigger_reboot = 0;
 
 extern unsigned int not_in_kdp;
 
+extern int kdp_vm_read( caddr_t, caddr_t, unsigned int);
+static u_char etherbroadcastaddr[ETHER_ADDR_LEN] =
+					{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
 void
 kdp_register_send_receive(
 	kdp_send_t	send, 
 	kdp_receive_t	receive)
 {
-	unsigned int	debug;
+	unsigned int	debug = 0;
 
 	kdp_en_send_pkt = send;
 	kdp_en_recv_pkt = receive;
@@ -162,7 +213,7 @@
 	
 	if (PE_parse_boot_arg ("_panicd_ip", panicd_ip_str))
 	  panicd_specified = 1;
-	/* For the future, currently non-functional */
+	/* functional with changes made 20060102 */
 	if (PE_parse_boot_arg ("_router_ip", router_ip_str))
 	  router_specified = 1;
 
@@ -366,8 +417,6 @@
 	struct in_addr		*ipaddr, 
 	struct ether_addr	*macaddr)
 {
-	unsigned int debug = 0;
-
 	kdp_current_ip_address = ipaddr->s_addr;
 	kdp_current_mac_address = *macaddr;
 }
@@ -376,6 +425,8 @@
 kdp_set_gateway_mac(void *gatewaymac)
 {
   router_mac = *(struct ether_addr *)gatewaymac;
+  target_mac = *(struct ether_addr *)gatewaymac;
+  flag_router_mac_initialized = 1;
 } 
 
 struct ether_addr 
@@ -390,13 +441,94 @@
   return kdp_current_ip_address;
 }
 
+/* ARP request builder. Note that this saves the ip address
+ * we want for the use of kdp_handle_arp_reply
+*/
+static int 
+create_arp_request(struct in_addr* ipaddr)
+{
+	struct ether_header	header;
+	struct ether_header	*eh = &header;
+	struct ether_arp	aligned_ea, *ea = &aligned_ea;
+
+	struct in_addr 		myaddr;
+	struct ether_addr	my_enaddr;
+	
+	unsigned long wk;
+	wk = ntohl(ipaddr->s_addr);
+/*	printf("request arp for IP %d.%d.%d.%d\n",
+		(wk & 0xff000000) >> 24,
+		(wk & 0x00ff0000) >> 16,
+		(wk & 0x0000ff00) >>  8,
+		(wk & 0x000000ff)       ); */
+
+	myaddr.s_addr = kdp_get_ip_address();
+	my_enaddr = kdp_get_mac_addr();
+
+	if (!(myaddr.s_addr) || !(my_enaddr.ether_addr_octet[1]))
+		return 1;
+
+	/* lay out ether header fields */
+	memcpy( eh->ether_dhost, etherbroadcastaddr, sizeof(struct ether_addr));
+	memcpy( eh->ether_shost, (void*)&my_enaddr, sizeof(struct ether_addr) );
+	eh->ether_type = htons(ETHERTYPE_ARP);
+	
+	/* now the arp request header */
+	ea->arp_hrd = htons(ARPHRD_ETHER);
+	ea->arp_pro = htons(ETHERTYPE_IP);
+	ea->arp_hln = sizeof(ea->arp_sha);
+	ea->arp_pln = sizeof(ea->arp_spa);
+	ea->arp_op = htons(ARPOP_REQUEST);
+	
+	/* sender addresses (us) */
+	memcpy(ea->arp_sha, (void *)&my_enaddr, sizeof(ea->arp_sha));
+	memcpy(ea->arp_spa, (void *)&myaddr, sizeof(ea->arp_spa));
+	
+	/* target addresses */
+	memcpy(ea->arp_tha, etherbroadcastaddr, sizeof(struct ether_addr));
+	memcpy(ea->arp_tpa, (void *)ipaddr, sizeof(ea->arp_tpa));
+	
+	pkt.len = 0;
+	pkt.off = 0;
+	memcpy( &pkt.data[pkt.off], eh, sizeof(struct ether_header) );
+	pkt.len += sizeof(struct ether_header);
+	pkt.off += pkt.len;
+	memcpy( &pkt.data[pkt.off], ea, sizeof(struct ether_arp) );
+	pkt.len += sizeof(struct ether_arp);
+	pkt.off = 0;
+	
+	return 0;
+}
+
 /* ARP responses are enabled when the DB_ARP bit of the debug boot arg
    is set. A workaround if you don't want to reboot is to set 
    kdpDEBUGFlag &= DB_ARP when connected (but that certainly isn't a published
    interface!)
 */
 static void 
-kdp_arp_reply(void)
+kdp_handle_arp(void)
+{
+	struct ether_arp	aligned_ea, *ea = &aligned_ea;
+	int offset = sizeof(struct ether_header);
+
+	memcpy((void *)ea, (void *)&pkt.data[offset],sizeof(*ea));
+  
+	if( (kdp_flag & KDP_ARP) && (ntohs(ea->arp_op) == ARPOP_REQUEST) )
+	  kdp_arp_respond();
+	else if(ntohs(ea->arp_op) == ARPOP_REPLY)
+	  kdp_handle_arp_reply();
+	  
+	return;
+
+}
+
+/* ARP responses are enabled when the DB_ARP bit of the debug boot arg
+   is set. A workaround if you don't want to reboot is to set 
+   kdpDEBUGFlag &= DB_ARP when connected (but that certainly isn't a published
+   interface!)
+*/
+static void 
+kdp_arp_respond(void)
 {
 	struct ether_header	*eh;
 	struct ether_arp	aligned_ea, *ea = &aligned_ea;
@@ -440,6 +572,30 @@
 	}
 }
 
+/* We have an ARP reply. Maybe we are waiting for one??
+ * Handle it if we are, else ignore it.
+ */
+static void 
+kdp_handle_arp_reply(void)
+{
+	struct ether_arp	aligned_ea, *ea = &aligned_ea;
+
+	pkt.off = sizeof(struct ether_header);
+	memcpy((void *)ea, (void *)&pkt.data[pkt.off],sizeof(*ea));
+  
+	if(ntohs(ea->arp_op) != ARPOP_REPLY)
+	  return;
+
+	if(  ((struct in_addr *)(ea->arp_spa))->s_addr != arp_ip) /* not the one we want */
+	  return;
+
+	arp_mac = *(struct ether_addr*)(ea->arp_sha);
+	flag_have_arp = 1;
+	/* printf("kdp_handle_arp_reply set flag_have_arp\n"); */
+	
+	return;
+}
+
 static void
 kdp_poll(void)
 {
@@ -470,15 +626,13 @@
       {
 	eh = (struct ether_header *)&pkt.data[pkt.off];  
 	
-	if (kdp_flag & KDP_ARP)
-	  {
+		/* testing for KDP_ARP now done in kdp_handle_arp() */
 	    if (ntohs(eh->ether_type) == ETHERTYPE_ARP)
 	      {
-		kdp_arp_reply();
+		kdp_handle_arp();
 		return;
 	      }
 	  }
-      }
 
     if (pkt.len < (sizeof (struct ether_header) + sizeof (struct udpiphdr)))
     	return;
@@ -595,10 +749,11 @@
 kdp_connection_wait(void)
 {
 	unsigned short		reply_port;
-	boolean_t		kdp_call_kdb();
-	struct ether_addr	kdp_mac_addr = kdp_get_mac_addr();
-	unsigned int		ip_addr = ntohl(kdp_get_ip_address());
+	struct ether_addr	kdp_mac_addr;
+	unsigned int		ip_addr;
 
+	kdp_mac_addr = kdp_get_mac_addr();
+	ip_addr = ntohl(kdp_get_ip_address());
 	printf( "ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
             kdp_mac_addr.ether_addr_octet[0] & 0xff,
             kdp_mac_addr.ether_addr_octet[1] & 0xff,
@@ -751,7 +906,6 @@
     int			index;
 
     extern unsigned int disableDebugOuput;
-    extern unsigned int disableConsoleOutput;
 
     disable_preemption();
 
@@ -826,6 +980,16 @@
 	kdp_panic_dump();
       }
 
+/* Trigger a reboot if the user has set this flag through the
+ * debugger.Ideally, this would be done through the HOSTREBOOT packet
+ * in the protocol,but that will need gdb support,and when it's
+ * available, it should work automatically.
+ */
+    if (1 == flag_kdp_trigger_reboot) {
+	    kdp_reboot();
+	    /* If we're still around, reset the flag */
+	    flag_kdp_trigger_reboot = 0;
+    }
     kdp_sync_cache();
 
     if (reattach_wait == 1)
@@ -918,7 +1082,7 @@
 
   eh = (struct ether_header *)&pkt.data[pkt.off];
   enaddr_copy(&kdp_current_mac_address, eh->ether_shost);
-  enaddr_copy(&router_mac, eh->ether_dhost);
+  enaddr_copy(&target_mac, eh->ether_dhost);
   eh->ether_type = htons(ETHERTYPE_IP);
     
   pkt.len += sizeof (struct ether_header);
@@ -952,6 +1116,7 @@
 	kdp_send_panic_pkt(request, corename, (txend - txstart), (caddr_t) txstart);
       }
     }
+    return 0;
 }
 
 int 
@@ -1054,6 +1219,108 @@
   return 1;
 }
 
+static int 
+kdp_arp_request (
+	struct in_addr		*ipaddr, 
+	struct ether_addr	*macaddr)
+{
+  struct corehdr *th = NULL;
+  int poll_count = 2500;
+  int err = 0;
+  
+  char rretries = 0, tretries = 0;
+  /*
+  extern signed long gIODebuggerSemaphore;
+  */
+  pkt.off = pkt.len = 0;
+  
+TRANSMIT_RETRY:
+  tretries++;
+
+  if (tretries > 2)
+    printf("TX arp retry #%d ", tretries );
+  
+  if (tretries >=15) {
+    /* This iokit layer issue can potentially 
+     *cause a hang, uncomment to check if it's happening.
+     */
+    /*
+      if (gIODebuggerSemaphore)
+      printf("The gIODebuggerSemaphore is raised, preventing packet transmission (2760413)\n");
+    */
+    
+    printf ("Cannot arp panic server, timing out.\n");
+    return (-3);
+  }
+  
+  err = create_arp_request(ipaddr);
+  if ( err != 0 ) {
+    printf("create arp request failed\n");
+    return (-4);
+  }
+  
+  arp_ip = ipaddr->s_addr;
+  flag_have_arp = 0;
+  
+
+
+  (*kdp_en_send_pkt)(&pkt.data[pkt.off], pkt.len);
+
+  /* Now we have to listen for the ACK */
+ RECEIVE_RETRY:
+
+  while (!pkt.input && flag_panic_dump_in_progress && poll_count) {
+      kdp_poll();
+      poll_count--;
+      if ( flag_have_arp ) {
+      	*macaddr = arp_mac;
+      	return 0;
+      }
+    }
+
+  if (pkt.input) {
+    
+    pkt.input = FALSE;
+    
+    th = (struct corehdr *) &pkt.data[pkt.off];
+    /* These will eventually have to be ntoh[ls]'ed as appropriate */
+    
+    if (th->th_opcode == KDP_ACK && th->th_block == panic_block) {
+    }
+    else
+      if (th->th_opcode == KDP_ERROR) {
+	printf("Panic server returned error %d, retrying\n", th->th_code);
+	poll_count = 1000;
+	goto TRANSMIT_RETRY;
+      }
+      else 
+	if (th->th_block == (panic_block -1)) {
+	  printf("RX retry ");
+	  if (++rretries > 1)
+	    goto TRANSMIT_RETRY;
+	  else
+	    goto RECEIVE_RETRY;
+	}
+  }
+  else
+    if (!flag_panic_dump_in_progress) /* we received a debugging packet, bail*/
+      {
+	printf("Received a debugger packet,transferring control to debugger\n");
+	/* Configure that if not set ..*/
+	kdp_flag |= DBG_POST_CORE;
+	return (-2);
+      }
+    else /* We timed out */
+      if (0 == poll_count) {
+	poll_count = 1000;
+	kdp_us_spin ((tretries%4) * panic_timeout); /* capped linear backoff */
+	goto TRANSMIT_RETRY;
+      }
+  
+  
+  return 1;
+}
+
 /* Since we don't seem to have an isdigit() .. */
 static int 
 isdigit (char c)
@@ -1090,6 +1357,19 @@
  * xnu version into a string or an int somewhere at project submission
  * time - makes assumptions about sizeof(version), but will not fail if
  * it changes, but may be incorrect.
+ *
+ * Changed 20060102 to allow a more complete version number, including
+ * minor version. It will now look something like xnu-792.6.22
+ * (hopefully fixes radar 3735061)
+ *
+ * The only use of this routine provides the packet buffer as the
+ * data buffer (versionbuf) which is just as well, as there's
+ * no size checking done. That buffer is >1500
+ * The fetched size used to be 90 but that's quite close to the end
+ * of the name so now it's up to 100. The version string is a system-wide
+ * global, defined in version.c in each darwin build. The content is
+ * similar to ...
+ * "Darwin Kernel Version 8.3.0: Thu Dec 29 06:13:35 PST 2005; root:xnu-792.6.22.obj/RELEASE_PPC"
  */
  
 static int 
@@ -1097,20 +1377,30 @@
 {
   extern const char version[];
   char *versionpos;
-  char vstr[10];
+  char vstr[20];
   int retval = -1;
+  char*	ptr;
 
   strcpy(vstr, "custom");
    if (version) { 
-       if (kdp_vm_read(version, versionbuf, 90)) {
+       if (kdp_vm_read(version, versionbuf, 100)) {
 
- 	   versionbuf[89] = '\0'; 
+ 	   versionbuf[99] = '\0'; 
 	   
-	   versionpos = strnstr(versionbuf, "xnu-", 80);
+	   versionpos = strnstr(versionbuf, "xnu-", 90);
 
 	   if (versionpos) {
-	     strncpy (vstr, versionpos, (isdigit (versionpos[7]) ? 8 : 7));
-	     vstr[(isdigit (versionpos[7]) ? 8 : 7)] = '\0';
+	     strncpy(vstr, versionpos, sizeof(vstr));
+	     vstr[sizeof(vstr)-1] = '\0';	/* terminate */
+	     
+	     ptr = vstr + 4;	/* start after "xnu-" */
+	     while ( isdigit(*ptr) || (*ptr == '.') )
+	     	ptr++;
+	     
+	     *ptr = '\0';	/* terminate */
+	     if ( *(--ptr) == '.' )		/* if period is last */
+	     	*ptr = '\0';			/* then remove trailing period */
+	     
 	     retval = 0;
 	   }
        }
@@ -1118,20 +1408,19 @@
    strcpy(versionbuf, vstr);
    return retval;
 }
+
 /* Primary dispatch routine for the system dump */
 void 
 kdp_panic_dump()
 {
-  char corename[50];
+  char corename[64];
   char coreprefix[10];
   int panic_error;
-  extern char *debug_buf;
+  int err = 0;
   extern vm_map_t kernel_map;
 
   extern char *inet_aton(const char *cp, struct in_addr *pin);
 
-  extern char *debug_buf;
-  extern char *debug_buf_ptr;
   uint64_t abstime;
 
   printf ("Entering system dump routine\n");
@@ -1156,7 +1445,7 @@
     strncpy(coreprefix, "core", sizeof(coreprefix));
   
   abstime = mach_absolute_time();
-  pkt.data[10] = '\0';
+  pkt.data[20] = '\0';	/* limit file name length to something reasonable */
   snprintf (corename, sizeof(corename), "%s-%s-%d.%d.%d.%d-%x", 
 	    coreprefix, &pkt.data[0],
 	   (kdp_current_ip_address & 0xff000000) >> 24,
@@ -1173,32 +1462,57 @@
     printf("Attempting connection to panic server configured at IP %s\n", 
 	   panicd_ip_str);
 
+    /* first try to ARP the dump server */
+
+    err = kdp_arp_request((struct in_addr *) &panic_server_ip, &server_mac);
+    if ( err >= 0 ) {
+	target_mac = server_mac;
+	  printf("kdump server MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
+		  target_mac.ether_addr_octet[0] & 0xff,
+		  target_mac.ether_addr_octet[1] & 0xff,
+		  target_mac.ether_addr_octet[2] & 0xff,
+		  target_mac.ether_addr_octet[3] & 0xff,
+		  target_mac.ether_addr_octet[4] & 0xff,
+		  target_mac.ether_addr_octet[5] & 0xff);
+	
+    }
+    else
+    {
+	  if ( err == -3 )
+		printf ("No arp response for panic server.\n");
+
   if (router_specified) {
       if (0 == inet_aton(router_ip_str, (struct in_addr *) &parsed_router_ip)){
 	  printf("inet_aton() failed interpreting %s as an IP\n", router_ip);
 	}
       else {
 	  router_ip = parsed_router_ip;
-	  printf("Routing through specified router IP %s (%d)\n", router_ip_str, router_ip);
-	  /* We will eventually need to resolve the router's MAC ourselves,
-	   * if one is specified,rather than being set through the BSD callback
-	   * but the _router_ip option does not function currently
+	  printf("Trying specified router IP %s\n", router_ip_str);
+	  /* Resolve the router's MAC, as specified in the _router_ip option.
+	   * If it doesn't resolve, use the one set through the BSD callback
+	   * in kdp_set_gateway_mac
 	   */
+	  err = kdp_arp_request((struct in_addr *) &router_ip, &server_mac);
+	  if ( err >= 0 ) 
+	    target_mac = server_mac;
+	  else if ( err == -3 )
+	    printf ("No arp response for panic server.\n");
 	}
     }
-  /* These & 0xffs aren't necessary,but cut&paste is ever so convenient */
+
   printf("Routing via router MAC address: %02x:%02x:%02x:%02x:%02x:%02x\n",
-	  router_mac.ether_addr_octet[0] & 0xff,
-	  router_mac.ether_addr_octet[1] & 0xff,
-	  router_mac.ether_addr_octet[2] & 0xff,
-	  router_mac.ether_addr_octet[3] & 0xff,
-	  router_mac.ether_addr_octet[4] & 0xff,
-	  router_mac.ether_addr_octet[5] & 0xff);
+	  target_mac.ether_addr_octet[0] & 0xff,
+	  target_mac.ether_addr_octet[1] & 0xff,
+	  target_mac.ether_addr_octet[2] & 0xff,
+	  target_mac.ether_addr_octet[3] & 0xff,
+	  target_mac.ether_addr_octet[4] & 0xff,
+	  target_mac.ether_addr_octet[5] & 0xff);
+  }
 
-  printf("Kernel map size is %d\n", get_vmmap_size(kernel_map));
+  printf("Kernel map size is %ld\n", get_vmmap_size(kernel_map));
   printf ("Sending write request for %s\n", corename);  
 
-  if ((panic_error = kdp_send_panic_pkt (KDP_WRQ, corename, 0 , NULL) < 0)) {
+  if ((panic_error = kdp_send_panic_pkt (KDP_WRQ, corename, 0 , NULL)) < 0) {
       printf ("kdp_send_panic_pkt failed with error %d\n", panic_error);
       goto panic_dump_exit;
     }
To Unsubscribe: send mail to majordomo at trustedbsd.org
with "unsubscribe trustedbsd-cvs" in the body of the message



More information about the trustedbsd-cvs mailing list