############################################################################### # Copyright (c) 2000-2019 Ericsson Telecom AB # All rights reserved. This program and the accompanying materials # are made available under the terms of the Eclipse Public License v2.0 # which accompanies this distribution, and is available at # https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html # # Contributors: # Roland Gecse - initial implementation and initial documentation # Akos Pernek # Antal Wuh.Hen.Chang # Attila Fulop # Balazs Barcsik # Bence Molnar # Csaba Koppany # David Juhasz # Eduard Czimbalmos # Elemer Lelik # Endre Kiss # Endre Kulcsar # Gabor Szalai # Gabor Tatarka # Gergely Futo # Istvan Sandor # Krisztian Pandi # Kulcsár Endre # Laszlo Tamas Zeke # Norbert Pinter # Roland Gecse # Tibor Bende # Tibor Szabo # Timea Moder # Zoltan Medve # Zsolt Nandor Torok # Zsolt Szalai ############################################################################### # # # File: AVP.awk # # Description: Diameter Protocol Module Generator (DPMG) GNU awk # # script for weaving DDF files # # Requires GNU awk 3.1.6 # # Rev: RnXnn # # Prodnr: CNL 113 462 # # # ############################################################################# BEGIN { FS = "[ \t\n;]+" HT = "\t" SP = " " # Number of AVP descriptors found in input DDF file avp_descriptors = 0 # Number of AVP type definitions matching preceeding AVP descriptor matching_avp_types = 0 # Identifier of generated TTCN-3 module if(!module_id) module_id = "DIAMETER_Types" # Use APPLICATION-REVISION prefix in AVP type identifiers when true if(!use_application_revision) use_application_revision = 0 # Replace all enumeration type AVPs with type Unsigned32 when true if(!enum_2_Unsigned32) enum_2_Unsigned32 = 0 # Use integer for 32 bit unsigned and 64 bit signed types when true if(!use_bigint) use_bigint = 0 # Use detailed description for RPET and VMP bits if(!detailed_bits) detailed_bits = 0 # Disable application name prefix if(!disable_prefix) disable_prefix = 0 # Replace the listed enumeration type AVPs with type Unsigned32 enum_replace_list["0 0"]=1 if(enum_2_Unsigned32_list){ while ((getline < enum_2_Unsigned32_list) > 0) { split($0,el," ") enum_replace_list["(" el[1] ")" SP "(" el[2] ")"]=1 } close(enum_2_Unsigned32_list); } print "module " module_id " {" } { # Remove excess WS from beginning and end of EACH record sub(/^[ \t]+/, "") sub(/[ \t]+$/, "") } /\/\/ APPLICATION-NAME:/ { # Will be used to prefix generated AVP type definitions if(disable_prefix) { application_id = "AVP_" } else { application_id = $3 "_" } } /\/\/ APPLICATION-REVISION:/ { # Could be used as additional prefix for generated AVP type definitions application_revision = $3 if(use_application_revision && !disable_prefix && application_revision) { application_id = application_id application_revision "_" } } /\/\/ AVP:/ { # AVP descriptor line e.g.: # // AVP: Official-AVP-Name (Official-AVP-Code) Vendor-Id (Vendor-Id-Code) # <------ $3 -----> <------ $4 ------> <- $5 -> <----- $6 -----> new_avp_name = $3 new_avp_code = $4 new_avp_vendor_id = $5 new_avp_vendor_id_code = $6 if(!new_avp_vendor_id) { new_avp_vendor_id = "NONE" new_avp_vendor_id_code = "(0)" } gsub(/-/, "_", new_avp_name) gsub(/-/, "_", new_vendor_id) avp_descriptors++ } /\ if($3 == new_avp_name && (new_avp_code SP new_avp_vendor_id_code) in AVP) { print "// WARNING: Duplicated AVP definition removed by gawk script!" if($2 == "enumerated") { f_ReadTotalEnum() } ++deleted_avp_types next } else if($3 == new_avp_name) { ++matching_avp_types $3 = new_avp_id = application_id new_avp_vendor_id "_" new_avp_name AVP[new_avp_code SP new_avp_vendor_id_code] = new_avp_id if(!(new_avp_vendor_id_code in VENDORID)) { VENDORID[new_avp_vendor_id_code] = new_avp_vendor_id } if($2 == "enumerated") { f_ReadTotalEnum() if(enum_2_Unsigned32 || ((new_avp_code SP new_avp_vendor_id_code) in enum_replace_list)) { print "// WARNING: Enumeration type AVP replaced by Unsigned32!" print "type AVP_Unsigned32 " new_avp_id ";" } else { gsub(/\,/, ",\n", total_enum) sub(/\{/, " {\n", total_enum) sub(/\}/, "\n}", total_enum) f_AddVariant_U32(total_enum) } next } } else if($2 == "enumerated" && $3 == "Command_Code") { # TODO: check unique entries! f_ReadTotalEnum() f_ParseStoreTotalEnum("Command_Code") } } /!2 / { if(use_bigint){ sub(/!2 /,"") print } next } /!1 / { if(!use_bigint){ sub(/!1 /,"") print } next } /!4 / { if(detailed_bits){ sub(/!4 /,"") print } next } /!3 / { if(!detailed_bits){ sub(/!3 /,"") print } next } /!5 / { if(!use_UTF8_encoding){ sub(/!5 /,"") print } next } /!6 / { if(use_UTF8_encoding){ sub(/!6 /,"") print } next } {print} END { print "// STATISTICS: " avp_descriptors " AVP descriptors found" print "// STATISTICS: " matching_avp_types \ " AVP type definitions matching AVP descriptors found" print "// STATISTICS: " deleted_avp_types " duplicate AVP definitions deleted" if(avp_descriptors != matching_avp_types + deleted_avp_types) { print "// ERROR: avp_descriptors " avp_descriptors \ " != matching_avp_types " matching_avp_types exit(1) } print "type enumerated Command_Code {" print ENUM["Command_Code"] print "} with {" print HT "variant \"FIELDLENGTH(24)\"" print HT "variant \"BYTEORDER(last)\"" print "}\n" print "type enumerated Vendor_Id {" len = length(VENDORID) for (i in VENDORID) { printf ("\tvendor_id_%s %s%s\n", VENDORID[i], i, (--len) ? "," : "") } f_AddVariant_U32("}") for (i in VENDORID) { AVP_Code_VENDORID[i] = "type enumerated AVP_Code_" VENDORID[i] " {\n" } for (i in AVP) { split(i, t) AVP_Code_VENDORID[t[2]] = \ AVP_Code_VENDORID[t[2]] HT "avp_code_" AVP[i] SP t[1] ",\n" } for (i in VENDORID) { sub(/\,\n$/, "", AVP_Code_VENDORID[i]) print AVP_Code_VENDORID[i] f_AddVariant_U32("}"); } print "type union AVP_Code {" len = length(VENDORID) for (i in VENDORID) { printf ("\tAVP_Code_%s vendor_id_%s%s\n", \ VENDORID[i], VENDORID[i], (--len) ? "," : "") } print "}" print "type record AVP_Header {" print HT "AVP_Code avp_code," if(detailed_bits){ print HT "BIT1 V_bit," print HT "BIT1 M_bit," print HT "BIT1 P_bit," print HT "BIT5 r_bits," } else { print HT "BIT8 VMPxxxxx," } print HT "UINT24 avp_length," print HT "Vendor_Id vendor_id optional" print "} with {" print HT "variant (vendor_id) \"PRESENCE( {" if(detailed_bits){ print HT HT "V_bit = '1'B" } else { print HT HT "VMPxxxxx = '10000000'B," print HT HT "VMPxxxxx = '10100000'B," print HT HT "VMPxxxxx = '11000000'B," print HT HT "VMPxxxxx = '11100000'B" } print HT "} )\"" print HT "variant (avp_code) \"CROSSTAG(" for(i in VENDORID) { if(VENDORID[i] == "NONE") { tmp = "omit" } else { tmp = "vendor_id_" VENDORID[i] } print HT HT "vendor_id_" VENDORID[i] ", vendor_id = " tmp ";" } print HT ")\"" if(detailed_bits){ print HT "variant (r_bits, P_bit, M_bit, V_bit) \"FIELDORDER(msb)\"" } print "}" print "type union AVP_Data {" for (i in AVP) { print HT AVP[i] " avp_" AVP[i] "," } print HT "octetstring", "avp_UNKNOWN" print "}" print "type union GenericAVP {" print HT "AVP avp," print HT "Undefined_AVP avp_undefined," print HT "octetstring avp_UNKNOWN" print "}" print "type record Undefined_AVP {" print HT "OCTET4 avp_code," if(detailed_bits){ print HT "BIT1 V_bit," print HT "BIT1 M_bit," print HT "BIT1 P_bit," print HT "BIT5 r_bits," } else { print HT "BIT8 VMPxxxxx," } print HT "UINT24 avp_length," print HT "OCTET4 vendor_id optional," print HT "octetstring avp_data" print "} with {" print HT "variant \"PADDING(dword32)\"" print HT "variant (vendor_id) \"PRESENCE( {" if(detailed_bits){ print HT HT "V_bit = '1'B" } else { print HT HT "VMPxxxxx = '10000000'B," print HT HT "VMPxxxxx = '10100000'B," print HT HT "VMPxxxxx = '11000000'B," print HT HT "VMPxxxxx = '11100000'B" } print HT "} )\"" if(detailed_bits){ print HT "variant (avp_length) \"LENGTHTO(avp_code, V_bit, M_bit, P_bit, r_bits, avp_length, vendor_id, avp_data)\"" print HT "variant (r_bits, P_bit, M_bit, V_bit) \"FIELDORDER(msb)\"" } else { print HT "variant (avp_length) \"LENGTHTO(avp_code, VMPxxxxx, avp_length, vendor_id, avp_data)\"" } print "}" print "type record AVP {" print HT "AVP_Header", "avp_header," print HT "AVP_Data", "avp_data" print "} with {" print HT "variant \"PADDING(dword32)\"" print HT "variant (avp_header) \"LENGTHTO(avp_header, avp_data)\"" print HT "variant (avp_header) \"LENGTHINDEX(avp_length)\"" print HT "variant (avp_data) \"CROSSTAG(" for (i in AVP) { split(i, t) print HT HT "avp_" AVP[i] ", " \ "avp_header.avp_code.vendor_id_" VENDORID[t[2]] " = " \ "avp_code_" AVP[i] ";" } print HT HT "avp_UNKNOWN, OTHERWISE" print HT ")\"" print "}" print "type set of GenericAVP AVP_list;" # AVP_Code constants' generation for (i in AVP) { split(i, t) print "const AVP_Code c_AVP_Code_" AVP[i] " := {" print HT "vendor_id_" VENDORID[t[2]] " := avp_code_" AVP[i] " };" } print "} with { encode \"RAW\" } // End module" } function f_AddVariant_U32(prefix) { print prefix, "with {" print HT "variant \"FIELDLENGTH(32)\"" print HT "variant \"BYTEORDER(last)\"" print HT "variant \"COMP(2scompl)\"" print "}" } # Read entire type definition into total_enum function f_ReadTotalEnum() { total_enum = $0 while(total_enum !~ /\}/) { getline sub(/\/\/.*/, "") total_enum = total_enum $0 } gsub(/[ \t]+/, " ", total_enum) # Replace $0 contents with data following } idx = index(total_enum, "}") $0 = substr(total_enum, idx+1) total_enum = substr(total_enum, 1, idx) } # Extract and store enumeration items from total_enum into ENUM array for key function f_ParseStoreTotalEnum(key) { sub(/^[^\{]+\{/, "", total_enum) sub(/\}[^\}]*$/, "", total_enum) if(ENUM[key]) { split(total_enum, t, /,/) for(i in t) { enum_item = t[i] match(enum_item, /(\([0-9]+\))/, enum_code) if(!index(ENUM[key], enum_code[1])) { ENUM[key] = ENUM[key] "," t[i] } else { print "// WARNING: Enumeration item with code", enum_code[1], \ "exists in type", key } } } else { ENUM[key] = total_enum } }