| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406 | /* * The MIT License (MIT) * * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com> *  * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: *  * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. *  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */#include "dhserver.h"#include "usb_eth.h"/* DHCP message type */#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_INFORM         8/* DHCP options */enum DHCP_OPTIONS{	DHCP_PAD                    = 0,	DHCP_SUBNETMASK             = 1,	DHCP_ROUTER                 = 3,	DHCP_DNSSERVER              = 6,	DHCP_HOSTNAME               = 12,	DHCP_DNSDOMAIN              = 15,	DHCP_MTU                    = 26,	DHCP_BROADCAST              = 28,	DHCP_PERFORMROUTERDISC      = 31,	DHCP_STATICROUTE            = 33,	DHCP_NISDOMAIN              = 40,	DHCP_NISSERVER              = 41,	DHCP_NTPSERVER              = 42,	DHCP_VENDOR                 = 43,	DHCP_IPADDRESS              = 50,	DHCP_LEASETIME              = 51,	DHCP_OPTIONSOVERLOADED      = 52,	DHCP_MESSAGETYPE            = 53,	DHCP_SERVERID               = 54,	DHCP_PARAMETERREQUESTLIST   = 55,	DHCP_MESSAGE                = 56,	DHCP_MAXMESSAGESIZE         = 57,	DHCP_RENEWALTIME            = 58,	DHCP_REBINDTIME             = 59,	DHCP_CLASSID                = 60,	DHCP_CLIENTID               = 61,	DHCP_USERCLASS              = 77,  /* RFC 3004 */	DHCP_FQDN                   = 81,	DHCP_DNSSEARCH              = 119, /* RFC 3397 */	DHCP_CSR                    = 121, /* RFC 3442 */	DHCP_MSCSR                  = 249, /* MS code for RFC 3442 */	DHCP_END                    = 255,};typedef struct{    uint8_t  dp_op;           /* packet opcode type */    uint8_t  dp_htype;        /* hardware addr type */    uint8_t  dp_hlen;         /* hardware addr length */    uint8_t  dp_hops;         /* gateway hops */    uint32_t dp_xid;          /* transaction ID */    uint16_t dp_secs;         /* seconds since boot began */    uint16_t dp_flags;    uint8_t  dp_ciaddr[4];    /* client IP address */    uint8_t  dp_yiaddr[4];    /* 'your' IP address */    uint8_t  dp_siaddr[4];    /* server IP address */    uint8_t  dp_giaddr[4];    /* gateway IP address */    uint8_t  dp_chaddr[16];   /* client hardware address */    uint8_t  dp_legacy[192];    uint8_t  dp_magic[4];         uint8_t  dp_options[275]; /* options area */} DHCP_TYPE;DHCP_TYPE dhcp_data;static struct udp_pcb *pcb = NULL;static dhcp_config_t *config = NULL;char magic_cookie[] = {0x63,0x82,0x53,0x63};static dhcp_entry_t *entry_by_ip(uint32_t ip){	int i;	for (i = 0; i < config->num_entry; i++)		if (*(uint32_t *)config->entries[i].addr == ip)			return &config->entries[i];	return NULL;}static dhcp_entry_t *entry_by_mac(uint8_t *mac){	int i;	for (i = 0; i < config->num_entry; i++)		if (memcmp(config->entries[i].mac, mac, 6) == 0)			return &config->entries[i];	return NULL;}static inline bool is_vacant(dhcp_entry_t *entry){	return memcmp("\0\0\0\0\0", entry->mac, 6) == 0;}static dhcp_entry_t *vacant_address(){	int i;	for (i = 0; i < config->num_entry; i++)		if (is_vacant(config->entries + i))			return config->entries + 1;	return NULL;}static inline void free_entry(dhcp_entry_t *entry){	memset(entry->mac, 0, 6);}uint8_t *find_dhcp_option(uint8_t *attrs, int size, uint8_t attr){	int i = 0;	while ((i + 1) < size)	{		int next = i + attrs[i + 1] + 2;		if (next > size) return NULL;		if (attrs[i] == attr)			return attrs + i;		i = next;	}	return NULL;}int fill_options(void *dest,	uint8_t msg_type,	const char *domain,	uint32_t dns,	int lease_time,	uint32_t serverid,	uint32_t router,	uint32_t subnet){	uint8_t *ptr = (uint8_t *)dest;	// ACK message type	*ptr++ = 53;	*ptr++ = 1;	*ptr++ = msg_type;	// dhcp server identifier	*ptr++ = DHCP_SERVERID;	*ptr++ = 4;	*(uint32_t *)ptr = serverid;	ptr += 4;	// lease time	*ptr++ = DHCP_LEASETIME;	*ptr++ = 4;	*ptr++ = (lease_time >> 24) & 0xFF;	*ptr++ = (lease_time >> 16) & 0xFF;	*ptr++ = (lease_time >> 8) & 0xFF;	*ptr++ = (lease_time >> 0) & 0xFF;	// subnet mask	*ptr++ = DHCP_SUBNETMASK;	*ptr++ = 4;	*(uint32_t *)ptr = subnet;	ptr += 4;	// router	if (router != 0)	{		*ptr++ = DHCP_ROUTER;		*ptr++ = 4;		*(uint32_t *)ptr = router;		ptr += 4;	}	// domain name	if (domain != NULL)	{		int len = strlen(domain);		*ptr++ = DHCP_DNSDOMAIN;		*ptr++ = len;		memcpy(ptr, domain, len);		ptr += len;	}	// domain name server (DNS)	if (dns != 0)	{		*ptr++ = DHCP_DNSSERVER;		*ptr++ = 4;		*(uint32_t *)ptr = dns;		ptr += 4;	}	// end	*ptr++ = DHCP_END;	return ptr - (uint8_t *)dest;///*//						// static route//						*option_ptr++ = DHCP_STATICROUTE;//						*option_ptr++ = 8;//						*option_ptr++ = ((uint8_t *)&server_ip)[0];//						*option_ptr++ = ((uint8_t *)&server_ip)[1];//						*option_ptr++ = ((uint8_t *)&server_ip)[2];//						*option_ptr++ = 0;//						memcpy(option_ptr, &server_ip, 4);//						option_ptr += 4;//*////*//						*option_ptr++ = 0x2e; // NetBIOS over TCP/IP Node Type Option//						*option_ptr++ = 1;//						*option_ptr++ = 1;//						//						*option_ptr++ = 0x2c; // NetBIOS over TCP/IP Name Server Option//						*option_ptr++ = 4;//						memcpy(option_ptr, &server_ip, 4);//						option_ptr += 4;//*///						/*//						*option_ptr++ = DHCP_MSCSR;//						*option_ptr++ = 8;//						*option_ptr++ = 24;//						*option_ptr++ = 192;//						*option_ptr++ = 168;//						*option_ptr++ = 0;//						*option_ptr++ = 192;//						*option_ptr++ = 168;//						*option_ptr++ = 0;//						*option_ptr++ = 11;//						*///						// renewal time//						//						*option_ptr++ = DHCP_RENEWALTIME;//						*option_ptr++ = 4;//						*option_ptr++ = 0;//						*option_ptr++ = 0;//						*option_ptr++ = 0x38;//						*option_ptr++ = 0x40;//						//	//					// rebinding time//						//						*option_ptr++ = DHCP_REBINDTIME;//						*option_ptr++ = 4;//						*option_ptr++ = 0;//						*option_ptr++ = 0;//						*option_ptr++ = 0x62;//						*option_ptr++ = 0x70;//						///*//						// domain name//						*option_ptr++ = DHCP_DNSDOMAIN;//						int len = sprintf((char*)option_ptr+1, "stm32f4.net");//						*option_ptr = (len + 1);//						option_ptr += (len + 2);//						// Option: (31) Perform Router Discover//						*option_ptr++ = DHCP_PERFORMROUTERDISC;//						*option_ptr++ = 1;//						*option_ptr++ = 1;//*/						// end}static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, struct ip_addr *addr, u16_t port){	uint8_t *ptr;	dhcp_entry_t *entry;	struct pbuf *pp;	int n = p->len;	if (n > sizeof(dhcp_data)) n = sizeof(dhcp_data);	memcpy(&dhcp_data, p->payload, n);	switch (dhcp_data.dp_options[2])	{		case DHCP_DISCOVER:			entry = entry_by_mac(dhcp_data.dp_chaddr);			if (entry == NULL) entry = vacant_address();			if (entry == NULL) break;			dhcp_data.dp_op = 2; // reply			dhcp_data.dp_secs = 0;			dhcp_data.dp_flags = 0;			*(uint32_t *)dhcp_data.dp_yiaddr = *(uint32_t *)entry->addr;			memcpy(dhcp_data.dp_magic, magic_cookie, 4);			memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options));			fill_options(dhcp_data.dp_options,				DHCP_OFFER,				config->domain,				*(uint32_t *)config->dns,				entry->lease, 				*(uint32_t *)config->addr,				*(uint32_t *)config->addr, 				*(uint32_t *)entry->subnet);			pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL);			if (pp == NULL) break;			memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data));			//udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port);			udp_sendto_if(upcb, pp, IP_ADDR_BROADCAST, port, &netif_data);			pbuf_free(pp);			break;		case DHCP_REQUEST:			// 1. find requested ipaddr in option list			ptr = find_dhcp_option(dhcp_data.dp_options, sizeof(dhcp_data.dp_options), DHCP_IPADDRESS);			if (ptr == NULL) break;			if (ptr[1] != 4) break;			ptr += 2;			// 2. does hw-address registered?			entry = entry_by_mac(dhcp_data.dp_chaddr);			if (entry != NULL) free_entry(entry);			// 3. find requested ipaddr			entry = entry_by_ip(*(uint32_t *)ptr);			if (entry == NULL) break;			if (!is_vacant(entry)) break;			// 4. fill struct fields			memcpy(dhcp_data.dp_yiaddr, ptr, 4);			dhcp_data.dp_op = 2; // reply			dhcp_data.dp_secs = 0;			dhcp_data.dp_flags = 0;			memcpy(dhcp_data.dp_magic, magic_cookie, 4);			// 5. fill options			memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options));			fill_options(dhcp_data.dp_options,				DHCP_ACK,				config->domain,				*(uint32_t *)config->dns,				entry->lease, 				*(uint32_t *)config->addr,				*(uint32_t *)config->addr, 				*(uint32_t *)entry->subnet);			// 6. send ACK			pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL);			if (pp == NULL) break;			memcpy(entry->mac, dhcp_data.dp_chaddr, 6);			memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data));			//udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port);			udp_sendto_if(upcb, pp, IP_ADDR_BROADCAST, port, &netif_data);			pbuf_free(pp);			break;		default:				break;	}	pbuf_free(p);}err_t dhserv_init(dhcp_config_t *c){	err_t err;	udp_init();	dhserv_free();	pcb = udp_new();	if (pcb == NULL)		return ERR_MEM;	err = udp_bind(pcb, IP_ADDR_ANY, c->port);	if (err != ERR_OK)	{		dhserv_free();		return err;	}    //typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);	udp_recv(pcb, (udp_recv_fn)udp_recv_proc, NULL);	config = c;	return ERR_OK;}void dhserv_free(void){	if (pcb == NULL) return;	udp_remove(pcb);	pcb = NULL;}
 |