[Asterisk-cvs] asterisk/channels chan_iax2.c,1.97,1.98 iax2-parser.c,1.14,1.15 iax2-parser.h,1.6,1.7 iax2.h,1.13,1.14

markster at lists.digium.com markster at lists.digium.com
Tue Feb 24 16:38:40 CST 2004


Update of /usr/cvsroot/asterisk/channels
In directory mongoose.digium.com:/tmp/cvs-serv28962/channels

Modified Files:
	chan_iax2.c iax2-parser.c iax2-parser.h iax2.h 
Log Message:
Add IAX2 firmware upgrade support


Index: chan_iax2.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_iax2.c,v
retrieving revision 1.97
retrieving revision 1.98
diff -u -d -r1.97 -r1.98
--- chan_iax2.c	18 Feb 2004 04:52:56 -0000	1.97
+++ chan_iax2.c	24 Feb 2004 21:27:16 -0000	1.98
@@ -33,7 +33,9 @@
 #include <asterisk/app.h>
 #include <asterisk/astdb.h>
 #include <asterisk/musiconhold.h>
+#include <sys/mman.h>
 #include <arpa/inet.h>
+#include <dirent.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
 #include <netinet/in_systm.h>
@@ -58,6 +60,7 @@
 #endif
 #include "iax2.h"
 #include "iax2-parser.h"
+#include "../astconf.h"
 
 #ifndef IPTOS_MINCOST
 #define IPTOS_MINCOST 0x02
@@ -240,6 +243,15 @@
 	int notransfer;
 };
 
+struct iax_firmware {
+	struct iax_firmware *next;
+	int fd;
+	int mmaplen;
+	int dead;
+	struct ast_iax2_firmware_header *fwh;
+	unsigned char *buf;
+};
+
 #define REG_STATE_UNREGISTERED 0
 #define REG_STATE_REGSENT	   1
 #define REG_STATE_AUTHSENT 	   2
@@ -434,6 +446,11 @@
 	ast_mutex_t lock;
 } peerl;
 
+static struct ast_firmware_list {
+	struct iax_firmware *wares;
+	ast_mutex_t lock;
+} waresl;
+
 /* Extension exists */
 #define CACHE_FLAG_EXISTS		(1 << 0)
 /* Extension is non-existant */
@@ -851,6 +868,216 @@
 	return 0;
 }
 
