Commit a960e4b3 authored by Dean Camera's avatar Dean Camera
Browse files

Add DHCP server to the Webserver demo for automatic network configuration....

Add DHCP server to the Webserver demo for automatic network configuration. Correct uIP timer clock not tracking the correct timespan.
parent 1aeb5056
This diff is collapsed.
......@@ -11,6 +11,7 @@
* Development Blog: http://www.fourwalledcubicle.com/blog \n
* Discussion Group: http://groups.google.com/group/myusb-support-list \n
* Official Releases, SVN Access, Issue Tracker: http://code.google.com/p/lufa-lib/ \n
* Development Source Archives: http://github.com/abcminiuser/lufa-lib/archives/master
* Git Access: http://github.com/abcminiuser/lufa-lib
* Commit RSS: http://github.com/feeds/abcminiuser/commits/lufa-lib/master
* Author's Website: http://www.fourwalledcubicle.com \n
......
......@@ -27,6 +27,9 @@
* library API more streamlined and robust. You can download AVR-GCC for free in a convenient windows package,
* from the the WinAVR website (see \ref Page_Resources).
*
* The only required AVR peripherals for LUFA is the USB controller itself and interrupts - LUFA does not require the use of the
* microcontroller's timers or other hardware, leaving more hardware to the application developer.
*
* Accompanying LUFA in the download package is a set of example demo applications, plus several Bootloaders of different classes
* and open source LUFA powered projects.
*
......
/*
LUFA Library
Copyright (C) Dean Camera, 2010.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* DHCP Client Application. When connected to the uIP stack, this will retrieve IP configuration settings from the
* DHCP server on the network.
*/
#include "DHCPApp.h"
#if defined(ENABLE_DHCP)
/** Timer for managing the timeout period for a DHCP server to respond */
struct timer DHCPTimer;
/** Initialization function for the DHCP client. */
void DHCPApp_Init(void)
{
uip_udp_appstate_t* const AppState = &uip_udp_conn->appstate;
/* Create a new UDP connection to the DHCP server port for the DHCP solicitation */
uip_ipaddr_t DHCPServerIPAddress;
uip_ipaddr(&DHCPServerIPAddress, 255, 255, 255, 255);
AppState->Connection = uip_udp_new(&DHCPServerIPAddress, HTONS(DHCPC_SERVER_PORT));
/* If the connection was sucessfully created, bind it to the local DHCP client port */
if(AppState->Connection != NULL)
{
uip_udp_bind(AppState->Connection, HTONS(DHCPC_CLIENT_PORT));
AppState->CurrentState = DHCP_STATE_SendDiscover;
}
/* Set timeout period to half a second for a DHCP server to respond */
timer_set(&DHCPTimer, CLOCK_SECOND / 2);
}
/** uIP stack application callback for the DHCP client. This function must be called each time the TCP/IP stack
* needs a UDP packet to be processed.
*/
void DHCPApp_Callback(void)
{
uip_udp_appstate_t* const AppState = &uip_udp_conn->appstate;
DHCP_Header_t* const AppData = (DHCP_Header_t*)uip_appdata;
uint16_t AppDataSize = 0;
switch (AppState->CurrentState)
{
case DHCP_STATE_SendDiscover:
/* Clear all DHCP settings, reset client IP address */
memset(&AppState->DHCPOffer_Data, 0x00, sizeof(AppState->DHCPOffer_Data));
uip_sethostaddr(&AppState->DHCPOffer_Data.AllocatedIP);
/* Fill out the DHCP response header */
AppDataSize += DHCPApp_FillDHCPHeader(AppData, DHCP_DISCOVER, AppState);
/* Add the required DHCP options list to the packet */
uint8_t RequiredOptionList[] = {DHCP_OPTION_SUBNET_MASK, DHCP_OPTION_ROUTER, DHCP_OPTION_DNS_SERVER};
AppDataSize += DHCPApp_SetOption(AppData->Options, DHCP_OPTION_REQ_LIST, sizeof(RequiredOptionList),
RequiredOptionList);
/* Send the DHCP DISCOVER packet */
uip_send(AppData, AppDataSize);
/* Reset the timeout timer, progress to next state */
timer_reset(&DHCPTimer);
AppState->CurrentState = DHCP_STATE_WaitForResponse;
break;
case DHCP_STATE_WaitForResponse:
if (!(uip_newdata()))
{
/* Check if the DHCP timeout period has expired while waiting for a response */
if (timer_expired(&DHCPTimer))
AppState->CurrentState = DHCP_STATE_SendDiscover;
break;
}
uint8_t OfferResponse_MessageType;
if ((AppData->TransactionID == DHCP_TRANSACTION_ID) &&
DHCPApp_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &OfferResponse_MessageType) &&
(OfferResponse_MessageType == DHCP_OFFER))
{
/* Received a DHCP offer for an IP address, copy over values for later request */
memcpy(&AppState->DHCPOffer_Data.AllocatedIP, &AppData->YourIP, sizeof(uip_ipaddr_t));
DHCPApp_GetOption(AppData->Options, DHCP_OPTION_SUBNET_MASK, &AppState->DHCPOffer_Data.Netmask);
DHCPApp_GetOption(AppData->Options, DHCP_OPTION_ROUTER, &AppState->DHCPOffer_Data.GatewayIP);
DHCPApp_GetOption(AppData->Options, DHCP_OPTION_SERVER_ID, &AppState->DHCPOffer_Data.ServerIP);
timer_reset(&DHCPTimer);
AppState->CurrentState = DHCP_STATE_SendRequest;
}
break;
case DHCP_STATE_SendRequest:
/* Fill out the DHCP response header */
AppDataSize += DHCPApp_FillDHCPHeader(AppData, DHCP_REQUEST, AppState);
/* Add the DHCP REQUESTED IP ADDRESS option to the packet */
AppDataSize += DHCPApp_SetOption(AppData->Options, DHCP_OPTION_REQ_IPADDR, sizeof(uip_ipaddr_t),
&AppState->DHCPOffer_Data.AllocatedIP);
/* Add the DHCP SERVER IP ADDRESS option to the packet */
AppDataSize += DHCPApp_SetOption(AppData->Options, DHCP_OPTION_SERVER_ID, sizeof(uip_ipaddr_t),
&AppState->DHCPOffer_Data.ServerIP);
/* Send the DHCP REQUEST packet */
uip_send(AppData, AppDataSize);
/* Reset the timeout timer, progress to next state */
timer_reset(&DHCPTimer);
AppState->CurrentState = DHCP_STATE_WaitForACK;
break;
case DHCP_STATE_WaitForACK:
if (!(uip_newdata()))
{
/* Check if the DHCP timeout period has expired while waiting for a response */
if (timer_expired(&DHCPTimer))
AppState->CurrentState = DHCP_STATE_SendDiscover;
break;
}
uint8_t RequestResponse_MessageType;
if ((AppData->TransactionID == DHCP_TRANSACTION_ID) &&
DHCPApp_GetOption(AppData->Options, DHCP_OPTION_MSG_TYPE, &RequestResponse_MessageType) &&
(RequestResponse_MessageType == DHCP_ACK))
{
/* Set the new network parameters from the DHCP server */
uip_sethostaddr(&AppState->DHCPOffer_Data.AllocatedIP);
uip_setnetmask(&AppState->DHCPOffer_Data.Netmask);
uip_setdraddr(&AppState->DHCPOffer_Data.GatewayIP);
AppState->CurrentState = DHCP_STATE_AddressLeased;
}
break;
}
}
uint16_t DHCPApp_FillDHCPHeader(DHCP_Header_t* DHCPHeader, uint8_t DHCPMessageType, uip_udp_appstate_t* AppState)
{
/* Erase existing packet data so that we start will all 0x00 DHCP header data */
memset(DHCPHeader, 0, sizeof(DHCP_Header_t));
/* Fill out the DHCP packet header */
DHCPHeader->Operation = DHCP_OP_BOOTREQUEST;
DHCPHeader->HardwareType = DHCP_HTYPE_ETHERNET;
DHCPHeader->HardwareAddressLength = sizeof(MACAddress);
DHCPHeader->Hops = 0;
DHCPHeader->TransactionID = DHCP_TRANSACTION_ID;
DHCPHeader->ElapsedSeconds = 0;
DHCPHeader->Flags = HTONS(BOOTP_BROADCAST);
memcpy(&DHCPHeader->ClientIP, &uip_hostaddr, sizeof(uip_ipaddr_t));
memcpy(&DHCPHeader->YourIP, &AppState->DHCPOffer_Data.AllocatedIP, sizeof(uip_ipaddr_t));
memcpy(&DHCPHeader->NextServerIP, &AppState->DHCPOffer_Data.ServerIP, sizeof(uip_ipaddr_t));
memcpy(&DHCPHeader->ClientHardwareAddress, &MACAddress, sizeof(struct uip_eth_addr));
DHCPHeader->Cookie = DHCP_MAGIC_COOKIE;
/* Add a DHCP type and terminator options to the start of the DHCP options field */
DHCPHeader->Options[0] = DHCP_OPTION_MSG_TYPE;
DHCPHeader->Options[1] = 1;
DHCPHeader->Options[2] = DHCPMessageType;
DHCPHeader->Options[3] = DHCP_OPTION_END;
/* Calculate the total number of bytes added to the outgoing packet */
return (sizeof(DHCP_Header_t) + 4);
}
uint8_t DHCPApp_SetOption(uint8_t* DHCPOptionList, uint8_t Option, uint8_t DataLen, void* Source)
{
/* Skip through the DHCP options list until the terminator option is found */
while (*DHCPOptionList != DHCP_OPTION_END)
DHCPOptionList += (DHCPOptionList[1] + 2);
/* Overwrite the existing terminator with the new option, add a new terminator at the end of the list */
DHCPOptionList[0] = Option;
DHCPOptionList[1] = DataLen;
memcpy(&DHCPOptionList[2], Source, DataLen);
DHCPOptionList[2 + DataLen] = DHCP_OPTION_END;
/* Calculate the total number of bytes added to the outgoing packet */
return (2 + DataLen);
}
bool DHCPApp_GetOption(uint8_t* DHCPOptionList, uint8_t Option, void* Destination)
{
/* Look through the incomming DHCP packet's options list for the requested option */
while (*DHCPOptionList != DHCP_OPTION_END)
{
/* Check if the current DHCP option in the packet is the one requested */
if (DHCPOptionList[0] == Option)
{
/* Copy request option's data to the destination buffer */
memcpy(Destination, &DHCPOptionList[2], DHCPOptionList[1]);
/* Indicate that the requested option data was sucessfully retrieved */
return true;
}
/* Skip to next DHCP option in the options list */
DHCPOptionList += (DHCPOptionList[1] + 2);
}
/* Requested option not found in the incomming packet's DHCP options list */
return false;
}
#endif
/*
LUFA Library
Copyright (C) Dean Camera, 2010.
dean [at] fourwalledcubicle [dot] com
www.fourwalledcubicle.com
*/
/*
Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com)
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that the copyright notice and this
permission notice and warranty disclaimer appear in supporting
documentation, and that the name of the author not be used in
advertising or publicity pertaining to distribution of the
software without specific, written prior permission.
The author disclaim all warranties with regard to this
software, including all implied warranties of merchantability
and fitness. In no event shall the author be liable for any
special, indirect or consequential damages or any damages
whatsoever resulting from loss of use, data or profits, whether
in an action of contract, negligence or other tortious action,
arising out of or in connection with the use or performance of
this software.
*/
/** \file
*
* Header file for DHCPApp.c.
*/
#ifndef _DHCP_APP_H_
#define _DHCP_APP_H_
/* Includes: */
#include <stdio.h>
#include <uip.h>
#include "../Webserver.h"
/* Macros: */
#define DHCPC_SERVER_PORT 67
#define DHCPC_CLIENT_PORT 68
#define DHCP_OP_BOOTREQUEST 0x01
#define DHCP_OP_BOOTREPLY 0x02
#define BOOTP_BROADCAST 0x8000
#define DHCP_MAGIC_COOKIE 0x63538263
#define DHCP_TRANSACTION_ID 0x13245466
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_DECLINE 4
#define DHCP_ACK 5
#define DHCP_NAK 6
#define DHCP_RELEASE 7
#define DHCP_HTYPE_ETHERNET 1
#define DHCP_OPTION_SUBNET_MASK 1
#define DHCP_OPTION_ROUTER 3
#define DHCP_OPTION_DNS_SERVER 6
#define DHCP_OPTION_REQ_IPADDR 50
#define DHCP_OPTION_LEASE_TIME 51
#define DHCP_OPTION_MSG_TYPE 53
#define DHCP_OPTION_SERVER_ID 54
#define DHCP_OPTION_REQ_LIST 55
#define DHCP_OPTION_END 255
/* Type Defines: */
/** Type define for a DHCP packet inside an Ethernet frame. */
typedef struct
{
uint8_t Operation; /**< DHCP operation, either DHCP_OP_BOOTREQUEST or DHCP_OP_BOOTREPLY */
uint8_t HardwareType; /**< Hardware carrier type constant */
uint8_t HardwareAddressLength; /**< Length in bytes of a hardware (MAC) address on the network */
uint8_t Hops; /**< Number of hops required to reach the server, unused */
uint32_t TransactionID; /**< Unique ID of the DHCP packet, for positive matching between sent and received packets */
uint16_t ElapsedSeconds; /**< Elapsed seconds since the request was made */
uint16_t Flags; /**< BOOTP packet flags */
uip_ipaddr_t ClientIP; /**< Client IP address, if already leased an IP */
uip_ipaddr_t YourIP; /**< Client IP address */
uip_ipaddr_t NextServerIP; /**< Legacy BOOTP protocol field, unused for DHCP */
uip_ipaddr_t RelayAgentIP; /**< Legacy BOOTP protocol field, unused for DHCP */
uint8_t ClientHardwareAddress[16]; /**< Hardware (MAC) address of the client making a request to the DHCP server */
uint8_t ServerHostnameString[64]; /**< Legacy BOOTP protocol field, unused for DHCP */
uint8_t BootFileName[128]; /**< Legacy BOOTP protocol field, unused for DHCP */
uint32_t Cookie; /**< Magic BOOTP protocol cookie to indicate a valid packet */
uint8_t Options[]; /** DHCP message options */
} DHCP_Header_t;
/* Enums: */
enum DHCP_States_t
{
DHCP_STATE_SendDiscover,
DHCP_STATE_WaitForResponse,
DHCP_STATE_SendRequest,
DHCP_STATE_WaitForACK,
DHCP_STATE_AddressLeased,
};
/* Function Prototypes: */
void DHCPApp_Init(void);
void DHCPApp_Callback(void);
uint16_t DHCPApp_FillDHCPHeader(DHCP_Header_t* DHCPHeader, uint8_t DHCPMessageType, uip_udp_appstate_t* AppState);
uint8_t DHCPApp_SetOption(uint8_t* DHCPOptionList, uint8_t Option, uint8_t DataLen, void* Source);
bool DHCPApp_GetOption(uint8_t* DHCPOptionList, uint8_t Option, void* Destination);
#endif
......@@ -76,7 +76,7 @@ char PROGMEM HTTPPage[] =
void WebserverApp_Init(void)
{
/* Listen on port 80 for HTTP connections from hosts */
uip_listen(HTONS(80));
uip_listen(HTONS(HTTP_SERVER_PORT));
}
/** uIP stack application callback for the simple HTTP webserver. This function must be called each time the
......@@ -84,8 +84,9 @@ void WebserverApp_Init(void)
*/
void WebserverApp_Callback(void)
{
char* AppDataPtr = (char*)uip_appdata;
uint16_t AppDataSize = 0;
uip_tcp_appstate_t* const AppState = &uip_conn->appstate;
char* AppData = (char*)uip_appdata;
uint16_t AppDataSize = 0;
if (uip_closed() || uip_aborted() || uip_timedout())
{
......@@ -95,12 +96,12 @@ void WebserverApp_Callback(void)
else if (uip_connected())
{
/* New connection - initialize connection state and data pointer to the appropriate HTTP header */
uip_conn->appstate.SendPos = HTTP200Header;
uip_conn->appstate.CurrentState = WEBSERVER_STATE_SendHeaders;
AppState->SendPos = HTTP200Header;
AppState->CurrentState = WEBSERVER_STATE_SendHeaders;
}
/* Calculate the maximum segment size and remaining data size */
uint16_t BytesRemaining = strlen_P(uip_conn->appstate.SendPos);
uint16_t BytesRemaining = strlen_P(AppState->SendPos);
uint16_t MaxSegSize = uip_mss();
/* No more bytes remaining in the current data being sent - progress to next data chunk or
......@@ -108,15 +109,15 @@ void WebserverApp_Callback(void)
if (!(BytesRemaining))
{
/* Check which data chunk we are currently sending (header or data) */
if (uip_conn->appstate.CurrentState == WEBSERVER_STATE_SendHeaders)
if (AppState->CurrentState == WEBSERVER_STATE_SendHeaders)
{
uip_conn->appstate.SendPos = HTTPPage;
uip_conn->appstate.CurrentState = WEBSERVER_STATE_SendData;
AppState->SendPos = HTTPPage;
AppState->CurrentState = WEBSERVER_STATE_SendData;
}
else if (uip_conn->appstate.CurrentState == WEBSERVER_STATE_SendData)
else if (AppState->CurrentState == WEBSERVER_STATE_SendData)
{
uip_close();
uip_conn->appstate.CurrentState = WEBSERVER_STATE_Closed;
AppState->CurrentState = WEBSERVER_STATE_Closed;
}
return;
......@@ -133,9 +134,9 @@ void WebserverApp_Callback(void)
}
/* Copy over the next data segment to the application buffer, advance send position pointer */
strncpy_P(uip_appdata, uip_conn->appstate.SendPos, AppDataSize);
uip_conn->appstate.SendPos += AppDataSize;
strncpy_P(AppData, AppState->SendPos, AppDataSize);
AppState->SendPos += AppDataSize;
/* Send the data to the requesting host */
uip_send(AppDataPtr, AppDataSize);
uip_send(AppData, AppDataSize);
}
......@@ -43,6 +43,17 @@
#include <LUFA/Version.h>
#include <uip.h>
/* Enums: */
enum Webserver_States_t
{
WEBSERVER_STATE_SendHeaders,
WEBSERVER_STATE_SendData,
WEBSERVER_STATE_Closed,
};
/* Macros: */
#define HTTP_SERVER_PORT 80
/* Function Prototypes: */
void WebserverApp_Init(void);
......
#ifndef __APPS_CONF_H__
#define __APPS_CONF_H__
enum Webserver_States_t
{
WEBSERVER_STATE_SendHeaders,
WEBSERVER_STATE_SendData,
WEBSERVER_STATE_Closed,
};
typedef struct
{
uint8_t CurrentState;
char* SendPos;
} uip_tcp_appstate_t;
typedef struct
{
uint8_t CurrentState;
struct uip_udp_conn* Connection;
struct
{
uint8_t AllocatedIP[4];
uint8_t Netmask[4];
uint8_t GatewayIP[4];
uint8_t ServerIP[4];
} DHCPOffer_Data;
} uip_udp_appstate_t;
#define UIP_APPCALL WebserverApp_Callback
#define UIP_UDP_APPCALL DHCPApp_Callback
void UIP_APPCALL(void);
void UIP_UDP_APPCALL(void);
#endif /*__APPS_CONF_H__*/
......@@ -21,8 +21,7 @@ ISR(TIMER1_COMPA_vect)
void clock_init()
{
OCR1A = ((F_CPU / 1024) / 100);
TCCR1A = (1 << WGM12);
TCCR1B = ((1 << CS12) | (1 << CS10));
TCCR1B = ((1 << WGM12) | (1 << CS12) | (1 << CS10));
TIMSK1 = (1 << OCIE1A);
}
......
......@@ -2,10 +2,6 @@
#ifndef __GLOBAL_CONF_H__
#define __GLOBAL_CONF_H__
//Define frequency
// #define F_CPU 12500000UL
//
//Include uip.h gives all the uip configurations in uip-conf.h
#include "uip.h"
......
......@@ -79,7 +79,11 @@ typedef unsigned short uip_stats_t;
*
* \hideinitializer
*/
#define UIP_CONF_UDP 0
#if defined(ENABLE_DHCP)
#define UIP_CONF_UDP 1
#else
#define UIP_CONF_UDP 0
#endif
/**
* UDP checksums on or off
......
......@@ -63,6 +63,8 @@ struct timer ConnectionTimer;
/** ARP timer, to retain the time elapsed since the ARP cache was last updated. */
struct timer ARPTimer;
/** MAC address of the RNDIS device, when enumerated */
struct uip_eth_addr MACAddress;
/** Main program entry point. This routine configures the hardware required by the application, then
* enters a loop to run the application tasks in sequence.
......@@ -122,7 +124,6 @@ int main(void)
break;
}
struct uip_eth_addr MACAddress;
if (RNDIS_Host_QueryRNDISProperty(&Ethernet_RNDIS_Interface, OID_802_3_CURRENT_ADDRESS,
&MACAddress, sizeof(MACAddress)) != HOST_SENDCONTROL_Successful)
{
......@@ -204,14 +205,36 @@ void ManageConnections(void)
for (uint8_t i = 0; i < UIP_CONNS; i++)
{
/* Run periodic connection management for each connection */
/* Run periodic connection management for each TCP connection */
uip_periodic(i);
/* If a response was generated, send it */
if (uip_len > 0)
RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface, &uip_buf[0], uip_len);
{
/* Add destination MAC to outgoing packet */
uip_arp_out();
RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface, &uip_buf[0], uip_len);
}
}
#if defined(ENABLE_DHCP)
for (uint8_t i = 0; i < UIP_UDP_CONNS; i++)
{
/* Run periodic connection management for each UDP connection */
uip_udp_periodic(i);
/* If a response was generated, send it */
if (uip_len > 0)
{
/* Add destination MAC to outgoing packet */
uip_arp_out();
RNDIS_Host_SendPacket(&Ethernet_RNDIS_Interface, &uip_buf[0], uip_len);
}
}
#endif
LEDs_SetAllLEDs(LEDMASK_USB_READY);
}
......@@ -244,14 +267,20 @@ void SetupHardware(void)
/* uIP Stack Initialization */
uip_init();
/* DHCP/Server IP Settings Initialization */
#if defined(ENABLE_DHCP)
DHCPApp_Init();
#else
uip_ipaddr_t IPAddress, Netmask, GatewayIPAddress;
uip_ipaddr(&IPAddress, DEVICE_IP_ADDRESS[0], DEVICE_IP_ADDRESS[1], DEVICE_IP_ADDRESS[2], DEVICE_IP_ADDRESS[3]);
uip_ipaddr(&Netmask, DEVICE_NETMASK[0], DEVICE_NETMASK[1], DEVICE_NETMASK[2], DEVICE_NETMASK[3]);
uip_ipaddr(&GatewayIPAddress, DEVICE_GATEWAY[0], DEVICE_GATEWAY[1], DEVICE_GATEWAY[2], DEVICE_GATEWAY[3]);
uip_ipaddr(&IPAddress, DEVICE_IP_ADDRESS[0], DEVICE_IP_ADDRESS[1], DEVICE_IP_ADDRESS[2], DEVICE_IP_ADDRESS[3]);
uip_ipaddr(&Netmask, DEVICE_NETMASK[0], DEVICE_NETMASK[1], DEVICE_NETMASK[2], DEVICE_NETMASK[3]);
uip_ipaddr(&GatewayIPAddress, DEVICE_GATEWAY[0], DEVICE_GATEWAY[1], DEVICE_GATEWAY[2