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