+static void destroy_firmware(struct iax_firmware *cur)
+{
+	/* Close firmware */
+	if (cur->fwh) {
+		munmap(cur->fwh, ntohl(cur->fwh->datalen) + sizeof(*(cur->fwh)));
+	}
+	close(cur->fd);
+	free(cur);
+}
+
+static int try_firmware(char *s)
+{
+	struct stat stbuf;
+	struct iax_firmware *cur;
+	int fd;
+	int res;
+	struct ast_iax2_firmware_header *fwh, fwh2;
+	struct MD5Context md5;
+	unsigned char sum[16];
+	res = stat(s, &stbuf);
+	if (res < 0) {
+		ast_log(LOG_WARNING, "Failed to stat '%s': %s\n", s, strerror(errno));
+		return -1;
+	}
+	/* Make sure it's not a directory */
+	if (S_ISDIR(stbuf.st_mode))
+		return -1;
+	fd = open(s, O_RDONLY);
+	if (fd < 0) {
+		ast_log(LOG_WARNING, "Cannot open '%s': %s\n", s, strerror(errno));
+		return -1;
+	}
+	if ((res = read(fd, &fwh2, sizeof(fwh2))) != sizeof(fwh2)) {
+		ast_log(LOG_WARNING, "Unable to read firmware header in '%s'\n", s);
+		close(fd);
+		return -1;
+	}
+	if (ntohl(fwh2.magic) != IAX_FIRMWARE_MAGIC) {
+		ast_log(LOG_WARNING, "'%s' is not a valid firmware file\n", s);
+		close(fd);
+		return -1;
+	}
+	if (ntohl(fwh2.datalen) != (stbuf.st_size - sizeof(fwh2))) {
+		ast_log(LOG_WARNING, "Invalid data length in firmware '%s'\n", s);
+		close(fd);
+		return -1;
+	}
+	if (fwh2.devname[sizeof(fwh2.devname) - 1] || !strlen(fwh2.devname)) {
+		ast_log(LOG_WARNING, "No or invalid device type specified for '%s'\n", s);
+		close(fd);
+		return -1;
+	}
+	fwh = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); 
+	if (!fwh) {
+		ast_log(LOG_WARNING, "mmap failed: %s\n", strerror(errno));
+		close(fd);
+		return -1;
+	}
+	MD5Init(&md5);
+	MD5Update(&md5, fwh->data, ntohl(fwh->datalen));
+	MD5Final(sum, &md5);
+	if (memcmp(sum, fwh->chksum, sizeof(sum))) {
+		ast_log(LOG_WARNING, "Firmware file '%s' fails checksum\n", s);
+		munmap(fwh, stbuf.st_size);
+		close(fd);
+		return -1;
+	}
+	cur = waresl.wares;
+	while(cur) {
+		if (!strcmp(cur->fwh->devname, fwh->devname)) {
+			/* Found a candidate */
+			if (cur->dead || (ntohs(cur->fwh->version) < ntohs(fwh->version)))
+				/* The version we have on loaded is older, load this one instead */
+				break;
+			/* This version is no newer than what we have.  Don't worry about it.
+			   We'll consider it a proper load anyhow though */
+			munmap(fwh, stbuf.st_size);
+			close(fd);
+			return 0;
+		}
+		cur = cur->next;
+	}
+	if (!cur) {
+		/* Allocate a new one and link it */
+		cur = malloc(sizeof(struct iax_firmware));
+		if (cur) {
+			memset(cur, 0, sizeof(struct iax_firmware));
+			cur->fd = -1;
+			cur->next = waresl.wares;
+			waresl.wares = cur;
+		}
+	}
+	if (cur) {
+		if (cur->fwh) {
+			munmap(cur->fwh, cur->mmaplen);
+		}
+		if (cur->fd > -1)
+			close(cur->fd);
+		cur->fwh = fwh;
+		cur->fd = fd;
+		cur->mmaplen = stbuf.st_size;
+		cur->dead = 0;
+	}
+	return 0;
+}
+
+static int iax_check_version(char *dev)
+{
+	int res = 0;
+	struct iax_firmware *cur;
+	if (dev && strlen(dev)) {
+		ast_mutex_lock(&waresl.lock);
+		cur = waresl.wares;
+		while(cur) {
+			if (!strcmp(dev, cur->fwh->devname)) {
+				res = ntohs(cur->fwh->version);
+				break;
+			}
+			cur = cur->next;
+		}
+		ast_mutex_unlock(&waresl.lock);
+	}
+	return res;
+}
+
+static int iax_firmware_append(struct iax_ie_data *ied, const unsigned char *dev, unsigned int desc)
+{
+	int res = -1;
+	unsigned int bs = desc & 0xff;
+	unsigned int start = (desc >> 8) & 0xffffff;
+	unsigned int bytes;
+	struct iax_firmware *cur;
+	if (dev && strlen(dev) && bs) {
+		start *= bs;
+		ast_mutex_lock(&waresl.lock);
+		cur = waresl.wares;
+		while(cur) {
+			if (!strcmp(dev, cur->fwh->devname)) {
+				iax_ie_append_int(ied, IAX_IE_FWBLOCKDESC, desc);
+				if (start < ntohl(cur->fwh->datalen)) {
+					bytes = ntohl(cur->fwh->datalen) - start;
+					if (bytes > bs)
+						bytes = bs;
+					iax_ie_append_raw(ied, IAX_IE_FWBLOCKDATA, cur->fwh->data + start, bytes);
+				} else {
+					bytes = 0;
+					iax_ie_append(ied, IAX_IE_FWBLOCKDATA);
+				}
+				if (bytes == bs)
+					res = 0;
+				else
+					res = 1;
+				break;
+			}
+			cur = cur->next;
+		}
+		ast_mutex_unlock(&waresl.lock);
+	}
+	return res;
+}
+
+
+static void reload_firmware(void)
+{
+	struct iax_firmware *cur, *curl, *curp;
+	DIR *fwd;
+	struct dirent *de;
+	char dir[256];
+	char fn[256];
+	/* Mark all as dead */
+	ast_mutex_lock(&waresl.lock);
+	cur = waresl.wares;
+	while(cur) {
+		cur->dead = 1;
+		cur = cur->next;
+	}
+	/* Now that we've freed them, load the new ones */
+	snprintf(dir, sizeof(dir), "%s/firmware/iax", (char *)ast_config_AST_VAR_DIR);
+	fwd = opendir(dir);
+	while((de = readdir(fwd))) {
+		if (de->d_name[0] != '.') {
+			snprintf(fn, sizeof(fn), "%s/%s", dir, de->d_name);
+			if (!try_firmware(fn)) {
+				if (option_verbose > 1)
+					ast_verbose(VERBOSE_PREFIX_2 "Loaded firmware '%s'\n", de->d_name);
+			}
+		}
+	}
+	closedir(fwd);
+
+	/* Clean up leftovers */
+	cur = waresl.wares;
+	curp = NULL;
+	while(cur) {
+		curl = cur;
+		cur = cur->next;
+		if (curl->dead) {
+			if (curp) {
+				curp->next = cur;
+			} else {
+				waresl.wares = cur;
+			}
+			destroy_firmware(curl);
+		} else {
+			curp = cur;
+		}
+	}
+	ast_mutex_unlock(&waresl.lock);
+}
+
 static int iax2_send(struct chan_iax2_pvt *pvt, struct ast_frame *f, unsigned int ts, int seqno, int now, int transfer, int final);
 
 static int __do_deliver(void *data)
