#!/usr/bin/perl
use strict;
use warnings;
use FindBin qw($Bin);
use lib "$Bin/../../PerlLib";
use BRCM::GenConfig;

# $p will allow us to GET values from the PROFILE
# $c will allow us to SET (and GET and DRIVER_SETUP) on the config
# file as we transform it from a template to the final config

# arguments
# * profile file
# * config  file
my $p    = new BRCM::GenConfig(shift);
my $chip = $p->get('BRCM_CHIP');
my $c    = new BRCM::GenConfig( shift, Chip => $chip, Profile => $p );


# list of netfilter modules, minus the "CONFIG_" prefix
my @nf_mods = qw[NETFILTER_XTABLES IP_NF_IPTABLES IP_NF_FILTER
  NETFILTER_XT_TARGET_TCPMSS NETFILTER_XT_TARGET_SKIPLOG
  NETFILTER_NETLINK NETFILTER_NETLINK_QUEUE
  NETFILTER_XT_MATCH_MULTIPORT NETFILTER_XT_MATCH_ADDRTYPE
  NETFILTER_XT_MATCH_BLOG NETFILTER_XT_MATCH_FLOWLABEL NETFILTER_XT_MATCH_U32];

# must match static modules defined in rut_iptables.c (modules[] = ...):
# also note: tcpudp is controled by NETFILTER_XTABLES
my @static_nf_mods = qw[NETFILTER_XTABLES];

if ( $p->get("BUILD_CONNTRACK_TOOLS") ) {

    # add one more to the list
    push @nf_mods, "NF_CT_NETLINK";
    $c->set( "CONFIG_NF_CONNTRACK_EVENTS", 'y' );
}

if ( $p->get("BUILD_IPSET") ) {
    # add one more to the list
    push @nf_mods, "NETFILTER_XT_SET";
}

# for each type of netfilter, the list of modules it needs
# to conditionally enable
my $nf_x_mods = {
    NAT => [
        qw[NF_CONNTRACK NF_CONNTRACK_IPV4
          NF_NAT IP_NF_TARGET_MASQUERADE IP_NF_TARGET_REDIRECT]
    ],

    FIREWALL => [qw[NETFILTER_XT_MATCH_CONNTRACK NETFILTER_XT_MATCH_STATE NETFILTER_XT_MATCH_LIMIT IP_NF_TARGET_LOG NETFILTER_XT_TARGET_LOG]],

    MANGLE => [
        qw[IP_NF_MANGLE NETFILTER_XT_MATCH_MARK
          NETFILTER_XT_TARGET_MARK NETFILTER_XT_MATCH_DSCP
          NETFILTER_XT_TARGET_DSCP NETFILTER_XT_MATCH_MAC]
    ],

    DYNDSCP => [qw[NF_CONNTRACK NF_CONNTRACK_IPV4 NF_DYNDSCP]],

    PPPREMOTE => [qw[NF_CONNTRACK NF_CONNTRACK_IPV4 NF_NAT NETFILTER_XT_MATCH_LIMIT]],

    LOG => [qw[IP_NF_TARGET_LOG NETFILTER_XT_TARGET_LOG]],
    
    FIREWALL_EXT => [qw[NETFILTER_XT_MATCH_HASHLIMIT]],
};


# If NAT is enabled, the list of ALGs needed for each module
# Example:
#    FTP  => [qw[NF_CONNTRACK_FTP NF_NAT_FTP]],
# means...
# CONFIG_CF_CONNTRACK and CONFIG_NF_NAT_FTP are both configured
# the same way as the  BRCM_KERNEL_NF_NAT_ALG_FTP profile variable

