Fix naming conventions for CORD apps.

Change-Id: I0b1d4dd276301b726269376eec137511c8e0a805
diff --git a/src/main/java/org/onosproject/aaa/AaaManager.java b/src/main/java/org/onosproject/aaa/AaaManager.java
new file mode 100644
index 0000000..dd324ee
--- /dev/null
+++ b/src/main/java/org/onosproject/aaa/AaaManager.java
@@ -0,0 +1,562 @@
+/*
+ * Copyright 2015 AT&T Foundry
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.aaa;
+
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onlab.packet.DeserializationException;
+import org.onlab.packet.EAP;
+import org.onlab.packet.EAPOL;
+import org.onlab.packet.EthType;
+import org.onlab.packet.Ethernet;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.RADIUS;
+import org.onlab.packet.RADIUSAttribute;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.config.ConfigFactory;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigRegistry;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.packet.DefaultOutboundPacket;
+import org.onosproject.net.packet.InboundPacket;
+import org.onosproject.net.packet.OutboundPacket;
+import org.onosproject.net.packet.PacketContext;
+import org.onosproject.net.packet.PacketProcessor;
+import org.onosproject.net.packet.PacketService;
+import org.onosproject.xosintegration.VoltTenantService;
+import org.slf4j.Logger;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.nio.ByteBuffer;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+
+import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
+import static org.onosproject.net.packet.PacketPriority.CONTROL;
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * AAA application for ONOS.
+ */
+@Component(immediate = true)
+public class AaaManager {
+
+    // for verbose output
+    private final Logger log = getLogger(getClass());
+
+    // a list of our dependencies :
+    // to register with ONOS as an application - described next
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    // to receive Packet-in events that we'll respond to
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected PacketService packetService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected VoltTenantService voltTenantService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected NetworkConfigRegistry netCfgService;
+
+    // Parsed RADIUS server addresses
+    protected InetAddress radiusIpAddress;
+    protected String radiusMacAddress;
+
+    // NAS IP address
+    protected InetAddress nasIpAddress;
+    protected String nasMacAddress;
+
+    // RADIUS server secret
+    protected String radiusSecret;
+
+    // ID of RADIUS switch
+    protected String radiusSwitch;
+
+    // RADIUS port number
+    protected long radiusPort;
+
+    // RADIUS server TCP port number
+    protected short radiusServerPort;
+
+    // our application-specific event handler
+    private ReactivePacketProcessor processor = new ReactivePacketProcessor();
+
+    // our unique identifier
+    private ApplicationId appId;
+
+    // Socket used for UDP communications with RADIUS server
+    private DatagramSocket radiusSocket;
+
+    // Executor for RADIUS communication thread
+    private ExecutorService executor;
+
+    // Configuration properties factory
+    private final ConfigFactory factory =
+            new ConfigFactory<ApplicationId, AaaConfig>(APP_SUBJECT_FACTORY,
+                                                         AaaConfig.class,
+                                                         "AAA") {
+                @Override
+                public AaaConfig createConfig() {
+                    return new AaaConfig();
+                }
+            };
+
+    // Listener for config changes
+    private final InternalConfigListener cfgListener = new InternalConfigListener();
+
+    /**
+     * Builds an EAPOL packet based on the given parameters.
+     *
+     * @param dstMac    destination MAC address
+     * @param srcMac    source MAC address
+     * @param vlan      vlan identifier
+     * @param eapolType EAPOL type
+     * @param eap       EAP payload
+     * @return Ethernet frame
+     */
+    private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
+                                               short vlan, byte eapolType, EAP eap) {
+
+        Ethernet eth = new Ethernet();
+        eth.setDestinationMACAddress(dstMac.toBytes());
+        eth.setSourceMACAddress(srcMac.toBytes());
+        eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
+        if (vlan != Ethernet.VLAN_UNTAGGED) {
+            eth.setVlanID(vlan);
+        }
+        //eapol header
+        EAPOL eapol = new EAPOL();
+        eapol.setEapolType(eapolType);
+        eapol.setPacketLength(eap.getLength());
+
+        //eap part
+        eapol.setPayload(eap);
+
+        eth.setPayload(eapol);
+        eth.setPad(true);
+        return eth;
+    }
+
+    @Activate
+    public void activate() {
+        netCfgService.addListener(cfgListener);
+        netCfgService.registerConfigFactory(factory);
+
+        // "org.onosproject.aaa" is the FQDN of our app
+        appId = coreService.registerApplication("org.onosproject.aaa");
+
+        cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AaaConfig.class));
+
+        // register our event handler
+        packetService.addProcessor(processor, PacketProcessor.director(2));
+        requestIntercepts();
+
+        StateMachine.initializeMaps();
+
+        try {
+            radiusSocket = new DatagramSocket(radiusServerPort);
+        } catch (Exception ex) {
+            log.error("Can't open RADIUS socket", ex);
+        }
+
+        executor = Executors.newSingleThreadExecutor(
+                new ThreadFactoryBuilder()
+                        .setNameFormat("AAA-radius-%d").build());
+        executor.execute(radiusListener);
+    }
+
+    @Deactivate
+    public void deactivate() {
+        appId = coreService.registerApplication("org.onosproject.aaa");
+        withdrawIntercepts();
+        // de-register and null our handler
+        packetService.removeProcessor(processor);
+        processor = null;
+        StateMachine.destroyMaps();
+        radiusSocket.close();
+        executor.shutdownNow();
+    }
+
+    protected void sendRadiusPacket(RADIUS radiusPacket) {
+
+        try {
+            final byte[] data = radiusPacket.serialize();
+            final DatagramSocket socket = radiusSocket;
+
+            DatagramPacket packet =
+                    new DatagramPacket(data, data.length,
+                                       radiusIpAddress, radiusServerPort);
+
+            socket.send(packet);
+        } catch (IOException e) {
+            log.info("Cannot send packet to RADIUS server", e);
+        }
+    }
+
+    /**
+     * Request packet in via PacketService.
+     */
+    private void requestIntercepts() {
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
+        packetService.requestPackets(selector.build(),
+                                     CONTROL, appId);
+    }
+
+    /**
+     * Cancel request for packet in via PacketService.
+     */
+    private void withdrawIntercepts() {
+        TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
+        selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
+        packetService.cancelPackets(selector.build(), CONTROL, appId);
+    }
+
+    /**
+     * Send the ethernet packet to the supplicant.
+     *
+     * @param ethernetPkt  the ethernet packet
+     * @param connectPoint the connect point to send out
+     */
+    private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
+        TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
+        OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
+                                                          treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
+        packetService.emit(packet);
+    }
+
+    // our handler defined as a private inner class
+
+    /**
+     * Packet processor responsible for forwarding packets along their paths.
+     */
+    private class ReactivePacketProcessor implements PacketProcessor {
+        @Override
+        public void process(PacketContext context) {
+
+            // Extract the original Ethernet frame from the packet information
+            InboundPacket pkt = context.inPacket();
+            Ethernet ethPkt = pkt.parsed();
+            if (ethPkt == null) {
+                return;
+            }
+            try {
+                // identify if incoming packet comes from supplicant (EAP) or RADIUS
+                switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
+                    case EAPOL:
+                        handleSupplicantPacket(context.inPacket());
+                        break;
+                    default:
+                        log.trace("Skipping Ethernet packet type {}",
+                                  EthType.EtherType.lookup(ethPkt.getEtherType()));
+                }
+            } catch (StateMachineException e) {
+                log.warn("Unable to process RADIUS packet:", e);
+            }
+        }
+
+        /**
+         * Creates and initializes common fields of a RADIUS packet.
+         *
+         * @param stateMachine state machine for the request
+         * @param eapPacket  EAP packet
+         * @return RADIUS packet
+         */
+        private RADIUS getRadiusPayload(StateMachine stateMachine, byte identifier, EAP eapPacket) {
+            RADIUS radiusPayload =
+                    new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
+                               eapPacket.getIdentifier());
+
+            // set Request Authenticator in StateMachine
+            stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
+
+            radiusPayload.setIdentifier(identifier);
+            radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
+                                       stateMachine.username());
+
+            radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
+                    AaaManager.this.nasIpAddress.getAddress());
+
+            radiusPayload.encapsulateMessage(eapPacket);
+
+            return radiusPayload;
+        }
+
+        /**
+         * Handles PAE packets (supplicant).
+         *
+         * @param inPacket Ethernet packet coming from the supplicant
+         */
+        private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
+            Ethernet ethPkt = inPacket.parsed();
+            // Where does it come from?
+            MacAddress srcMac = ethPkt.getSourceMAC();
+
+            DeviceId deviceId = inPacket.receivedFrom().deviceId();
+            PortNumber portNumber = inPacket.receivedFrom().port();
+            String sessionId = deviceId.toString() + portNumber.toString();
+            StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
+            if (stateMachine == null) {
+                stateMachine = new StateMachine(sessionId, voltTenantService);
+            }
+
+
+            EAPOL eapol = (EAPOL) ethPkt.getPayload();
+
+            switch (eapol.getEapolType()) {
+                case EAPOL.EAPOL_START:
+                    stateMachine.start();
+                    stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
+
+                    //send an EAP Request/Identify to the supplicant
+                    EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
+                    Ethernet eth = buildEapolResponse(srcMac, MacAddress.valueOf(nasMacAddress),
+                                                      ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
+                                                      eapPayload);
+                    stateMachine.setSupplicantAddress(srcMac);
+                    stateMachine.setVlanId(ethPkt.getVlanID());
+
+                    sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+
+                    break;
+                case EAPOL.EAPOL_PACKET:
+                    RADIUS radiusPayload;
+                    // check if this is a Response/Identify or  a Response/TLS
+                    EAP eapPacket = (EAP) eapol.getPayload();
+
+                    byte dataType = eapPacket.getDataType();
+                    switch (dataType) {
+
+                        case EAP.ATTR_IDENTITY:
+                            // request id access to RADIUS
+                            stateMachine.setUsername(eapPacket.getData());
+
+                            radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
+                            radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
+
+                            sendRadiusPacket(radiusPayload);
+
+                            // change the state to "PENDING"
+                            stateMachine.requestAccess();
+                            break;
+                        case EAP.ATTR_MD5:
+                            // verify if the EAP identifier corresponds to the
+                            // challenge identifier from the client state
+                            // machine.
+                            if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
+                                //send the RADIUS challenge response
+                                radiusPayload =
+                                        getRadiusPayload(stateMachine,
+                                                         stateMachine.identifier(),
+                                                         eapPacket);
+
+                                radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
+                                                           stateMachine.challengeState());
+                                radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
+                                sendRadiusPacket(radiusPayload);
+                            }
+                            break;
+                        case EAP.ATTR_TLS:
+                            // request id access to RADIUS
+                            radiusPayload = getRadiusPayload(stateMachine, stateMachine.identifier(), eapPacket);
+
+                            radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
+                                    stateMachine.challengeState());
+                            stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
+
+                            radiusPayload.addMessageAuthenticator(AaaManager.this.radiusSecret);
+                            sendRadiusPacket(radiusPayload);
+
+                            if (stateMachine.state() != StateMachine.STATE_PENDING) {
+                                stateMachine.requestAccess();
+                            }
+
+                            break;
+                        default:
+                            return;
+                    }
+                    break;
+                default:
+                    log.trace("Skipping EAPOL message {}", eapol.getEapolType());
+            }
+
+        }
+    }
+
+    class RadiusListener implements Runnable {
+
+        /**
+         * Handles RADIUS packets.
+         *
+         * @param radiusPacket RADIUS packet coming from the RADIUS server.
+         * @throws StateMachineException if an illegal state transition is triggered
+         */
+        protected void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
+            StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
+            if (stateMachine == null) {
+                log.error("Invalid session identifier, exiting...");
+                return;
+            }
+
+            EAP eapPayload;
+            Ethernet eth;
+            switch (radiusPacket.getCode()) {
+                case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
+                    byte[] challengeState =
+                            radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue();
+                    eapPayload = radiusPacket.decapsulateMessage();
+                    stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
+                    eth = buildEapolResponse(stateMachine.supplicantAddress(),
+                                             MacAddress.valueOf(nasMacAddress),
+                                             stateMachine.vlanId(),
+                                             EAPOL.EAPOL_PACKET,
+                                             eapPayload);
+                    sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+                    break;
+                case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
+                    //send an EAPOL - Success to the supplicant.
+                    byte[] eapMessage =
+                            radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
+                    eapPayload = new EAP();
+                    eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length);
+                    eth = buildEapolResponse(stateMachine.supplicantAddress(),
+                                             MacAddress.valueOf(nasMacAddress),
+                                             stateMachine.vlanId(),
+                                             EAPOL.EAPOL_PACKET,
+                                             eapPayload);
+                    sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
+
+                    stateMachine.authorizeAccess();
+                    break;
+                case RADIUS.RADIUS_CODE_ACCESS_REJECT:
+                    stateMachine.denyAccess();
+                    break;
+                default:
+                    log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
+            }
+        }
+
+
+        @Override
+        public void run() {
+            boolean done = false;
+            int packetNumber = 1;
+
+            log.info("UDP listener thread starting up");
+            RADIUS inboundRadiusPacket;
+            while (!done) {
+                try {
+                    byte[] packetBuffer = new byte[RADIUS.RADIUS_MAX_LENGTH];
+                    DatagramPacket inboundBasePacket =
+                            new DatagramPacket(packetBuffer, packetBuffer.length);
+                    DatagramSocket socket = radiusSocket;
+                    socket.receive(inboundBasePacket);
+                    log.info("Packet #{} received", packetNumber++);
+                    try {
+                        inboundRadiusPacket =
+                                RADIUS.deserializer()
+                                        .deserialize(inboundBasePacket.getData(),
+                                                     0,
+                                                     inboundBasePacket.getLength());
+                        handleRadiusPacket(inboundRadiusPacket);
+                    } catch (DeserializationException dex) {
+                        log.error("Cannot deserialize packet", dex);
+                    } catch (StateMachineException sme) {
+                        log.error("Illegal state machine operation", sme);
+                    }
+
+                } catch (IOException e) {
+                    log.info("Socket was closed, exiting listener thread");
+                    done = true;
+                }
+            }
+        }
+    }
+
+    RadiusListener radiusListener = new RadiusListener();
+
+    private class InternalConfigListener implements NetworkConfigListener {
+
+        /**
+         * Reconfigures the DHCP Server according to the configuration parameters passed.
+         *
+         * @param cfg configuration object
+         */
+        private void reconfigureNetwork(AaaConfig cfg) {
+            AaaConfig newCfg;
+            if (cfg == null) {
+                newCfg = new AaaConfig();
+            } else {
+                newCfg = cfg;
+            }
+            if (newCfg.nasIp() != null) {
+                nasIpAddress = newCfg.nasIp();
+            }
+            if (newCfg.radiusIp() != null) {
+                radiusIpAddress = newCfg.radiusIp();
+            }
+            if (newCfg.radiusMac() != null) {
+                radiusMacAddress = newCfg.radiusMac();
+            }
+            if (newCfg.nasMac() != null) {
+                nasMacAddress = newCfg.nasMac();
+            }
+            if (newCfg.radiusSecret() != null) {
+                radiusSecret = newCfg.radiusSecret();
+            }
+            if (newCfg.radiusSwitch() != null) {
+                radiusSwitch = newCfg.radiusSwitch();
+            }
+            if (newCfg.radiusPort() != -1) {
+                radiusPort = newCfg.radiusPort();
+            }
+            if (newCfg.radiusServerUdpPort() != -1) {
+                radiusServerPort = newCfg.radiusServerUdpPort();
+            }
+        }
+
+        @Override
+        public void event(NetworkConfigEvent event) {
+
+            if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
+                    event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
+                    event.configClass().equals(AaaConfig.class)) {
+
+                AaaConfig cfg = netCfgService.getConfig(appId, AaaConfig.class);
+                reconfigureNetwork(cfg);
+                log.info("Reconfigured");
+            }
+        }
+    }
+
+
+}