Package org.jnode.net.arp

Source Code of org.jnode.net.arp.ARPNetworkLayer

/*
* $Id$
*
* Copyright (C) 2003-2014 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library 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 Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

package org.jnode.net.arp;

import java.net.SocketException;
import java.util.ArrayList;
import java.util.Collection;
import org.apache.log4j.Logger;
import org.jnode.annotation.SharedStatics;
import org.jnode.driver.ApiNotFoundException;
import org.jnode.driver.Device;
import org.jnode.driver.net.NetDeviceAPI;
import org.jnode.driver.net.NetworkException;
import org.jnode.net.HardwareAddress;
import org.jnode.net.InvalidLayerException;
import org.jnode.net.LayerAlreadyRegisteredException;
import org.jnode.net.NetworkLayer;
import org.jnode.net.NoSuchProtocolException;
import org.jnode.net.ProtocolAddress;
import org.jnode.net.ProtocolAddressInfo;
import org.jnode.net.SocketBuffer;
import org.jnode.net.TransportLayer;
import org.jnode.net.ethernet.EthernetConstants;
import org.jnode.util.TimeoutException;
import org.jnode.vm.objects.Statistics;

/**
* @author epr
*/
@SharedStatics
public class ARPNetworkLayer implements NetworkLayer {

    private static final int IPv4_PROTOCOL_SIZE = 4;

    /**
     * Delay between ARP requests in millisecond
     */
    public static final int ARP_REQUEST_DELAY = 1500;

    /**
     * My logger
     */
    private static final Logger log = Logger.getLogger(ARPNetworkLayer.class);

    private static final boolean DEBUG = false;

    /**
     * My statistics
     */
    private final ARPStatistics stat = new ARPStatistics();

    /**
     * ARP cache
     */
    private static final ARPCache cache = new ARPCache();

    /**
     * Create a new instance
     */
    public ARPNetworkLayer() {
    }

    /**
     * Gets the name of this type
     */
    public String getName() {
        return "arp";
    }

    /**
     * Gets the protocol ID this packettype handles
     */
    public int getProtocolID() {
        return EthernetConstants.ETH_P_ARP;
    }

    /**
     * Can this packet type process packets received from the given device?
     */
    public boolean isAllowedForDevice(Device dev) {
        // For all devices
        return true;
    }

    /**
     * Process a packet that has been received and matches getType()
     *
     * @param skbuf
     * @param deviceAPI
     * @throws SocketException
     */
    public void receive(SocketBuffer skbuf, NetDeviceAPI deviceAPI) throws SocketException {

        // Update statistics
        stat.ipackets.inc();

        final ARPHeader hdr = new ARPHeader(skbuf);
        skbuf.setNetworkLayerHeader(hdr);
        skbuf.pull(hdr.getLength());

        // Update the cache
        cache.set(hdr.getSrcHWAddress(), hdr.getSrcPAddress(), true);

        // Should we reply?
        switch (hdr.getOperation()) {
            case ARP_REQUEST:
                processARPRequest(skbuf, hdr, deviceAPI);
                break;
            case ARP_REPLY:
                processARPReply(skbuf, hdr, deviceAPI);
                break;
            case RARP_REQUEST:
                processRARPRequest(skbuf, hdr, deviceAPI);
                break;
            case RARP_REPLY:
                processRARPReply(skbuf, hdr, deviceAPI);
                break;
            default: {
                log.debug("Unknown ARP operation " + hdr.getOperation());
            }
        }
    }

    /**
     * Process and ARP request.
     *
     * @param skbuf
     * @param hdr
     * @param deviceAPI
     * @throws NetworkException
     */
    private void processARPRequest(SocketBuffer skbuf, ARPHeader hdr, NetDeviceAPI deviceAPI)
        throws SocketException {

        final ProtocolAddressInfo addrInfo = deviceAPI.getProtocolAddressInfo(hdr.getPType());
        if ((addrInfo != null) && (addrInfo.contains(hdr.getTargetPAddress()))) {
            // log.debug("Sending ARP reply");
            stat.arpreply.inc();
            stat.opackets.inc();
            hdr.swapAddresses();
            hdr.setSrcHWAddress(deviceAPI.getAddress());
            hdr.setOperation(ARPOperation.ARP_REPLY);
            skbuf.clear();
            skbuf.setProtocolID(getProtocolID());
            hdr.prefixTo(skbuf);
            deviceAPI.transmit(skbuf, hdr.getTargetHWAddress());
        } else {
            // log.debug("ARP request, not my IP-address");
        }
    }

    /**
     * Process and ARP reply
     *
     * @param skbuf
     * @param hdr
     * @param deviceAPI
     * @throws NetworkException
     */
    private void processARPReply(SocketBuffer skbuf, ARPHeader hdr, NetDeviceAPI deviceAPI)
        throws SocketException {
        // Nothing further todo
    }

