/*package net.floodlightcontroller.teltonikadhcprewrite; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Map; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.openflow.protocol.OFFlowMod; import org.openflow.protocol.OFMatch; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPacketIn; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFType; import org.openflow.protocol.action.OFAction; import org.openflow.protocol.action.OFActionOutput; import org.openflow.protocol.action.OFActionType; import org.openflow.protocol.action.OFActionNetworkLayerDestination; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.floodlightcontroller.core.FloodlightContext; import net.floodlightcontroller.core.IFloodlightProviderService; import net.floodlightcontroller.core.IOFMessageListener; import net.floodlightcontroller.core.IOFSwitch; import net.floodlightcontroller.core.module.FloodlightModuleContext; import net.floodlightcontroller.core.module.FloodlightModuleException; import net.floodlightcontroller.core.module.IFloodlightModule; import net.floodlightcontroller.core.module.IFloodlightService; import net.floodlightcontroller.forwarding.Forwarding; import net.floodlightcontroller.packet.DHCP.DHCPOptionCode; import net.floodlightcontroller.packet.Ethernet; import net.floodlightcontroller.packet.IPv4; import net.floodlightcontroller.packet.UDP; import net.floodlightcontroller.packet.DHCP; import net.floodlightcontroller.packet.DHCPOption; import net.floodlightcontroller.staticflowentry.IStaticFlowEntryPusherService; import net.floodlightcontroller.util.MACAddress; public class TeltonikaDHCPRewrite implements IOFMessageListener, IFloodlightModule { protected static Logger log; protected IFloodlightProviderService floodlightProvider; protected IStaticFlowEntryPusherService sfp; /** START CONFIG FILE VARIABLES * // These variables are set using the floodlightdefault.properties file // Refer to startup() for a list of the expected names in the config file private static byte[] MY_DHCP_SERVER_IP; // Same as CONTROLLER_IP but in byte[] form private static byte[] MY_SUBNET_MASK; private static byte[] MY_BROADCAST_IP; private static byte[] MY_IP_ADDRESS; private static byte[] MY_ROUTER_IP = null; /** END CONFIG FILE VARIABLES * /** * DHCP messages are either: * REQUEST (client --0x01--> server) * or REPLY (server --0x02--> client) public static byte DHCP_OPCODE_REQUEST = intToBytes(1)[0]; public static byte DHCP_OPCODE_REPLY = intToBytes(2)[0]; /** * DHCP REQUEST messages are either of type: * DISCOVER (0x01) * REQUEST (0x03) * DECLINE (0x04) * RELEASE (0x07) * or INFORM (0x08) * DHCP REPLY messages are either of type: * OFFER (0x02) * ACK (0x05) * or NACK (0x06) ** public static byte[] DHCP_MSG_TYPE_DISCOVER = intToBytesSizeOne(1); public static byte[] DHCP_MSG_TYPE_OFFER = intToBytesSizeOne(2); public static byte[] DHCP_MSG_TYPE_REQUEST = intToBytesSizeOne(3); public static byte[] DHCP_MSG_TYPE_DECLINE = intToBytesSizeOne(4); public static byte[] DHCP_MSG_TYPE_ACK = intToBytesSizeOne(5); public static byte[] DHCP_MSG_TYPE_NACK = intToBytesSizeOne(6); public static byte[] DHCP_MSG_TYPE_RELEASE = intToBytesSizeOne(7); public static byte[] DHCP_MSG_TYPE_INFORM = intToBytesSizeOne(8); /** * DHCP messages contain options requested by the client and * provided by the server. The options requested by the client are * provided in a list (option 0x37 below) and the server elects to * answer some or all of these options and may provide additional * options as necessary for the DHCP client to obtain a lease. * OPTION NAME HEX DEC * Subnet Mask 0x01 1 * Router IP 0x03 3 * DNS Server IP 0x06 6 * Domain Name 0x0F 15 * IP Forwarding 0x13 19 * Broadcast IP 0x1C 28 * NTP Server IP 0x2A 42 * NetBios Name IP 0x2C 44 * NetBios DDS IP 0x2D 45 * NetBios Node Type 0x2E 46 * NetBios Scope ID 0x2F 47 * Requested IP 0x32 50 * Lease Time (s) 0x33 51 * Msg Type (above) 0x35 53 * DHCP Server IP 0x36 54 * Option List (this) 0x37 55 * Renewal Time (s) 0x3A 58 * Rebind Time (s) 0x3B 59 * End Option List 0xFF 255 ** public static byte DHCP_REQ_PARAM_OPTION_CODE_SN = intToBytes(1)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_ROUTER = intToBytes(3)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_DNS = intToBytes(6)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_DN = intToBytes(15)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_IP_FORWARDING = intToBytes(19)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_BROADCAST_IP = intToBytes(28)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_NTP_IP = intToBytes(42)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_NET_BIOS_NAME_IP = intToBytes(44)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_NET_BIOS_DDS_IP = intToBytes(45)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_NET_BIOS_NODE_TYPE = intToBytes(46)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_NET_BIOS_SCOPE_ID = intToBytes(47)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_REQUESTED_IP = intToBytes(50)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_LEASE_TIME = intToBytes(51)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_MSG_TYPE = intToBytes(53)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_DHCP_SERVER = intToBytes(54)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_REQUESTED_PARAMTERS = intToBytes(55)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_RENEWAL_TIME = intToBytes(58)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_REBIND_TIME = intToBytes(59)[0]; public static byte DHCP_REQ_PARAM_OPTION_CODE_END = intToBytes(255)[0]; public static final byte[] BROADCAST_MAC = Ethernet.toMACAddress("FF:FF:FF:FF:FF:FF"); public static final int BROADCAST_IP = IPv4.toIPv4Address(IPv4.toIPv4AddressBytes("255.255.255.255")); public static final int UNASSIGNED_IP = IPv4.toIPv4Address(IPv4.toIPv4AddressBytes("0.0.0.0")); @Override public Collection<Class<? extends IFloodlightService>> getModuleDependencies() { Collection<Class<? extends IFloodlightService>> l = new ArrayList<Class<? extends IFloodlightService>>(); l.add(IFloodlightProviderService.class); return l; } @Override public void init(FloodlightModuleContext context) throws FloodlightModuleException { floodlightProvider = context.getServiceImpl(IFloodlightProviderService.class); sfp = context.getServiceImpl(IStaticFlowEntryPusherService.class); log = LoggerFactory.getLogger(TeltonikaDHCPRewrite.class); } @Override public void startUp(FloodlightModuleContext context) { floodlightProvider.addOFMessageListener(OFType.PACKET_IN, this); // Read our config options for the DHCP DHCPServer Map<String, String> configOptions = context.getConfigParams(this); try { MY_SUBNET_MASK = IPv4.toIPv4AddressBytes(configOptions.get("my-subnet-mask")); MY_IP_ADDRESS = IPv4.toIPv4AddressBytes(configOptions.get("my-ip-address")); MY_BROADCAST_IP = IPv4.toIPv4AddressBytes(configOptions.get("my-broadcast-address")); MY_ROUTER_IP = IPv4.toIPv4AddressBytes(configOptions.get("my-router")); } catch(IllegalArgumentException ex) { log.error("Incorrect DHCP configuration options", ex); throw ex; } catch(NullPointerException ex) { log.error("Incorrect DHCP configuration options", ex); throw ex; } } @Override public Collection<Class<? extends IFloodlightService>> getModuleServices() { return null; } @Override public Map<Class<? extends IFloodlightService>, IFloodlightService> getServiceImpls() { return null; } @Override public String getName() { return TeltonikaDHCPRewrite.class.getSimpleName(); } @Override public boolean isCallbackOrderingPrereq(OFType type, String name) { return false; } @Override public boolean isCallbackOrderingPostreq(OFType type, String name) { // We will rely on forwarding to forward out any DHCP packets that are not // destined for our DHCP server. This is to allow an environment where // multiple DHCP servers operate cooperatively if (type == OFType.PACKET_IN && name.equals(Forwarding.class.getSimpleName())) { return true; } else { return false; } } public static byte[] intToBytes(int integer) { byte[] bytes = new byte[4]; bytes[3] = (byte) (integer >> 24); bytes[2] = (byte) (integer >> 16); bytes[1] = (byte) (integer >> 8); bytes[0] = (byte) (integer); return bytes; } public static byte[] intToBytesSizeOne(int integer) { byte[] bytes = new byte[1]; bytes[0] = (byte) (integer); return bytes; } public void sendDHCPOffer(IOFSwitch sw, short inPort, byte[] chaddr, int dstIPAddr, int yiaddr, int giaddr, int xid, ArrayList<Byte> requestOrder) { // Compose DHCP OFFER /** (2) DHCP Offer * -- UDP src port = 67 * -- UDP dst port = 68 * -- IP src addr = DHCP DHCPServer's IP * -- IP dst addr = 255.255.255.255 * -- Opcode = 0x02 * -- XID = transactionX * -- ciaddr = blank * -- yiaddr = offer IP * -- siaddr = DHCP DHCPServer IP * -- giaddr = blank * -- chaddr = Client's MAC * -- Options: * -- Option 53 = DHCP Offer * -- Option 1 = SN Mask IP * -- Option 3 = Router IP * -- Option 51 = Lease time (s) * -- Option 54 = DHCP DHCPServer IP * -- Option 6 = DNS servers ** OFPacketOut DHCPOfferPacket = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); DHCPOfferPacket.setBufferId(-1); Ethernet ethDHCPOffer = new Ethernet(); ethDHCPOffer.setSourceMACAddress(CONTROLLER_MAC); ethDHCPOffer.setDestinationMACAddress(chaddr); ethDHCPOffer.setEtherType(Ethernet.TYPE_IPv4); IPv4 ipv4DHCPOffer = new IPv4(); if (dstIPAddr == 0) { ipv4DHCPOffer.setDestinationAddress(BROADCAST_IP); } else { // Client has IP and dhcpc must have crashed ipv4DHCPOffer.setDestinationAddress(dstIPAddr); } ipv4DHCPOffer.setSourceAddress(CONTROLLER_IP); ipv4DHCPOffer.setProtocol(IPv4.PROTOCOL_UDP); ipv4DHCPOffer.setTtl((byte) 64); UDP udpDHCPOffer = new UDP(); udpDHCPOffer.setDestinationPort(UDP.DHCP_CLIENT_PORT); udpDHCPOffer.setSourcePort(UDP.DHCP_SERVER_PORT); DHCP dhcpDHCPOffer = new DHCP(); dhcpDHCPOffer.setOpCode(DHCP_OPCODE_REPLY); dhcpDHCPOffer.setHardwareType((byte) 1); dhcpDHCPOffer.setHardwareAddressLength((byte) 6); dhcpDHCPOffer.setHops((byte) 0); dhcpDHCPOffer.setTransactionId(xid); dhcpDHCPOffer.setSeconds((short) 0); dhcpDHCPOffer.setFlags((short) 0); dhcpDHCPOffer.setClientIPAddress(UNASSIGNED_IP); dhcpDHCPOffer.setYourIPAddress(yiaddr); dhcpDHCPOffer.setServerIPAddress(CONTROLLER_IP); dhcpDHCPOffer.setGatewayIPAddress(giaddr); dhcpDHCPOffer.setClientHardwareAddress(chaddr); List<DHCPOption> dhcpOfferOptions = new ArrayList<DHCPOption>(); DHCPOption newOption; newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_MSG_TYPE); newOption.setData(DHCP_MSG_TYPE_OFFER); newOption.setLength((byte) 1); dhcpOfferOptions.add(newOption); for (Byte specificRequest : requestOrder) { if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_SN) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_SN); newOption.setData(DHCP_SERVER_SUBNET_MASK); newOption.setLength((byte) 4); dhcpOfferOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_ROUTER) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_ROUTER); newOption.setData(DHCP_SERVER_ROUTER_IP); newOption.setLength((byte) 4); dhcpOfferOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_DN) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_DN); newOption.setData(DHCP_SERVER_DN); newOption.setLength((byte) DHCP_SERVER_DN.length); dhcpOfferOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_DNS) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_DNS); newOption.setData(DHCP_SERVER_DNS_IP_LIST); newOption.setLength((byte) DHCP_SERVER_DNS_IP_LIST.length); dhcpOfferOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_BROADCAST_IP) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_BROADCAST_IP); newOption.setData(DHCP_SERVER_BROADCAST_IP); newOption.setLength((byte) 4); dhcpOfferOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_DHCP_SERVER) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_DHCP_SERVER); newOption.setData(DHCP_SERVER_DHCP_SERVER_IP); newOption.setLength((byte) 4); dhcpOfferOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_NTP_IP) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_NTP_IP); newOption.setData(DHCP_SERVER_NTP_IP_LIST); newOption.setLength((byte) DHCP_SERVER_NTP_IP_LIST.length); dhcpOfferOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_IP_FORWARDING) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_IP_FORWARDING); newOption.setData(DHCP_SERVER_IP_FORWARDING); newOption.setLength((byte) 1); dhcpOfferOptions.add(newOption); } else { //log.debug("Setting specific request for OFFER failed"); } } newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_END); newOption.setLength((byte) 0); dhcpOfferOptions.add(newOption); dhcpDHCPOffer.setOptions(dhcpOfferOptions); ethDHCPOffer.setPayload(ipv4DHCPOffer.setPayload(udpDHCPOffer.setPayload(dhcpDHCPOffer))); short packetOutLength = (short) OFPacketOut.MINIMUM_LENGTH; DHCPOfferPacket.setInPort(OFPort.OFPP_NONE.getValue()); DHCPOfferPacket.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); packetOutLength = (short) (packetOutLength + OFActionOutput.MINIMUM_LENGTH); List<OFAction> actions = new ArrayList<OFAction>(1); actions.add(new OFActionOutput(inPort, (short) 0)); DHCPOfferPacket.setActions(actions); DHCPOfferPacket.setPacketData(ethDHCPOffer.serialize()); packetOutLength = (short) (packetOutLength + ethDHCPOffer.serialize().length); DHCPOfferPacket.setLength(packetOutLength); log.debug("Sending DHCP OFFER"); try { sw.write(DHCPOfferPacket, null); } catch (IOException e) { System.out.println("Failed to write {} to switch {}: {}"); } } public void sendDHCPAck(IOFSwitch sw, short inPort, byte[] chaddr, int dstIPAddr, int yiaddr, int giaddr, int xid, ArrayList<Byte> requestOrder) { /** (4) DHCP ACK * -- UDP src port = 67 * -- UDP dst port = 68 * -- IP src addr = DHCP DHCPServer's IP * -- IP dst addr = 255.255.255.255 * -- Opcode = 0x02 * -- XID = transactionX * -- ciaddr = blank * -- yiaddr = offer IP * -- siaddr = DHCP DHCPServer IP * -- giaddr = blank * -- chaddr = Client's MAC * -- Options: * -- Option 53 = DHCP ACK * -- Option 1 = SN Mask IP * -- Option 3 = Router IP * -- Option 51 = Lease time (s) * -- Option 54 = DHCP DHCPServer IP * -- Option 6 = DNS servers ** OFPacketOut DHCPACKPacket = (OFPacketOut) floodlightProvider.getOFMessageFactory().getMessage(OFType.PACKET_OUT); DHCPACKPacket.setBufferId(-1); Ethernet ethDHCPAck = new Ethernet(); ethDHCPAck.setSourceMACAddress(CONTROLLER_MAC); ethDHCPAck.setDestinationMACAddress(chaddr); ethDHCPAck.setEtherType(Ethernet.TYPE_IPv4); IPv4 ipv4DHCPAck = new IPv4(); if (dstIPAddr == 0) { ipv4DHCPAck.setDestinationAddress(BROADCAST_IP); } else { // Client has IP and dhclient must have crashed ipv4DHCPAck.setDestinationAddress(dstIPAddr); } ipv4DHCPAck.setSourceAddress(CONTROLLER_IP); ipv4DHCPAck.setProtocol(IPv4.PROTOCOL_UDP); ipv4DHCPAck.setTtl((byte) 64); UDP udpDHCPAck = new UDP(); udpDHCPAck.setDestinationPort(UDP.DHCP_CLIENT_PORT); udpDHCPAck.setSourcePort(UDP.DHCP_SERVER_PORT); DHCP dhcpDHCPAck = new DHCP(); dhcpDHCPAck.setOpCode(DHCP_OPCODE_REPLY); dhcpDHCPAck.setHardwareType((byte) 1); dhcpDHCPAck.setHardwareAddressLength((byte) 6); dhcpDHCPAck.setHops((byte) 0); dhcpDHCPAck.setTransactionId(xid); dhcpDHCPAck.setSeconds((short) 0); dhcpDHCPAck.setFlags((short) 0); dhcpDHCPAck.setClientIPAddress(UNASSIGNED_IP); dhcpDHCPAck.setYourIPAddress(yiaddr); dhcpDHCPAck.setServerIPAddress(CONTROLLER_IP); dhcpDHCPAck.setGatewayIPAddress(giaddr); dhcpDHCPAck.setClientHardwareAddress(chaddr); List<DHCPOption> dhcpAckOptions = new ArrayList<DHCPOption>(); DHCPOption newOption; newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_MSG_TYPE); newOption.setData(DHCP_MSG_TYPE_ACK); newOption.setLength((byte) 1); dhcpAckOptions.add(newOption); for (Byte specificRequest : requestOrder) { if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_SN) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_SN); newOption.setData(DHCP_SERVER_SUBNET_MASK); newOption.setLength((byte) 4); dhcpAckOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_ROUTER) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_ROUTER); newOption.setData(DHCP_SERVER_ROUTER_IP); newOption.setLength((byte) 4); dhcpAckOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_DN) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_DN); newOption.setData(DHCP_SERVER_DN); newOption.setLength((byte) DHCP_SERVER_DN.length); dhcpAckOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_DNS) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_DNS); newOption.setData(DHCP_SERVER_DNS_IP_LIST); newOption.setLength((byte) DHCP_SERVER_DNS_IP_LIST.length); dhcpAckOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_BROADCAST_IP) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_BROADCAST_IP); newOption.setData(DHCP_SERVER_BROADCAST_IP); newOption.setLength((byte) 4); dhcpAckOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_DHCP_SERVER) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_DHCP_SERVER); newOption.setData(DHCP_SERVER_DHCP_SERVER_IP); newOption.setLength((byte) 4); dhcpAckOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_NTP_IP) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_NTP_IP); newOption.setData(DHCP_SERVER_NTP_IP_LIST); newOption.setLength((byte) DHCP_SERVER_NTP_IP_LIST.length); dhcpAckOptions.add(newOption); } else if (specificRequest.byteValue() == DHCP_REQ_PARAM_OPTION_CODE_IP_FORWARDING) { newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_IP_FORWARDING); newOption.setData(DHCP_SERVER_IP_FORWARDING); newOption.setLength((byte) 1); dhcpAckOptions.add(newOption); }else { log.debug("Setting specific request for ACK failed"); } } newOption = new DHCPOption(); newOption.setCode(DHCP_REQ_PARAM_OPTION_CODE_END); newOption.setLength((byte) 0); dhcpAckOptions.add(newOption); dhcpDHCPAck.setOptions(dhcpAckOptions); ethDHCPAck.setPayload(ipv4DHCPAck.setPayload(udpDHCPAck.setPayload(dhcpDHCPAck))); short packetOutLength = (short) OFPacketOut.MINIMUM_LENGTH; DHCPACKPacket.setInPort(OFPort.OFPP_NONE.getValue()); DHCPACKPacket.setActionsLength((short) OFActionOutput.MINIMUM_LENGTH); packetOutLength = (short) (packetOutLength + OFActionOutput.MINIMUM_LENGTH); List<OFAction> actions = new ArrayList<OFAction>(1); actions.add(new OFActionOutput(inPort, (short) 0)); DHCPACKPacket.setActions(actions); DHCPACKPacket.setPacketData(ethDHCPAck.serialize()); packetOutLength = (short) (packetOutLength + ethDHCPAck.serialize().length); DHCPACKPacket.setLength(packetOutLength); log.debug("Sending DHCP ACK"); try { sw.write(DHCPACKPacket, null); } catch (IOException e) { System.out.println("Failed to write {} to switch {}: {}"); } } public ArrayList<Byte> getRequestedParameters(DHCP DHCPPayload, boolean isInform) { ArrayList<Byte> requestOrder = new ArrayList<Byte>(); byte[] requests = DHCPPayload.getOption(DHCPOptionCode.OptionCode_RequestedParameters).getData(); boolean requestedLeaseTime = false; boolean requestedRebindTime = false; boolean requestedRenewTime = false; for (byte specificRequest : requests) { if (specificRequest == DHCP_REQ_PARAM_OPTION_CODE_SN) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_SN); } else if (specificRequest == DHCP_REQ_PARAM_OPTION_CODE_ROUTER) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_ROUTER); } else if (specificRequest == DHCP_REQ_PARAM_OPTION_CODE_DN) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_DN); } else if (specificRequest == DHCP_REQ_PARAM_OPTION_CODE_DNS) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_DNS); } else if (specificRequest == DHCP_REQ_PARAM_OPTION_CODE_LEASE_TIME) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_LEASE_TIME); requestedLeaseTime = true; } else if (specificRequest == DHCP_REQ_PARAM_OPTION_CODE_DHCP_SERVER) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_DHCP_SERVER); } else if (specificRequest == DHCP_REQ_PARAM_OPTION_CODE_BROADCAST_IP) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_BROADCAST_IP); } else if (specificRequest == DHCP_REQ_PARAM_OPTION_CODE_NTP_IP) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_NTP_IP); } else if (specificRequest == DHCP_REQ_PARAM_OPTION_CODE_REBIND_TIME) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_REBIND_TIME); requestedRebindTime = true; } else if (specificRequest == DHCP_REQ_PARAM_OPTION_CODE_RENEWAL_TIME) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_RENEWAL_TIME); requestedRenewTime = true; } else if (specificRequest == DHCP_REQ_PARAM_OPTION_CODE_IP_FORWARDING) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_IP_FORWARDING); log.debug("requested IP FORWARDING"); } else { //log.debug("Requested option 0x" + Byte.toString(specificRequest) + " not available"); } } // We need to add these in regardless if the request list includes them if (!isInform) { if (!requestedLeaseTime) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_LEASE_TIME); //log.debug("added option LEASE TIME"); } if (!requestedRenewTime) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_RENEWAL_TIME); //log.debug("added option RENEWAL TIME"); } if (!requestedRebindTime) { requestOrder.add(DHCP_REQ_PARAM_OPTION_CODE_REBIND_TIME); //log.debug("added option REBIND TIME"); } } return requestOrder; } @Override public net.floodlightcontroller.core.IListener.Command receive( IOFSwitch sw, OFMessage msg, FloodlightContext cntx) { OFPacketIn pi = (OFPacketIn) msg; Ethernet eth = IFloodlightProviderService.bcStore.get(cntx, IFloodlightProviderService.CONTEXT_PI_PAYLOAD); if (eth.getEtherType() == Ethernet.TYPE_IPv4) { //log.debug("Got IPv4 Packet"); IPv4 IPv4Payload = (IPv4) eth.getPayload(); int IPv4SrcAddr = IPv4Payload.getSourceAddress(); if (IPv4Payload.getProtocol() == IPv4.PROTOCOL_UDP) { //log.debug("Got UDP Packet"); UDP UDPPayload = (UDP) IPv4Payload.getPayload(); if ((UDPPayload.getDestinationPort() == UDP.DHCP_SERVER_PORT || UDPPayload.getDestinationPort() == UDP.DHCP_CLIENT_PORT) && (UDPPayload.getSourcePort() == UDP.DHCP_SERVER_PORT || UDPPayload.getSourcePort() == UDP.DHCP_CLIENT_PORT)) { //log.debug("Got DHCP Packet"); // This is a DHCP packet that we need to process DHCP DHCPPayload = (DHCP) UDPPayload.getPayload(); short inPort = pi.getInPort(); /* DHCP/IPv4 Header Information * int xid = 0; int yiaddr = 0; int giaddr = 0; byte[] chaddr = null; byte[] desiredIPAddr = null; ArrayList<Byte> requestOrder = new ArrayList<Byte>(); if (DHCPPayload.getOpCode() == DHCP_OPCODE_REQUEST) { // Do nothing... we want to modify the replies only } // END IF DHCP OPCODE REQUEST else if (DHCPPayload.getOpCode() == DHCP_OPCODE_REPLY) { /** * (1) DHCP Discover * -- UDP src port = 68 * -- UDP dst port = 67 * -- IP src addr = 0.0.0.0 * -- IP dst addr = 255.255.255.255 * -- Opcode = 0x01 * -- XID = transactionX * -- All addresses blank: * -- ciaddr (client IP) * -- yiaddr (your IP) * -- siaddr (DHCPServer IP) * -- giaddr (GW IP) * -- chaddr = Client's MAC * -- Options: * -- Option 53 = DHCP Discover * -- Option 50 = possible IP request * -- Option 55 = parameter request list * -- (1) SN Mask * -- (3) Router * -- (15) Domain Name * -- (6) DNS ** if (Arrays.equals(DHCPPayload.getOption(DHCP.DHCPOptionCode.OptionCode_MessageType).getData(), DHCP_MSG_TYPE_OFFER)) { log.debug("DHCP OFFER Received"); yiaddr = DHCPPayload.getYourIPAddress(); // Will have GW IP if a relay agent was used giaddr = DHCPPayload.getGatewayIPAddress(); chaddr = Arrays.copyOf(DHCPPayload.getClientHardwareAddress(), DHCPPayload.getClientHardwareAddress().length); List<DHCPOption> options = DHCPPayload.getOptions(); for (DHCPOption option : options) { if (option.getCode() == DHCP_REQ_PARAM_OPTION_CODE_REQUESTED_IP) { option.setData(data) = Arrays.copyOf(option.getData(), option.getData().length); log.debug("Got requested IP"); } else if (option.getCode() == DHCP_REQ_PARAM_OPTION_CODE_REQUESTED_PARAMTERS) { log.debug("Got requested param list"); requestOrder = getRequestedParameters(DHCPPayload, false); } } sendDHCPAck(sw, inPort, chaddr, IPv4SrcAddr, yiaddr, giaddr, xid, requestOrder); } else if (Arrays.equals(DHCPPayload.getOption(DHCP.DHCPOptionCode.OptionCode_MessageType).getData(), DHCP_MSG_TYPE_ACK)) { log.debug("DHCP ACK Received"); xid = DHCPPayload.getTransactionId(); yiaddr = DHCPPayload.getYourIPAddress(); // Will have GW IP if a relay agent was used giaddr = DHCPPayload.getGatewayIPAddress(); chaddr = Arrays.copyOf(DHCPPayload.getClientHardwareAddress(), DHCPPayload.getClientHardwareAddress().length); List<DHCPOption> options = DHCPPayload.getOptions(); for (DHCPOption option : options) { if (option.getCode() == DHCP_REQ_PARAM_OPTION_CODE_REQUESTED_IP) { desiredIPAddr = Arrays.copyOf(option.getData(), option.getData().length); log.debug("Got requested IP"); } else if (option.getCode() == DHCP_REQ_PARAM_OPTION_CODE_REQUESTED_PARAMTERS) { log.debug("Got requested param list"); requestOrder = getRequestedParameters(DHCPPayload, false); } } sendDHCPAck(sw, inPort, chaddr, IPv4SrcAddr, yiaddr, giaddr, xid, requestOrder); } } else { log.debug("Got DHCP packet, but not a known DHCP packet opcode"); } } // END IF DHCP packet } // END IF UDP packet } // END IF IPv4 packet return Command.CONTINUE; } // END of receive(pkt) }*/