4
* Copyright � 2006-2007 Silicondust Engineering Ltd. <www.silicondust.com>.
6
* This library is free software; you can redistribute it and/or
7
* modify it under the terms of the GNU Lesser General Public
8
* License as published by the Free Software Foundation; either
9
* version 3 of the License, or (at your option) any later version.
11
* This library is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14
* Lesser General Public License for more details.
16
* You should have received a copy of the GNU Lesser General Public
17
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
20
#include "hdhomerun_os.h"
21
#include "hdhomerun_pkt.h"
22
#include "hdhomerun_dhcp.h"
25
uint8_t bootp_message_type;
26
uint8_t hardware_type;
27
uint8_t hardware_address_length;
29
uint32_t transaction_id;
30
uint16_t seconds_elapsed;
34
uint32_t next_server_ip;
35
uint32_t relay_agent_ip;
36
uint8_t client_mac[16];
37
uint8_t server_host_name[64];
38
uint8_t boot_file_name[128];
39
uint32_t magic_cookie;
42
struct hdhomerun_dhcp_t {
43
struct hdhomerun_dhcp_interface_t *intf_list;
46
volatile bool_t terminate;
49
static THREAD_FUNC_PREFIX hdhomerun_dhcp_thread_execute(void *arg);
51
struct hdhomerun_dhcp_t *hdhomerun_dhcp_create(void)
53
struct hdhomerun_dhcp_t *dhcp = (struct hdhomerun_dhcp_t *)calloc(1, sizeof(struct hdhomerun_dhcp_t));
58
if (pthread_create(&dhcp->thread, NULL, &hdhomerun_dhcp_thread_execute, dhcp) != 0) {
66
void hdhomerun_dhcp_destroy(struct hdhomerun_dhcp_t *dhcp)
68
dhcp->terminate = TRUE;
69
pthread_join(dhcp->thread, NULL);
71
if (dhcp->sock != -1) {
78
static bool_t hdhomerun_dhcp_create_sock(struct hdhomerun_dhcp_t *dhcp)
81
int sock = (int)socket(AF_INET, SOCK_DGRAM, 0);
87
setsocktimeout(sock, SOL_SOCKET, SO_RCVTIMEO, 1000);
89
/* Allow broadcast. */
91
setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&sock_opt, sizeof(sock_opt));
94
struct sockaddr_in sock_addr;
95
memset(&sock_addr, 0, sizeof(sock_addr));
96
sock_addr.sin_family = AF_INET;
97
sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
98
sock_addr.sin_port = htons(67);
99
if (bind(sock, (struct sockaddr *)&sock_addr, sizeof(sock_addr)) != 0) {
108
static void hdhomerun_dhcp_send(struct hdhomerun_dhcp_t *dhcp, uint8_t message_type, uint8_t *buffer)
110
struct dhcp_pkt_t *pkt = (struct dhcp_pkt_t *)buffer;
112
uint32_t remote_addr = 0xA9FE0000;
113
remote_addr |= (uint32_t)pkt->client_mac[4] << 8;
114
remote_addr |= (uint32_t)pkt->client_mac[5] << 0;
116
pkt->bootp_message_type = 0x02;
117
pkt->your_ip = htonl(remote_addr);
118
pkt->next_server_ip = htonl(0xA9FEFFFF);
120
uint8_t *ptr = buffer + sizeof(struct dhcp_pkt_t);
122
hdhomerun_write_u8(&ptr, 53);
123
hdhomerun_write_u8(&ptr, 1);
124
hdhomerun_write_u8(&ptr, message_type);
126
hdhomerun_write_u8(&ptr, 54);
127
hdhomerun_write_u8(&ptr, 4);
128
hdhomerun_write_u32(&ptr, 0xA9FEFFFF);
130
hdhomerun_write_u8(&ptr, 51);
131
hdhomerun_write_u8(&ptr, 4);
132
hdhomerun_write_u32(&ptr, 7*24*60*60);
134
hdhomerun_write_u8(&ptr, 1);
135
hdhomerun_write_u8(&ptr, 4);
136
hdhomerun_write_u32(&ptr, 0xFFFF0000);
138
hdhomerun_write_u8(&ptr, 0xFF);
140
while (ptr < buffer + 300) {
141
hdhomerun_write_u8(&ptr, 0x00);
144
struct sockaddr_in sock_addr;
145
memset(&sock_addr, 0, sizeof(sock_addr));
146
sock_addr.sin_family = AF_INET;
147
sock_addr.sin_addr.s_addr = htonl(0xFFFFFFFF);
148
sock_addr.sin_port = htons(68);
150
sendto(dhcp->sock, (char *)buffer, (int)(ptr - buffer), 0, (struct sockaddr *)&sock_addr, sizeof(sock_addr));
153
static void hdhomerun_dhcp_recv(struct hdhomerun_dhcp_t *dhcp, uint8_t *buffer, uint8_t *end)
155
uint8_t *ptr = buffer + sizeof(struct dhcp_pkt_t);
160
struct dhcp_pkt_t *pkt = (struct dhcp_pkt_t *)buffer;
161
if (ntohl(pkt->magic_cookie) != 0x63825363) {
165
static uint8_t vendor[3] = {0x00, 0x18, 0xDD};
166
if (memcmp(pkt->client_mac, vendor, 3) != 0) {
173
if (hdhomerun_read_u8(&ptr) != 53) {
176
if (hdhomerun_read_u8(&ptr) != 1) {
179
uint8_t message_type_val = hdhomerun_read_u8(&ptr);
181
switch (message_type_val) {
183
hdhomerun_dhcp_send(dhcp, 0x02, buffer);
186
hdhomerun_dhcp_send(dhcp, 0x05, buffer);
193
static THREAD_FUNC_PREFIX hdhomerun_dhcp_thread_execute(void *arg)
195
struct hdhomerun_dhcp_t *dhcp = (struct hdhomerun_dhcp_t *)arg;
198
if (dhcp->terminate) {
202
if (dhcp->sock == -1) {
203
if (!hdhomerun_dhcp_create_sock(dhcp)) {
209
uint8_t buffer[1460];
210
int length = recv(dhcp->sock, (char *)buffer, sizeof(buffer), 0);
212
if (sock_getlasterror_socktimeout) {
220
hdhomerun_dhcp_recv(dhcp, buffer, buffer + length);