@@ -2614,6 +2841,27 @@
 #undef FORMAT2
 }
 
+static int iax2_show_firmware(int fd, int argc, char *argv[])
+{
+#define FORMAT2 "%-15.15s  %-15.15s %-15.15s\n"
+#define FORMAT "%-15.15s  %-15.4x %-15d\n"
+	struct iax_firmware *cur;
+	if ((argc != 3) && (argc != 4))
+		return RESULT_SHOWUSAGE;
+	ast_mutex_lock(&waresl.lock);
+	
+	ast_cli(fd, FORMAT2, "Device", "Version", "Size");
+	for (cur = waresl.wares;cur;cur = cur->next) {
+		if ((argc == 3) || (!strcasecmp(argv[3], cur->fwh->devname))) 
+			ast_cli(fd, FORMAT, cur->fwh->devname, ntohs(cur->fwh->version),
+						ntohl(cur->fwh->datalen));
+	}
+	ast_mutex_unlock(&waresl.lock);
+	return RESULT_SUCCESS;
+#undef FORMAT
+#undef FORMAT2
+}
+
 /* JDG: callback to display iax peers in manager */
 static int manager_iax2_show_peers( struct mansession *s, struct message *m )
 {
@@ -2742,6 +2990,10 @@
 "Usage: iax2 show peers\n"
 "       Lists all known IAX peers.\n";
 
+static char show_firmware_usage[] = 
+"Usage: iax2 show firmware\n"
+"       Lists all known IAX firmware images.\n";
+
 static char show_reg_usage[] =
 "Usage: iax2 show registry\n"
 "       Lists all registration requests and status.\n";
@@ -2760,6 +3012,8 @@
 
 static struct ast_cli_entry  cli_show_users = 
 	{ { "iax2", "show", "users", NULL }, iax2_show_users, "Show defined IAX users", show_users_usage };
+static struct ast_cli_entry  cli_show_firmware = 
+	{ { "iax2", "show", "firmware", NULL }, iax2_show_firmware, "Show available IAX firmwares", show_firmware_usage };
 static struct ast_cli_entry  cli_show_channels =
 	{ { "iax2", "show", "channels", NULL }, iax2_show_channels, "Show active IAX channels", show_channels_usage };
 static struct ast_cli_entry  cli_show_peers =
@@ -3606,13 +3860,14 @@
 	}
 }
 
