Index: pbx/pbx_loopback.c
===================================================================
--- pbx/pbx_loopback.c	(revision 39030)
+++ pbx/pbx_loopback.c	(working copy)
@@ -43,7 +43,6 @@
 #include "asterisk/file.h"
 #include "asterisk/cli.h"
 #include "asterisk/lock.h"
-#include "asterisk/md5.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/chanvars.h"
 #include "asterisk/sched.h"
Index: pbx/pbx_realtime.c
===================================================================
--- pbx/pbx_realtime.c	(revision 39030)
+++ pbx/pbx_realtime.c	(working copy)
@@ -46,7 +46,6 @@
 #include "asterisk/file.h"
 #include "asterisk/cli.h"
 #include "asterisk/lock.h"
-#include "asterisk/md5.h"
 #include "asterisk/linkedlists.h"
 #include "asterisk/chanvars.h"
 #include "asterisk/sched.h"
Index: pbx/pbx_dundi.c
===================================================================
--- pbx/pbx_dundi.c	(revision 39030)
+++ pbx/pbx_dundi.c	(working copy)
@@ -63,7 +63,6 @@
 #include "asterisk/file.h"
 #include "asterisk/cli.h"
 #include "asterisk/lock.h"
-#include "asterisk/md5.h"
 #include "asterisk/dundi.h"
 #include "asterisk/sched.h"
 #include "asterisk/io.h"
Index: channels/chan_sip.c
===================================================================
--- channels/chan_sip.c	(revision 39030)
+++ channels/chan_sip.c	(working copy)
@@ -132,6 +132,7 @@
 #include "asterisk/astdb.h"
 #include "asterisk/causes.h"
 #include "asterisk/utils.h"
+#include "asterisk/md5.h"
 #include "asterisk/file.h"
 #include "asterisk/astobj.h"
 #include "asterisk/dnsmgr.h"
@@ -1015,6 +1016,7 @@
 					/*!< peer->name is the unique name of this object */
 	char secret[80];		/*!< Password */
 	char md5secret[80];		/*!< Password in MD5 */
+	char mac[13];			/*!< MAC address of SIP phone */ 
 	struct sip_auth *auth;		/*!< Realm authentication list */
 	char context[AST_MAX_CONTEXT];	/*!< Default context for incoming calls */
 	char subscribecontext[AST_MAX_CONTEXT];	/*!< Default context for subscriptions */
@@ -1435,6 +1437,7 @@
 static void build_via(struct sip_pvt *p);
 static int create_addr_from_peer(struct sip_pvt *r, struct sip_peer *peer);
 static int create_addr(struct sip_pvt *dialog, const char *opeer);
+static int grandstream_reset_packet(int fd, struct sip_request *req, const char *opeer);
 static char *generate_random_string(char *buf, size_t size);
 static void build_callid_pvt(struct sip_pvt *pvt);
 static void build_callid_registry(struct sip_registry *reg, struct in_addr ourip, const char *fromdomain);
@@ -1442,6 +1445,7 @@
 static int add_header(struct sip_request *req, const char *var, const char *value);
 static int add_header_contentLength(struct sip_request *req, int len);
 static int add_line(struct sip_request *req, const char *line);
+static int add_line_binary(struct sip_request *req, const char *line, int len);
 static int add_text(struct sip_request *req, const char *text);
 static int add_digit(struct sip_request *req, char digit);
 static int add_vidupdate(struct sip_request *req);
@@ -2631,6 +2635,66 @@
 	return 0;
 }
 
+static int grandstream_reset_packet(int fd, struct sip_request *req, const char *opeer)
+{
+	time_t nowtime;
+	struct MD5Context c;
+	unsigned char digest[24];
+	unsigned char mac[6];
+	unsigned char *colon = ":";
+	unsigned char buf[3];
+	int i, len;
+
+	struct sip_peer *p;
+
+	p = find_peer(opeer, NULL, 1);
+
+	if (!strlen(p->secret)) 
+	{
+		ast_cli(fd, "Need secret to reset peer %s (Grandstream phone)\n", opeer);
+		return -1;
+	}
+
+	if (!p || !strlen(p->mac)) 
+	{
+		ast_cli(fd, "No peer %s or no MAC address for Grandstream phone\n", opeer);
+		return -1;
+	}
+
+	len = strlen((char *)p->mac);
+	for(i = 0; i * 2 < len && i < 6; i++)
+	{
+		buf[0] = p->mac[2*i];
+		buf[1] = p->mac[2*i+1];
+		buf[2] = 0;
+		mac[i] = (unsigned char) strtoq(buf, NULL, 16);
+	}
+
+	digest[0] = 0;
+	digest[1] = 1;
+	digest[2] = 0;
+	digest[3] = 0;
+	nowtime = time(NULL);
+	digest[4] = (unsigned char) ((nowtime >> 24) & 0xff);
+	digest[5] = (unsigned char) ((nowtime >> 16) & 0xff);
+	digest[6] = (unsigned char) ((nowtime >> 8) & 0xff);
+	digest[7] = (unsigned char) (nowtime & 0xff);
+
+	MD5Init(&c);
+	MD5Update(&c, mac, 6);
+	MD5Update(&c, colon, 1);
+	MD5Update(&c, p->secret, strlen((char *)p->secret));
+	MD5Update(&c, colon, 1);
+	MD5Update(&c, digest+4, 4);
+	MD5Final(digest+8, &c);
+
+	add_header(req, "Content-Type", "application/octet-stream");
+	add_header_contentLength(req, 24);
+	add_line_binary(req, digest, 24);
+
+	return 0;
+}
+
 /*! \brief Scheduled congestion on a call */
 static int auto_congest(void *nothing)
 {
@@ -5051,6 +5115,29 @@
 	return 0;	
 }
 