    /**
     * Process and RARP request
     *
     * @param skbuf
     * @param hdr
     * @param deviceAPI
     * @throws NetworkException
     */
    private void processRARPRequest(SocketBuffer skbuf, ARPHeader hdr, NetDeviceAPI deviceAPI)
        throws SocketException {
        stat.rarpreq.inc();
        log.debug("GOT RARP Request");
    }

    /**
     * Process and RARP reply
     *
     * @param skbuf
     * @param hdr
     * @param deviceAPI
     * @throws NetworkException
     */
    private void processRARPReply(SocketBuffer skbuf, ARPHeader hdr, NetDeviceAPI deviceAPI)
        throws SocketException {
        log.debug("GOT RARP Reply");
    }

    /**
     * Gets the ARP cache.
     */
    public ARPCache getCache() {
        return cache;
    }

    /**
     * @see org.jnode.net.NetworkLayer#getStatistics()
     */
    public Statistics getStatistics() {
        return stat;
    }

    /**
     * @see org.jnode.net.NetworkLayer#registerTransportLayer(org.jnode.net.TransportLayer)
     */
    public void registerTransportLayer(TransportLayer layer)
        throws LayerAlreadyRegisteredException, InvalidLayerException {
        throw new InvalidLayerException("ARP cannot register transportlayers");
    }

    /**
     * @see org.jnode.net.NetworkLayer#unregisterTransportLayer(org.jnode.net.TransportLayer)
     */
    public void unregisterTransportLayer(TransportLayer layer) {
        // Just ignore
    }

    /**
     * Gets all registered transport-layers
     */
    public Collection<TransportLayer> getTransportLayers() {
        return new ArrayList<TransportLayer>(0);
    }

    /**
     * Gets a registered transportlayer by its protocol ID.
     *
     * @param protocolID
     */
    public TransportLayer getTransportLayer(int protocolID) throws NoSuchProtocolException {
        throw new NoSuchProtocolException("protocol " + protocolID);
    }

    /**
     * Gets the hardware address for a given protocol address.
     *
     * @param address
     * @param myAddress
     * @param device
     * @param timeout
     * @throws TimeoutException
     * @throws NetworkException
     */
    public HardwareAddress getHardwareAddress(ProtocolAddress address, ProtocolAddress myAddress,
                                              Device device, long timeout) throws TimeoutException, NetworkException {
        final long start = System.currentTimeMillis();
        long lastReq = 0;

        if (DEBUG) {
            if (log.isDebugEnabled()) {
                log.debug("getHardwareAddress(" + address + ", " + myAddress + ", " + device.getId() +
                    ", " + timeout + ')');
            }
        }

        if (address.equals(myAddress)) {
            // This is simple, just return my address
            return getAPI(device).getAddress();
        }

        while (true) {
            final HardwareAddress hwAddress = cache.get(address);
            if (hwAddress != null) {
                return hwAddress;
            }
            final long now = System.currentTimeMillis();
            if ((now - start) >= timeout) {
                // Still not correct response
                throw new TimeoutException("Timeout in ARP request");
            }
            // Try to send a request every few seconds
            if ((now - lastReq) >= ARP_REQUEST_DELAY) {
                lastReq = now;
                request(address, myAddress, device);
            } else {
                cache.waitForChanges(Math.min(timeout, ARP_REQUEST_DELAY));
            }
        }

    }

    /**
     * Gets the protocol addresses for a given name, or null if not found.
     *
     * @param hostname
     * @return the addresses or {@code null}
     */
    public ProtocolAddress[] getHostByName(String hostname) {
        return null;
    }

    /**
     * Create and transmit an ARP request
     *
     * @param address
     * @param myAddress
     * @param device
     */
    private void request(ProtocolAddress address, ProtocolAddress myAddress, Device device)
        throws NetworkException {
        // Not found in the cache, make a request
        final NetDeviceAPI api = getAPI(device);
        final HardwareAddress srcHwAddr = api.getAddress();
        final HardwareAddress trgHwAddr = srcHwAddr.getDefaultBroadcastAddress();
        final ARPOperation op = ARPOperation.ARP_REQUEST;
        final int hwtype = srcHwAddr.getType();
        final int ptype = address.getType();

        final ARPHeader hdr =
            new ARPHeader(srcHwAddr, myAddress, trgHwAddr, address, op, hwtype, ptype, EthernetConstants.ETH_ALEN,
                IPv4_PROTOCOL_SIZE);
        final SocketBuffer skbuf = new SocketBuffer();
        skbuf.setProtocolID(EthernetConstants.ETH_P_ARP);
        hdr.prefixTo(skbuf);

        api.transmit(skbuf, trgHwAddr);
    }

    /**
     * Gets the NetDeviceAPI for a given device
     *
     * @param device
     */
    private NetDeviceAPI getAPI(Device device) {
        try {
            return device.getAPI(NetDeviceAPI.class);
        } catch (ApiNotFoundException ex) {
            throw new IllegalArgumentException("Not a network device " + device.getId());
        }
    }
}
TOP

Related Classes of org.jnode.net.arp.ARPNetworkLayer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.