-static int update_registry(char *name, struct sockaddr_in *sin, int callno)
+static int update_registry(char *name, struct sockaddr_in *sin, int callno, char *devtype)
 {
 	/* Called from IAX thread only, with proper iaxsl lock */
 	struct iax_ie_data ied;
 	struct iax2_peer *p;
 	int msgcount;
 	char data[80];
+	int version;
 	memset(&ied, 0, sizeof(ied));
 	for (p = peerl.peers;p;p = p->next) {
 		if (!strcasecmp(name, p->name)) {
@@ -3666,6 +3921,9 @@
 			if (p->hascallerid)
 				iax_ie_append_str(&ied, IAX_IE_CALLING_NAME, p->callerid);
 		}
+		version = iax_check_version(devtype);
+		if (version) 
+			iax_ie_append_short(&ied, IAX_IE_FIRMWAREVER, version);
 		if (p->temponly)
 			free(p);
 		return send_command_final(iaxs[callno], AST_FRAME_IAX, IAX_COMMAND_REGACK, 0, ied.buf, ied.pos, -1);
@@ -4174,7 +4432,7 @@
 			f.subclass = uncompress_subclass(fh->csub);
 		}
 		if ((f.frametype == AST_FRAME_IAX) && ((f.subclass == IAX_COMMAND_NEW) || (f.subclass == IAX_COMMAND_REGREQ)
-				|| (f.subclass == IAX_COMMAND_POKE)))
+				|| (f.subclass == IAX_COMMAND_POKE) || (f.subclass == IAX_COMMAND_FWDOWNL)))
 			new = NEW_ALLOW;
 	} else {
 		/* Don't knwo anything about it yet */
@@ -4195,7 +4453,8 @@
 			/* We can only raw hangup control frames */
 			if (((f.subclass != IAX_COMMAND_INVAL) &&
 				 (f.subclass != IAX_COMMAND_TXCNT) &&
-				 (f.subclass != IAX_COMMAND_TXACC))||
+				 (f.subclass != IAX_COMMAND_TXACC) &&
+				 (f.subclass != IAX_COMMAND_FWDOWNL))||
 			    (f.frametype != AST_FRAME_IAX))
 				raw_hangup(&sin, ntohs(fh->dcallno) & ~IAX_FLAG_RETRANS, ntohs(mh->callno) & ~IAX_FLAG_FULL
 				);
@@ -4791,7 +5050,7 @@
 				if ((!strlen(iaxs[fr.callno]->secret) && !strlen(iaxs[fr.callno]->inkeys)) || (iaxs[fr.callno]->state & IAX_STATE_AUTHENTICATED)) {
 					if (f.subclass == IAX_COMMAND_REGREL)
 						memset(&sin, 0, sizeof(sin));
-					if (update_registry(iaxs[fr.callno]->peer, &sin, fr.callno))
+					if (update_registry(iaxs[fr.callno]->peer, &sin, fr.callno, ies.devicetype))
 						ast_log(LOG_WARNING, "Registry error\n");
 					break;
 				}
@@ -4884,6 +5143,17 @@
 			case IAX_COMMAND_UNSUPPORT:
 				ast_log(LOG_NOTICE, "Peer did not understand our iax command '%d'\n", ies.iax_unknown);
 				break;
+			case IAX_COMMAND_FWDOWNL:
+				/* Firmware download */
+				memset(&ied0, 0, sizeof(ied0));
+				res = iax_firmware_append(&ied0, ies.devicetype, ies.fwdesc);
+				if (res < 0)
+					send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_REJECT, 0, ied0.buf, ied0.pos, -1);
+				else if (res > 0)
+					send_command_final(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_FWDATA, 0, ied0.buf, ied0.pos, -1);
+				else
+					send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_FWDATA, 0, ied0.buf, ied0.pos, -1);
+				break;
 			default:
 				ast_log(LOG_DEBUG, "Unknown IAX command %d on %d/%d\n", f.subclass, fr.callno, iaxs[fr.callno]->peercallno);
 				memset(&ied0, 0, sizeof(ied0));