+/*! \brief Add binary content (not header) to SIP message */
+static int add_line_binary(struct sip_request *req, const char *line, int len)
+{
+	if (req->lines == SIP_MAX_LINES)  {
+		ast_log(LOG_WARNING, "Out of SIP line space\n");
+		return -1;
+	}
+	if (!req->lines) {
+		/* Add extra empty return */
+		snprintf(req->data + req->len, sizeof(req->data) - req->len, "\r\n");
+		req->len += strlen(req->data + req->len);
+	}
+	if (req->len + len >= sizeof(req->data) - 4) {
+		ast_log(LOG_WARNING, "Out of space, can't add anymore\n");
+		return -1;
+	}
+	req->line[req->lines] = req->data + req->len;
+	memcpy(req->line[req->lines], line, len);
+	req->len += len;
+	req->lines++;
+	return 0;	
+}
+
 /*! \brief Copy one header field from one request to another */
 static int copy_header(struct sip_request *req, const struct sip_request *orig, const char *field)
 {
@@ -10525,6 +10612,14 @@
 			p->ourip = __ourip;
 		build_via(p);
 		build_callid_pvt(p);
+		if (!strcmp(argv[2], "reboot-grandstream")) {
+			ast_cli(fd, "REBOOTING type '%s' to '%s'\n", argv[2], argv[i]);
+			if (grandstream_reset_packet(fd, &req, argv[i])) {
+				sip_destroy(p);
+				ast_cli(fd, "Could not create address for '%s'\n", argv[i]);
+				continue;
+			}
+		}
 		ast_cli(fd, "Sending NOTIFY of type '%s' to '%s'\n", argv[2], argv[i]);
 		transmit_sip_request(p, &req);
 		sip_scheddestroy(p, SIP_TRANS_TIMEOUT);
@@ -15234,6 +15329,8 @@
 			ast_copy_string(peer->secret, v->value, sizeof(peer->secret));
 		else if (!strcasecmp(v->name, "md5secret")) 
 			ast_copy_string(peer->md5secret, v->value, sizeof(peer->md5secret));
+		else if (!strcasecmp(v->name, "mac"))
+			ast_copy_string(peer->mac, v->value, sizeof(peer->mac)); 
 		else if (!strcasecmp(v->name, "auth"))
 			peer->auth = add_realm_authentication(peer->auth, v->value, v->lineno);
 		else if (!strcasecmp(v->name, "callerid")) {
Index: configs/sip_notify.conf.sample
===================================================================
--- configs/sip_notify.conf.sample	(revision 39030)
+++ configs/sip_notify.conf.sample	(working copy)
@@ -7,8 +7,7 @@
 Event=>resync
 Content-Length=>0
 
-; Untested
-[grandstream-check-cfg]
+[reboot-grandstream]
 Event=>sys-control
 
 ; Untested
Index: configs/sip.conf.sample
===================================================================
--- configs/sip.conf.sample	(revision 39030)
+++ configs/sip.conf.sample	(working copy)
@@ -431,6 +431,7 @@
 ;                             rtpholdtimeout
 ;                             sendrpid
 ;                             outboundproxy
+;                             mac
 
 ;[sip_proxy]
 ; For incoming calls only. Example: FWD (Free World Dialup)
@@ -479,6 +480,7 @@
 ;nat=no				; there is not NAT between phone and Asterisk
 ;canreinvite=yes		; allow RTP voice traffic to bypass Asterisk
 ;dtmfmode=info			; either RFC2833 or INFO for the BudgeTone
+;mac=000b8203f9fe		; MAC address of Grandstream phone to reboot it
 ;call-limit=1			; permit only 1 outgoing call and 1 incoming call at a time
 				; from the phone to asterisk
 				; 1 for the explicit peer, 1 for the explicit user,
Index: res/res_jabber.c
===================================================================
--- res/res_jabber.c	(revision 39030)
+++ res/res_jabber.c	(working copy)
@@ -44,7 +44,6 @@
 #include "asterisk/cli.h"
 #include "asterisk/app.h"
 #include "asterisk/pbx.h"
-#include "asterisk/md5.h"
 #include "asterisk/acl.h"
 #include "asterisk/utils.h"
 #include "asterisk/module.h"
