/* * protini.c - Read and process an NDIS protocol.ini file * * Copyright (C) 1998-2003 Gero Kuhlmann * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. * * $Id: protini.c,v 1.4 2003/01/25 23:29:42 gkminix Exp $ */ #define NEED_BINARY 1 #include #include #include "makerom.h" #include "protini.h" /* * Definitions local to this module */ #define BUFSIZE 1024 /* chunk size of input buffer */ #define MAXPARLEN 15 /* max section & parameter name len */ /* * Structure holding each parameter argument */ struct argdef { size_t arglen; /* length of argument string */ char *argptr; /* pointer to argument string */ struct argdef *next; /* pointer to next argument */ }; /* * Variables private to this module */ static char *inbuf; /* input buffer pointer */ static char *inpos; /* current write position in buffer */ static size_t inbufsize; /* input buffer size */ static __u8 *outbuf; /* memory image output buffer */ static __u8 *outpos; /* current write position in buffer */ static size_t outbufsize; /* output buffer size */ static long lastmod; /* offset to last module header */ static long lastkeyword; /* offset to last keyword header */ /* ************************************************************************** * * Reading of PROTOCOL.INI file * ************************************************************************** */ /* * Put a character at the end of the input buffer */ static void putinbuf(c) char c; { size_t len; char *cp; /* Check that we don't get at the end of the input buffer */ len = (inpos - inbuf); if (len >= (inbufsize - 1)) { cp = (char *)nbmalloc(inbufsize + BUFSIZE); memcpy(cp, inbuf, inbufsize); free(inbuf); inbuf = cp; inbufsize += BUFSIZE; inpos = inbuf + len; } /* Finally put new character into line buffer */ *inpos++ = c; } /* * Read a protocol.ini file into a local buffer. This will not * parse the file, as that's done later. */ char *readprotini(fname) char *fname; { FILE *infile; int c; /* Open input file */ if ((infile = fopen(fname, "r")) == NULL) { prnerr1("unable to open %s", fname); exit(EXIT_OPEN); } /* * Reset the input buffer pointers. The caller has to make sure, that * the old buffer is freed before calling this routine successivly. * Therefore, we can safely overwrite the pointers here. */ inbuf = inpos = (char *)nbmalloc(BUFSIZE); inbufsize = BUFSIZE; /* * Simply read the whole input file without any further processing, * except skipping return characters, which will only be found in * DOS written files. */ while (TRUE) { if ((c = fgetc(infile)) == EOF) break; if (c != '\r') putinbuf(c); } putinbuf('\0'); fclose(infile); return(inbuf); } /* ************************************************************************** * * Processing of PROTOCOL.INI contents * ************************************************************************** */ /* * Put a byte at the end of the output buffer */ static void putoutbuf(b) __u8 b; { size_t len; __u8 *cp; /* Check that we don't get at the end of the input buffer */ len = (outpos - outbuf); if (len >= (outbufsize - 1)) { cp = (__u8 *)nbmalloc(outbufsize + BUFSIZE); memcpy(cp, outbuf, outbufsize); free(outbuf); outbuf = cp; outbufsize += BUFSIZE; outpos = outbuf + len; } /* Finally put new character into line buffer */ *outpos++ = b; } /* * Put a section header structure into protocol.ini memory image */ static char *putsection(name, len) char *name; size_t len; { struct module_config mod, *mp; unsigned long newofs; int i; __u8 *bp; /* Clear module header structure */ memset(&mod, 0, sizeof(mod)); /* Copy section name into module header */ if (len > 15) return("section name too long"); i = 0; while (i < len && *name) { if (!isalpha(*name) && !isdigit(*name)) return("invalid character in section name"); mod.name[i++] = toupper(*(name++)) & 0xff; } /* Setup pointers to last module header */ newofs = (unsigned long)(outpos - outbuf); if (lastmod >= 0) { mp = (struct module_config *)(outbuf + lastmod); assign(mp->next.offset, htot(newofs)); assign(mod.prev.offset, htot(lastmod)); } lastmod = newofs; lastkeyword = -1L; /* Copy new module header into output buffer */ bp = (__u8 *)&mod; for (i = 0; i < MODCONF_SIZE; i++) putoutbuf(*(bp++)); return(NULL); } /* * Put a numeric argument into protocol.ini memory image */ static void putnumeric(num) long num; { struct param_struct par; int i; __u8 *bp; /* Setup and copy parameter header */ assign(par.paramtype, htot(PARAM_NUM)); assign(par.paramlen, htot(4)); bp = (__u8 *)∥ for (i = 0; i < PARAM_SIZE; i++) putoutbuf(*(bp++)); /* Copy number into output image */ for (i = 0; i < 4; i++) { putoutbuf((num % 256) & 0xff); num /= 256; } } /* * Put a string argument into protocol.ini memory image */ static void putstring(str) char *str; { struct param_struct par; int i; __u8 *bp; /* Setup and copy parameter header */ assign(par.paramtype, htot(PARAM_STRING)); assign(par.paramlen, htot(strlen(str) + 1)); bp = (__u8 *)∥ for (i = 0; i < PARAM_SIZE; i++) putoutbuf(*(bp++)); /* Copy string into output image */ while (*str) putoutbuf(*(str++) & 0xff); putoutbuf(0); } /* * Put a parameter header structure into protocol.ini memory image, * followed by all individual parameter arguments. */ static char *putparam(name, len, args, argnum) char *name; size_t len; struct argdef *args; int argnum; { struct keyword_entry key, *kp; struct argdef *ap; unsigned long newofs; __u8 *bp; char *cp, *str; long numeric; int i; /* Clear module header structure */ memset(&key, 0, sizeof(key)); /* Copy section name into module header */ if (len > 15) return("keyword name too long"); i = 0; while (i < len && *name) { if (!isalpha(*name) && !isdigit(*name)) return("invalid character in keyword name"); key.name[i++] = toupper(*(name++)) & 0xff; } /* Set number of parameters */ assign(key.numparams, htot(argnum)); /* Setup pointers to last keyword header */ newofs = (unsigned long)(outpos - outbuf); if (lastkeyword >= 0) { kp = (struct keyword_entry *)(outbuf + lastkeyword); assign(kp->next.offset, htot(newofs)); assign(key.prev.offset, htot(lastkeyword)); } lastkeyword = newofs; /* Copy new keyword header into output buffer */ bp = (__u8 *)&key; for (i = 0; i < KEYWORD_SIZE; i++) putoutbuf(*(bp++)); /* Put each parameter into output buffer */ ap = args; while (ap != NULL) { if (ap->arglen > 0 && ap->argptr != NULL) { str = (char *)nbmalloc(ap->arglen + 1); memcpy(str, ap->argptr, ap->arglen); str[ap->arglen] = '\0'; if (str[0] == '0' && toupper(str[1]) == 'X') { cp = str + 2; while (*cp && isxdigit(*cp)) cp++; if (*cp) return("invalid character in hexadecimal argument"); sscanf(str, "%lx", &numeric); if (numeric > 0x7FFFFFFFL) return("hexadecimal number too large"); putnumeric(numeric); } else if (((str[0] == '+' || str[0] == '-') && isdigit(str[1])) || isdigit(str[0])) { cp = str; if (*cp == '+' || *cp == '-') cp++; while (*cp && isdigit(*cp)) cp++; if (*cp) return("invalid character in decimal argument"); cp = str; if (*cp == '+') cp++; sscanf(cp, "%ld", &numeric); if (numeric > 0x7FFFFFFFL) return("decimal number too large"); else if (numeric < -0x7FFFFFFFL) return("decimal number too small"); putnumeric(numeric); } else { putstring(str); } free(str); } ap = ap->next; } return(NULL); } /* * Parse the contents of a PROTOCOL.INI file. This will remove * unnecessary comments and blanks and convert parameter and section * names to upper case as required per the NDIS specification. Then * put everything into the NDIS binary memory format. */ void parseprotini(protini, image, imglen) char *protini; __u8 **image; size_t *imglen; { int errnum = 0; int linenum = 0; char *errtext = NULL; char *inptr, *lineptr, *cp; char *paramnameptr; size_t paramnamelen; size_t len; int sectionnum = 0; int paramnum = 0; int argnum; struct argdef *args, *arglast, *ap; /* Don't do anything if protocol.ini image is empty */ assert(image != NULL && imglen != NULL); if (protini == NULL || !*protini) { *image = NULL; *imglen = 0; return; } /* * Reset the output buffer pointers. The caller has to make sure, that * the old buffer is freed before calling this routine successivly. * Therefore, we can safely overwrite the pointers here. */ outbuf = outpos = (__u8 *)nbmalloc(BUFSIZE); outbufsize = BUFSIZE; lastmod = lastkeyword = -1L; /* Scan through input buffer and handle each line seperately */ inptr = protini; while (*inptr) { /* Isolate the next line from the input buffer */ linenum++; lineptr = inptr; while (*inptr && *inptr != '\n') inptr++; if (*inptr == '\n') { *inptr = '\0'; inptr++; } /* Skip any blanks at the beginning of the line */ while (*lineptr == ' ' || *lineptr == '\t') lineptr++; /* Skip any blank line and any comment at the beginning of the line */ if (!*lineptr || *lineptr == ';') continue; /* Handle section name */ if (*lineptr == '[') { if (sectionnum > 0 && paramnum == 0) { errtext = "empty section"; goto doerr; } cp = ++lineptr; while (*lineptr && *lineptr != ']') lineptr++; if (!*lineptr) { errtext = "unterminated section name"; goto doerr; } len = lineptr - cp; if ((errtext = putsection(cp, len)) != NULL) goto doerr; lineptr++; while (*lineptr == ' ' || *lineptr == '\t') lineptr++; if (*lineptr && *lineptr != ';') { errtext = "junk after section name"; goto doerr; } sectionnum++; paramnum = 0; continue; } /* We can only accept parameters within a section */ if (sectionnum == 0) { errtext = "text outside section definition"; goto doerr; } /* Isolate parameter name */ paramnameptr = lineptr; while (*lineptr && !(*lineptr == ' ' || *lineptr == '\t' || *lineptr == '=')) lineptr++; paramnamelen = lineptr - paramnameptr; /* Check for equal sign and isolate all arguments */ argnum = 0; args = arglast = NULL; while (*lineptr == ' ' || *lineptr == '\t') lineptr++; if (*lineptr == '=') { lineptr++; while (TRUE) { while (*lineptr == ' ' || *lineptr == '\t') lineptr++; if (*lineptr == '"') { cp = ++lineptr; while (*lineptr && *lineptr != '"') lineptr++; if (!*lineptr) { errtext = "unterminated string character"; goto doerr; } len = lineptr - cp; lineptr++; } else { cp = lineptr; while (*lineptr && !(*lineptr == ',' || *lineptr == ';' || *lineptr == '\t' || *lineptr == ' ')) lineptr++; len = lineptr - cp; } if (len > 0) { ap = (struct argdef *)nbmalloc(sizeof(struct argdef)); ap->arglen = len; ap->argptr = cp; ap->next = NULL; if (args == NULL) args = ap; if (arglast != NULL) arglast->next = ap; arglast = ap; argnum++; } while (*lineptr == ' ' || *lineptr == '\t') lineptr++; if (*lineptr != ',') break; lineptr++; } } /* Check for correct termination of argument list */ if (*lineptr && *lineptr != ';') { errtext = "junk after parameter"; goto doerr; } /* Put parameter into memory image and clear argument list */ if ((errtext = putparam(paramnameptr, paramnamelen, args, argnum)) != NULL) goto doerr; paramnum++; while (args != NULL) { ap = args; args = args->next; free(ap); } continue; /* Check for error */ doerr: if (errtext != NULL) { prnerr2("protocol.ini [%d]: %s", linenum, errtext); errtext = NULL; errnum++; } } /* Exit if error */ if (errnum > 0) exit(EXIT_MAKEROM_PROTINI); /* The last section should not be empty */ if (sectionnum == 0) { *image = NULL; *imglen = 0; return; } else if (paramnum == 0) { prnerr0("unexpected end of protocol.ini"); exit(EXIT_MAKEROM_PROTINI); } /* Prepare return values */ *image = outbuf; *imglen = (outpos - outbuf); }