@@ -5782,6 +6052,7 @@
 	for (peer = peerl.peers; peer; peer = peer->next)
 		iax2_poke_peer(peer, 0);
 	ast_mutex_unlock(&peerl.lock);
+	reload_firmware();
 	return 0;
 }
 
@@ -6154,6 +6425,7 @@
 	ast_cli_unregister(&cli_show_users);
 	ast_cli_unregister(&cli_show_channels);
 	ast_cli_unregister(&cli_show_peers);
+	ast_cli_unregister(&cli_show_firmware);
 	ast_cli_unregister(&cli_show_registry);
 	ast_cli_unregister(&cli_debug);
 	ast_cli_unregister(&cli_trunk_debug);
@@ -6220,6 +6492,7 @@
 	ast_cli_register(&cli_show_users);
 	ast_cli_register(&cli_show_channels);
 	ast_cli_register(&cli_show_peers);
+	ast_cli_register(&cli_show_firmware);
 	ast_cli_register(&cli_show_registry);
 	ast_cli_register(&cli_debug);
 	ast_cli_register(&cli_trunk_debug);
@@ -6273,6 +6546,7 @@
 	for (peer = peerl.peers; peer; peer = peer->next)
 		iax2_poke_peer(peer, 0);
 	ast_mutex_unlock(&peerl.lock);
+	reload_firmware();
 	return res;
 }
 

Index: iax2-parser.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/iax2-parser.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -d -r1.14 -r1.15
--- iax2-parser.c	22 Oct 2003 02:53:39 -0000	1.14
+++ iax2-parser.c	24 Feb 2004 21:27:16 -0000	1.15
@@ -120,6 +120,11 @@
 	{ IAX_IE_PROVISIONING, "PROVISIONING" },
 	{ IAX_IE_AESPROVISIONING, "AES PROVISIONING" },
 	{ IAX_IE_DATETIME, "DATE TIME", dump_int },
+	{ IAX_IE_DEVICETYPE, "DEVICE TYPE", dump_string },
+	{ IAX_IE_SERVICEIDENT, "SERVICE IDENT", dump_string },
+	{ IAX_IE_FIRMWAREVER, "FIRMWARE VER", dump_short },
+	{ IAX_IE_FWBLOCKDESC, "FW BLOCK DESC", dump_int },
+	{ IAX_IE_FWBLOCKDATA, "FW BLOCK DATA" },
 };
 
 const char *iax_ie2str(int ie)
@@ -158,7 +163,11 @@
 					snprintf(tmp, sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
 					outputf(tmp);
 				} else {
-					snprintf(tmp, sizeof(tmp), "   %-15.15s : Present\n", ies[x].name);
+					if (ielen)
+						snprintf(interp, sizeof(interp), "%d bytes", ielen);
+					else
+						strcpy(interp, "Present");
+					snprintf(tmp, sizeof(tmp), "   %-15.15s : %s\n", ies[x].name, interp);
 					outputf(tmp);
 				}
 				found++;
@@ -223,6 +232,8 @@
 		"UNSUPPORTED",
 		"TRANSFER",
 		"PROVISION",