my $algs = {
    FTP  => [qw[NF_CONNTRACK_FTP NF_NAT_FTP]],
    SIP  => [qw[NF_CONNTRACK_SIP NF_NAT_SIP]],
    TFTP => [qw[NF_CONNTRACK_TFTP NF_NAT_TFTP]],
    H323 => [qw[NF_CONNTRACK_H323 NF_NAT_H323]],

    # H323_SIGNAL_PROXY_ALG_MODULES="H323_SIGNAL_PROXY"
    IRC => [qw[NF_CONNTRACK_IRC NF_NAT_IRC]],

    PPTP => [qw[NF_CONNTRACK_PPTP NF_NAT_PPTP]],
    RTSP => [qw[NF_CONNTRACK_RTSP NF_NAT_RTSP]],
    SNMP => [qw[NF_NAT_SNMP_BASIC]],

    # TALK_ALG_MODULES="TALK NAT_TALK"
};

my $bcm_algs = {
    IPSEC => [qw[NF_CONNTRACK_IPSEC NF_NAT_IPSEC NF_CT_PROTO_ESP NF_NAT_PROTO_ESP]],

    # DTX8_ALG_MODULES="DTX8"
    # WM_ALG_MODULES="WM"
    PT => [qw[NF_NAT_PT]],
};

# list of ipset modules, minus the "CONFIG_" prefix
my @ips_mods = qw[IP_SET IP_SET_BITMAP_IP IP_SET_BITMAP_PORT IP_SET_HASH_IP
  IP_SET_HASH_IPPORT IP_SET_HASH_IPPORTIP IP_SET_HASH_MAC IP_SET_LIST_SET
  IP_SET_HASH_NET];

# prepend "CONFIG_" to each member of @ips_mods
@ips_mods = map( "CONFIG_$_", @ips_mods );

# prepend "CONFIG_" to each member of @nf_mods
@nf_mods = map( "CONFIG_$_", @nf_mods );
@static_nf_mods = map( "CONFIG_$_", @static_nf_mods );

if ( my $m = $p->get("BRCM_KERNEL_NETFILTER") ) {
    $c->set( "CONFIG_NETFILTER", 'y' );

    if ( $p->get("BUILD_IPSET") ) {
        # set all of the modules in @ips_mods to 'm'
        # [we pass a reference to the list]
        $c->set( \@ips_mods, $m );
    }

    # set all of the modules in @nf_mods to either 'y' or 'm'
    # [we pass a reference to the list]
    $c->set( \@nf_mods, $m );
    $c->set( \@static_nf_mods, 'y' );

    # for each of the keys in the nf_x_mods hash
    # set ALL of the values' CONFIG_whatever to the same
    # 'y' or 'm' as BRCM_KERNEL_NF_thekeyname, but don't unset it
    # if is set and BRCM_KERNEL_NF_thekeyname is not
    foreach my $t ( keys( %{$nf_x_mods} ) ) {

        # The map statement makes a copy of the list reference with CONFIG_
        # prepended to each member
        my $r = [ map( "CONFIG_$_", @{ $nf_x_mods->{$t} } ) ];
        $c->set( $r, $p->get("BRCM_KERNEL_NF_$t"), NoUnset => 1 );
    }
    if ( my $nat_m = $p->get("BRCM_KERNEL_NF_NAT") ) {

        # for each of the ALGs in the $algs hash (reference),
        # set ALL of the values' CONFIG_whatever to the same
        # state as the ALG itself (but don't unset)
        foreach my $t ( keys( %{$algs} ) ) {
            my $r = [ map( "CONFIG_$_", @{ $algs->{$t} } ) ];
            $c->set( $r, $p->get("BRCM_KERNEL_NF_NAT_ALG_$t"), NoUnset => 1 );
            if ( $p->get("BRCM_KERNEL_NF_NAT_ALG_SIP") ) {
               $c->set( "CONFIG_BCM_NETFILTER_SIP", 'y');
            }
        }
        foreach my $t ( keys( %{$bcm_algs} ) ) {

            # Same thing, but don't let them be static
            my $r = [ map( "CONFIG_$_", @{ $bcm_algs->{$t} } ) ];
            $c->set( $r, $p->get("BRCM_KERNEL_NF_NAT_ALG_$t") ? 'm' : undef, NoUnset => 1 );
        }

            $c->set( "CONFIG_NF_NAT_IPV4", $nat_m);
            $c->set( 'CONFIG_IP_NF_NAT', $nat_m);

            if ( $p->get("BUILD_IPV6") ) {
                $c->set( "CONFIG_NF_NAT_IPV6", $nat_m);
            }

    }
    if ( $p->get("BUILD_OPENVSWITCH") ) {
        $c->set( "CONFIG_NETFILTER_XT_MATCH_CONNLABEL", "m" );
        $c->set( "CONFIG_NF_CT_NETLINK", "m" );
    }
    if ( $p->get("BUILD_MODSW_EE") ) {
        $c->set( "CONFIG_BRIDGE_NETFILTER", 'm' );
    }
    if ( $p->get("BRCM_DRIVER_DPI") ) {
        $c->set( "CONFIG_NETFILTER_NETLINK", 'm' );
        $c->set( "CONFIG_NF_CT_NETLINK",     'm' );
        $c->set( "CONFIG_NF_CONNTRACK_EVENTS", 'y' );
        $c->set( "CONFIG_BRIDGE_NETFILTER", 'y' );
    }

    $c->set( "CONFIG_BCM_NETFILTER_REGARDLESS_DROP_ORDER", $p->get("BRCM_KERNEL_NF_REGARDLESS_DROP_ORDER"));

}

