int dhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
			uint32_t source_ip, int source_port,
			uint32_t dest_ip, int dest_port,
			const uint8_t *dest_arp, int ifindex, bool bcast)
{
	struct sockaddr_ll dest;
	struct ip_udp_dhcp_packet packet;
	int fd, n;

	enum {
		IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) -
						EXTEND_FOR_BUGGY_SERVERS,
		UPD_DHCP_SIZE = IP_UPD_DHCP_SIZE -
				offsetof(struct ip_udp_dhcp_packet, udp),
	};

	fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
	if (fd < 0)
		return -errno;

	if (bcast)
		dhcp_pkt->flags |= htons(BROADCAST_FLAG);

	memset(&dest, 0, sizeof(dest));
	memset(&packet, 0, sizeof(packet));
	packet.data = *dhcp_pkt;

	dest.sll_family = AF_PACKET;
	dest.sll_protocol = htons(ETH_P_IP);
	dest.sll_ifindex = ifindex;
	dest.sll_halen = 6;
	memcpy(dest.sll_addr, dest_arp, 6);
	if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
		int err = errno;
		close(fd);
		return -err;
	}

	packet.ip.protocol = IPPROTO_UDP;
	packet.ip.saddr = source_ip;
	packet.ip.daddr = dest_ip;
	packet.udp.source = htons(source_port);
	packet.udp.dest = htons(dest_port);
	/* size, excluding IP header: */
	packet.udp.len = htons(UPD_DHCP_SIZE);
	/* for UDP checksumming, ip.len is set to UDP packet len */
	packet.ip.tot_len = packet.udp.len;
	packet.udp.check = dhcp_checksum(&packet, IP_UPD_DHCP_SIZE);
	/* but for sending, it is set to IP packet len */
	packet.ip.tot_len = htons(IP_UPD_DHCP_SIZE);
	packet.ip.ihl = sizeof(packet.ip) >> 2;
	packet.ip.version = IPVERSION;
	packet.ip.ttl = IPDEFTTL;
	packet.ip.check = dhcp_checksum(&packet.ip, sizeof(packet.ip));

	/*
	 * Currently we send full-sized DHCP packets (zero padded).
	 * If you need to change this: last byte of the packet is
	 * packet.data.options[dhcp_end_option(packet.data.options)]
	 */
	n = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0,
			(struct sockaddr *) &dest, sizeof(dest));
	if (n < 0) {
		int err = errno;
		close(fd);
		return -err;
	}

	close(fd);

	return n;
}
int dhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
			uint32_t source_ip, int source_port,
			uint32_t dest_ip, int dest_port,
			const uint8_t *dest_arp, int ifindex, bool bcast)
{
	struct sockaddr_ll dest;
	struct ip_udp_dhcp_packet packet;
	int fd, n;

	enum {
		IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) -
						EXTEND_FOR_BUGGY_SERVERS,
		UPD_DHCP_SIZE = IP_UPD_DHCP_SIZE -
				offsetof(struct ip_udp_dhcp_packet, udp),
	};

	fd = socket(PF_PACKET, SOCK_DGRAM | SOCK_CLOEXEC, 0);
	if (fd < 0)
		return -errno;

	if (bcast)
		dhcp_pkt->flags |= htons(BROADCAST_FLAG);

	memset(&dest, 0, sizeof(dest));
	memset(&packet, 0, sizeof(packet));
	packet.data = *dhcp_pkt;

	dest.sll_family = AF_PACKET;
	dest.sll_protocol = htons(ETH_P_IP);
	dest.sll_ifindex = ifindex;
	dest.sll_halen = 6;
	memcpy(dest.sll_addr, dest_arp, 6);
	if (bind(fd, (struct sockaddr *)&dest, sizeof(dest)) < 0) {
		int err = errno;
		close(fd);
		return -err;
	}

	packet.ip.protocol = IPPROTO_UDP;
	packet.ip.saddr = source_ip;
	packet.ip.daddr = dest_ip;
	packet.udp.source = htons(source_port);
	packet.udp.dest = htons(dest_port);
	 
	packet.udp.len = htons(UPD_DHCP_SIZE);
	 
	packet.ip.tot_len = packet.udp.len;
	packet.udp.check = dhcp_checksum(&packet, IP_UPD_DHCP_SIZE);
	 
	packet.ip.tot_len = htons(IP_UPD_DHCP_SIZE);
	packet.ip.ihl = sizeof(packet.ip) >> 2;
	packet.ip.version = IPVERSION;
	packet.ip.ttl = IPDEFTTL;
	packet.ip.check = dhcp_checksum(&packet.ip, sizeof(packet.ip));

	 
	n = sendto(fd, &packet, IP_UPD_DHCP_SIZE, 0,
			(struct sockaddr *) &dest, sizeof(dest));
	if (n < 0) {
		int err = errno;
		close(fd);
		return -err;
	}

	close(fd);

	return n;
}