+		"FWDOWNLD",
+		"FWDATA"
 	};
 	char *cmds[] = {
 		"(0?)",
@@ -363,6 +374,7 @@
 	char tmp[256];
 	memset(ies, 0, sizeof(struct iax_ies));
 	ies->msgcount = -1;
+	ies->firmwarever = -1;
 	while(datalen >= 2) {
 		ie = data[0];
 		len = data[1];
@@ -506,6 +518,30 @@
 				errorf(tmp);
 			} else
 				ies->datetime = ntohl(*((unsigned int *)(data + 2)));
+			break;
+		case IAX_IE_FIRMWAREVER:
+			if (len != sizeof(unsigned short)) {
+				snprintf(tmp, sizeof(tmp), "Expecting firmwarever to be %d bytes long but was %d\n", sizeof(unsigned short), len);
+				errorf(tmp);
+			} else
+				ies->firmwarever = ntohs(*((unsigned short *)(data + 2)));	
+			break;
+		case IAX_IE_DEVICETYPE:
+			ies->devicetype = data + 2;
+			break;
+		case IAX_IE_SERVICEIDENT:
+			ies->serviceident = data + 2;
+			break;
+		case IAX_IE_FWBLOCKDESC:
+			if (len != sizeof(unsigned int)) {
+				snprintf(tmp, sizeof(tmp), "Expected block desc to be %d bytes long but was %d\n", sizeof(unsigned int), len);
+				errorf(tmp);
+			} else
+				ies->fwdesc = ntohl(*((unsigned int *)(data + 2)));
+			break;
+		case IAX_IE_FWBLOCKDATA:
+			ies->fwdata = data + 2;
+			ies->fwdatalen = len;
 			break;
 		default:
 			snprintf(tmp, sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);

Index: iax2-parser.h
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/iax2-parser.h,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -d -r1.6 -r1.7
--- iax2-parser.h	1 Oct 2003 22:59:06 -0000	1.6
+++ iax2-parser.h	24 Feb 2004 21:27:16 -0000	1.7
@@ -44,6 +44,12 @@
 	int musiconhold;
 	unsigned int transferid;
 	unsigned int datetime;
+	char *devicetype;
+	char *serviceident;
+	int firmwarever;
+	unsigned int fwdesc;
+	unsigned char *fwdata;
+	unsigned char fwdatalen;
 };
 
 #define DIRECTION_INGRESS 1

Index: iax2.h
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/iax2.h,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -d -r1.13 -r1.14
--- iax2.h	1 Oct 2003 22:59:06 -0000	1.13
+++ iax2.h	24 Feb 2004 21:27:16 -0000	1.14
@@ -65,6 +65,8 @@
 #define IAX_COMMAND_UNSUPPORT	33	/* Unsupported message received */
 #define IAX_COMMAND_TRANSFER	34	/* Request remote transfer */
 #define IAX_COMMAND_PROVISION	35	/* Provision device */
+#define IAX_COMMAND_FWDOWNL	36	/* Download firmware */
+#define IAX_COMMAND_FWDATA	37	/* Firmware Data */
 
 #define IAX_DEFAULT_REG_EXPIRE  60	/* By default require re-registration once per minute */
 
@@ -104,6 +106,11 @@
 #define IAX_IE_PROVISIONING			29		/* Provisioning info */
 #define IAX_IE_AESPROVISIONING			30		/* AES Provisioning info */
 #define IAX_IE_DATETIME				31		/* Date/Time */
+#define IAX_IE_DEVICETYPE			32		/* Device Type -- string */
+#define IAX_IE_SERVICEIDENT			33		/* Service Identifier -- string */
+#define IAX_IE_FIRMWAREVER			34		/* Firmware revision -- u16 */
+#define IAX_IE_FWBLOCKDESC			35		/* Firmware block description -- u32 */
+#define IAX_IE_FWBLOCKDATA			36		/* Firmware block of data -- raw */
 
 #define IAX_AUTH_PLAINTEXT			(1 << 0)
 #define IAX_AUTH_MD5				(1 << 1)
@@ -163,4 +170,14 @@
 	unsigned short len;				/* Length of data for this callno */
 } __attribute__ ((__packed__));
 
+#define IAX_FIRMWARE_MAGIC 0x69617879
+
+struct ast_iax2_firmware_header {
+	unsigned int magic;		/* Magic number */
+	unsigned short version;		/* Software version */
+	unsigned char devname[16];	/* Device */
+	unsigned int datalen;		/* Data length of file beyond header */
+	unsigned char chksum[16];	/* Checksum of all data */
+	unsigned char data[0];
+} __attribute__ ((__packed__));
 #endif




More information about the svn-commits mailing list