# HND profile specific overrides and extra configs
if ( $p->get("BUILD_BRCM_HNDROUTER") ) {

	$c->set( "CONFIG_NETFILTER_NETLINK_LOG", 'y' );
	$c->set( "CONFIG_NF_CONNTRACK_MARK", 'y' );
	$c->set( "CONFIG_NF_CONNTRACK_EVENTS", 'y' );
	$c->set( "CONFIG_NF_CT_NETLINK", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_MARK", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_CONNMARK", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_TARGET_CLASSIFY", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_TARGET_CONNMARK", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_TARGET_NETMAP", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_TARGET_NFLOG", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_TARGET_NFQUEUE", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_MATCH_CONNMARK", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_MATCH_HELPER", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_MATCH_TCPMSS", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_MATCH_TIME", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_MATCH_ADDRTYPE", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_MATCH_BLOG", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_MATCH_FLOWLABEL", 'y' );
	$c->set( "CONFIG_NETFILTER_XT_MATCH_U32", 'y' );
	$c->set( "CONFIG_NF_REJECT_IPV4", 'y' );
	$c->set( "CONFIG_IP_NF_TARGET_REJECT", 'y' );
	$c->set( "CONFIG_IP_NF_TARGET_NETMAP", 'y' );
	$c->set( "CONFIG_IP_NF_RAW", 'y' );
	$c->set( "CONFIG_NF_DEFRAG_IPV6", 'y' );
	$c->set( "CONFIG_NF_CONNTRACK_IPV6", 'y' );
	$c->set( "CONFIG_NF_NAT_IPV6", 'y' );
	$c->set( "CONFIG_IP6_NF_IPTABLES", 'y' );
	$c->set( "CONFIG_IP6_NF_FILTER", 'y' );
	$c->unset( "CONFIG_IP6_NF_MANGLE" );
	$c->unset( "CONFIG_IP6_NF_RAW" );
}

$c->set( "CONFIG_NF_REJECT_IPV4", 'y' );
$c->set( "CONFIG_IP_NF_TARGET_REJECT", 'y' );
$c->set( "CONFIG_NF_REJECT_IPV6", 'y' );
$c->set( "CONFIG_IP6_NF_TARGET_REJECT", 'y' );
$c->set( "CONFIG_NETFILTER_XT_MATCH_COMMENT", 'm' );

$c->write();

