/*====================================================================* * * Copyright (c) 2013 Qualcomm Atheros, Inc. * * All rights reserved. * * Redistribution and use in source and binary forms, with or * without modification, are permitted (subject to the limitations * in the disclaimer below) provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials * provided with the distribution. * * * Neither the name of Qualcomm Atheros nor the names of * its contributors may be used to endorse or promote products * derived from this software without specific prior written * permission. * * NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE * GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE * COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * *--------------------------------------------------------------------*/ /*====================================================================* * * pibruin1.c - Atheros Classification Rule Insert Utility; * * This inserts classification rules into pib files from a rule * description file; * * * Contributor(s): * Nathaniel Houghton <nhoughto@qca.qualcomm.com> * *--------------------------------------------------------------------*/ /*====================================================================*" * system header files; *--------------------------------------------------------------------*/ #include <ctype.h> #include <unistd.h> #include <stdlib.h> #include <stdint.h> #include <string.h> #include <netinet/in.h> #include <arpa/inet.h> /*====================================================================* * custom header files; *--------------------------------------------------------------------*/ #include "../tools/getoptv.h" #include "../tools/memory.h" #include "../tools/number.h" #include "../tools/symbol.h" #include "../tools/types.h" #include "../tools/flags.h" #include "../tools/files.h" #include "../tools/error.h" #include "../plc/rules.h" #include "../pib/pib.h" /*====================================================================* * custom source files; *--------------------------------------------------------------------*/ #ifndef MAKEFILE #include "../tools/getoptv.c" #include "../tools/putoptv.c" #include "../tools/version.c" #include "../tools/lookup.c" #include "../tools/reword.c" #include "../tools/hexstring.c" #include "../tools/hexdecode.c" #include "../tools/fdchecksum32.c" #include "../tools/memout.c" #include "../tools/assist.c" #include "../tools/bytespec.c" #include "../tools/basespec.c" #include "../tools/ipv4spec.c" #include "../tools/ipv6spec.c" #include "../tools/endian.c" #include "../tools/emalloc.c" #include "../tools/todigit.c" #include "../tools/codelist.c" #include "../tools/error.c" #endif #ifndef MAKEFILE #include "../pib/pibfile1.c" #include "../pib/piblock.c" #endif #ifndef MAKEFILE #include "../plc/rules.c" #include "../plc/ParseRule.c" #endif /*====================================================================* * program variables; *--------------------------------------------------------------------*/ #ifndef __GNUC__ #pragma pack (push,1) #endif typedef struct __packed classifier_pib { uint32_t CR_PID; uint32_t CR_OPERAND; uint8_t CR_VALUE [16]; } classifier_pib; struct __packed auto_connection { uint8_t MACTION; uint8_t MOPERAND; uint16_t NUM_CLASSIFIERS; struct classifier_pib CLASSIFIER [3]; struct cspec cspec; uint8_t RSVD [14]; } auto_connection; struct __packed classifier_priority_map { uint32_t Priority; struct classifier_pib CLASSIFIER; } classifier_priority_map; #ifndef __GNUC__ #pragma pack (pop) #endif /*====================================================================* * program constants; *--------------------------------------------------------------------*/ #define PIB_MAX_AUTOCONN 16 #define PIB_MAX_PRIORITY_MAPS 8 #define PIB_AUTOCONN_COUNT_OFFSET 0x22C #define PIB_PRIORITY_COUNT_OFFSET 0x228 #define PIB_AUTOCONN_OFFSET 0x310 #define PIB_PRIORITY_MAPS_OFFSET 0x230 /*====================================================================* * * signed handle_rule (char * str, int argc, struct auto_connection * autoconn, struct classifier_priority_map * priority_map, int * autoconn_count, int * priority_count); * * *--------------------------------------------------------------------*/ static signed handle_rule (char * str, int argc, struct auto_connection * autoconn, struct classifier_priority_map * priority_map, int * autoconn_count, int * priority_count) { char const ** argv; char **mem; unsigned i; signed c; size_t len; struct rule rule; struct cspec cspec; static char const * optv [] = { "T:V:", "", "Atheros Classification Rule Insert Utility", "T\ttag", "V\tversion", (char const *) (0) }; extern char const * program_name; mem = emalloc ((argc + 2) * sizeof (char *)); argv = (char const **)(mem); * argv = program_name; ++argv; * argv = str; ++argv; len = strlen (str); for (i = 1; i < len; ++i) { if (str [i] == ' ') { str [i] = '\0'; * argv = &str [i + 1]; ++argv; } } * argv = NULL; optind = 1; argv = (char const **)(mem); memset (&rule, 0, sizeof (rule)); memset (&cspec, 0, sizeof (cspec)); while ((c = getoptv (argc, (char const **)(argv), optv)) != -1) { switch ((char) (c)) { case 'T': cspec.VLAN_TAG = (uint32_t)(basespec (optarg, 16, sizeof (cspec.VLAN_TAG))); cspec.VLAN_TAG = htonl (cspec.VLAN_TAG); break; case 'V': cspec.CSPEC_VERSION = (uint16_t)(basespec (optarg, 10, sizeof (cspec.CSPEC_VERSION))); break; default: break; } } argc -= optind; argv += optind; ParseRule (&argc, (char const ***) &argv, &rule, &cspec); /* Now migrate the rule into the correct PIB structure. */ if (rule.NUM_CLASSIFIERS > 1 || rule.MACTION == ACTION_STRIPTX || rule.MACTION == ACTION_STRIPRX || rule.MACTION == ACTION_TAGTX || *priority_count >= PIB_MAX_PRIORITY_MAPS) { if (*autoconn_count >= PIB_MAX_AUTOCONN) { error (1, 0, "too many rules"); } autoconn = &autoconn [*autoconn_count]; autoconn->CLASSIFIER [0].CR_PID = 0xFF; autoconn->CLASSIFIER [1].CR_PID = 0xFF; autoconn->CLASSIFIER [2].CR_PID = 0xFF; autoconn->MACTION = rule.MACTION; autoconn->MOPERAND = rule.MOPERAND; autoconn->NUM_CLASSIFIERS = rule.NUM_CLASSIFIERS; for (i = 0; i < rule.NUM_CLASSIFIERS; ++i) { autoconn->CLASSIFIER [i].CR_PID = rule.CLASSIFIER [i].CR_PID; autoconn->CLASSIFIER [i].CR_OPERAND = rule.CLASSIFIER [i].CR_OPERAND; memcpy (&autoconn->CLASSIFIER [i].CR_VALUE, &rule.CLASSIFIER [i].CR_VALUE, sizeof (autoconn->CLASSIFIER [i].CR_VALUE)); } memcpy (&autoconn->cspec, &rule.cspec, sizeof (autoconn->cspec)); ++(*autoconn_count); } else { if (*priority_count >= PIB_MAX_PRIORITY_MAPS) { error (1, 0, "too many rules"); } priority_map = &priority_map [*priority_count]; priority_map->Priority = rule.MACTION; priority_map->CLASSIFIER.CR_PID = rule.CLASSIFIER [0].CR_PID; priority_map->CLASSIFIER.CR_OPERAND = rule.CLASSIFIER [0].CR_OPERAND; memcpy (&priority_map->CLASSIFIER.CR_VALUE, &rule.CLASSIFIER [0].CR_VALUE, sizeof (priority_map->CLASSIFIER.CR_VALUE)); ++(*priority_count); } free (mem); return (0); } static void read_rules (struct auto_connection auto_connection [], unsigned * autoconn_count, struct classifier_priority_map classifier_priority_map [], unsigned * priority_count) { int len = 0; int wc = 0; while ((c = getc (stdin)) != EOF) { if (isspace (c)) { continue; } if (c == '#') { do { c = getc (stdin); } while (nobreak (c)); continue; } len = 0; wc = 0; do { if (isspace (c)) { while (c != '\n' && (c = getc (stdin)) != EOF && isspace (c)) { continue; } if (len > 0) { ++wc; } if (c != '\n' && c != '#') { line [len++] = ' '; if (len == sizeof (line) - 1) { error (1, 0, "rule too long"); } } } if (c == '\n' || c == '#') { line [len] = '\0'; handle_rule (line, wc, auto_connection, classifier_priority_map, autoconn_count, priority_count); len = 0; wc = 0; if (c == '#') { ungetc (c, stdin); } break; } line [len++] = c; if (len == sizeof (line) - 1) { error (1, 0, "rule too long"); } } while ((c = getc (stdin)) != EOF); } if (len > 0) { line [len] = '\0'; handle_rule (line, wc, auto_connection, classifier_priority_map, autoconn_count, priority_count); } } /*====================================================================* * * int main (int argc, char const * argv[]); * * *--------------------------------------------------------------------*/ int main (int argc, char const * argv []) { static char const * optv [] = { "eqv", "pibfile < rules", "Atheros Classification Rule Insert Utility", "e\tredirect stderr messages to stdout", "q\tquiet mode", "v\tverbose mode", (char const *) (0) }; struct auto_connection auto_connection [PIB_MAX_AUTOCONN]; struct classifier_priority_map classifier_priority_map [PIB_MAX_PRIORITY_MAPS]; unsigned autoconn_count = 0; unsigned priority_count = 0; flag_t flags = (flag_t)(0); struct _file_ pib; char line [1024]; signed c; optind = 1; while ((c = getoptv (argc, argv, optv)) != -1) { switch ((char) (c)) { case 'e': dup2 (STDOUT_FILENO, STDERR_FILENO); break; case 'q': _setbits (flags, PIB_SILENCE); break; case 'v': _setbits (flags, PIB_VERBOSE); break; default: break; } } argc -= optind; argv += optind; if (!argc) { error (1, 0, "must specify PIB file"); } memset (&auto_connection, 0, sizeof (auto_connection)); memset (&classifier_priority_map, 0, sizeof (classifier_priority_map)); read_rules (auto_connection, &autoconn_count, classifier_priority_map, &priority_count); pib.name = * argv; if ((pib.file = open (pib.name, O_BINARY|O_RDWR, FILE_FILEMODE)) == -1) { error (1, errno, "%s", pib.name); } if (pibfile1 (&pib)) { error (1, errno, "Bad PIB file: %s", pib.name); } if (lseek (pib.file, PIB_AUTOCONN_OFFSET, SEEK_SET) != PIB_AUTOCONN_OFFSET) { error (1, errno, "could not seek to AutoConnections"); } if (write (pib.file, &auto_connection, sizeof (auto_connection)) != sizeof (auto_connection)) { error (1, errno, "could not write AutoConnections"); } if (lseek (pib.file, PIB_AUTOCONN_COUNT_OFFSET, SEEK_SET) != PIB_AUTOCONN_COUNT_OFFSET) { error (1, errno, "could not seek to AutoConnection count"); } if (write (pib.file, &autoconn_count, sizeof (autoconn_count)) != sizeof (autoconn_count)) { error (1, errno, "could not write AutoConnection count"); } if (lseek (pib.file, PIB_PRIORITY_MAPS_OFFSET, SEEK_SET) != PIB_PRIORITY_MAPS_OFFSET) { error (1, errno, "could not seek to Priority Map"); } if (write (pib.file, &classifier_priority_map, sizeof (classifier_priority_map)) != sizeof (classifier_priority_map)) { error (1, errno, "could not write Priority Map"); } if (lseek (pib.file, PIB_PRIORITY_COUNT_OFFSET, SEEK_SET) != PIB_PRIORITY_COUNT_OFFSET) { error (1, errno, "could not seek to PriorityMaps count"); } if (write (pib.file, &priority_count, sizeof (priority_count)) != sizeof (priority_count)) { error (1, errno, "could not write PriorityMaps count"); } piblock (&pib); close (pib.file); exit (0); }