1 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
2 #pragma GCC diagnostic ignored "-Wcast-qual"
3 #pragma GCC diagnostic ignored "-Wcast-align"
5 #include "CommandQueue.h"
9 #include "SlowTicker.h"
12 #include "PublicDataRequest.h"
13 #include "PlayerPublicAccess.h"
16 #include "clock-arch.h"
17 #include "NetworkPublicAccess.h"
21 #include "webserver.h"
28 #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
30 #define network_enable_checksum CHECKSUM("enable")
31 #define network_webserver_checksum CHECKSUM("webserver")
32 #define network_telnet_checksum CHECKSUM("telnet")
33 #define network_mac_override_checksum CHECKSUM("mac_override")
34 #define network_ip_address_checksum CHECKSUM("ip_address")
35 #define network_ip_gateway_checksum CHECKSUM("ip_gateway")
36 #define network_ip_mask_checksum CHECKSUM("ip_mask")
38 extern "C" void uip_log(char *m
)
40 printf("uIP log message: %s\n", m
);
43 static bool webserver_enabled
, telnet_enabled
, use_dhcp
;
44 static Network
*theNetwork
;
46 static CommandQueue
*command_q
= CommandQueue::getInstance();
48 Network
* Network::instance
;
51 ethernet
= new LPC17XX_Ethernet();
63 static uint32_t getSerialNumberHash()
65 #define IAP_LOCATION 0x1FFF1FF1
68 typedef void (*IAP
)(uint32_t *, uint32_t *);
69 IAP iap
= (IAP
) IAP_LOCATION
;
76 return crc32((uint8_t *)&result
[1], 4 * 4);
79 static bool parse_ip_str(const string
&s
, uint8_t *a
, int len
, char sep
= '.')
83 for (int i
= 0; i
< len
; i
++) {
85 size_t o
= s
.find(sep
, p
);
86 if (o
== string::npos
) return false;
87 n
= s
.substr(p
, o
- p
).c_str();
90 n
= s
.substr(p
).c_str();
97 void Network::on_module_loaded()
99 if ( !THEKERNEL
->config
->value( network_checksum
, network_enable_checksum
)->by_default(false)->as_bool() ) {
100 // as not needed free up resource
105 webserver_enabled
= THEKERNEL
->config
->value( network_checksum
, network_webserver_checksum
, network_enable_checksum
)->by_default(false)->as_bool();
106 telnet_enabled
= THEKERNEL
->config
->value( network_checksum
, network_telnet_checksum
, network_enable_checksum
)->by_default(false)->as_bool();
108 string mac
= THEKERNEL
->config
->value( network_checksum
, network_mac_override_checksum
)->by_default("")->as_string();
109 if (mac
.size() == 17 ) { // parse mac address
110 if (!parse_ip_str(mac
, mac_address
, 6, ':')) {
111 printf("Invalid MAC address: %s\n", mac
.c_str());
112 printf("Network not started due to errors in config");
116 } else { // autogenerate
117 uint32_t h
= getSerialNumberHash();
118 mac_address
[0] = 0x00; // OUI
119 mac_address
[1] = 0x1F; // OUI
120 mac_address
[2] = 0x11; // OUI
121 mac_address
[3] = 0x02; // Openmoko allocation for smoothie board
122 mac_address
[4] = 0x04; // 04-14 03 bits -> chip id, 1 bits -> hashed serial
123 mac_address
[5] = h
& 0xFF; // 00-FF 8bits -> hashed serial
126 ethernet
->set_mac(mac_address
);
128 // get IP address, mask and gateway address here....
130 string s
= THEKERNEL
->config
->value( network_checksum
, network_ip_address_checksum
)->by_default("auto")->as_string();
136 if (!parse_ip_str(s
, ipaddr
, 4)) {
137 printf("Invalid IP address: %s\n", s
.c_str());
140 s
= THEKERNEL
->config
->value( network_checksum
, network_ip_mask_checksum
)->by_default("255.255.255.0")->as_string();
141 if (!parse_ip_str(s
, ipmask
, 4)) {
142 printf("Invalid IP Mask: %s\n", s
.c_str());
145 s
= THEKERNEL
->config
->value( network_checksum
, network_ip_gateway_checksum
)->by_default("192.168.3.1")->as_string();
146 if (!parse_ip_str(s
, ipgw
, 4)) {
147 printf("Invalid IP gateway: %s\n", s
.c_str());
152 printf("Network not started due to errors in config");
157 THEKERNEL
->add_module( ethernet
);
158 THEKERNEL
->slow_ticker
->attach( 100, this, &Network::tick
);
160 // Register for events
161 this->register_for_event(ON_IDLE
);
162 this->register_for_event(ON_MAIN_LOOP
);
163 this->register_for_event(ON_GET_PUBLIC_DATA
);
168 void Network::on_get_public_data(void* argument
) {
169 PublicDataRequest
* pdr
= static_cast<PublicDataRequest
*>(argument
);
171 if(!pdr
->starts_with(network_checksum
)) return;
173 if(pdr
->second_element_is(get_ip_checksum
)) {
174 pdr
->set_data_ptr(this->ipaddr
);
177 }else if(pdr
->second_element_is(get_ipconfig_checksum
)) {
178 // NOTE caller must free the returned string when done
180 int n1
= snprintf(buf
, sizeof(buf
), "IP Addr: %d.%d.%d.%d\n", ipaddr
[0], ipaddr
[1], ipaddr
[2], ipaddr
[3]);
181 int n2
= snprintf(&buf
[n1
], sizeof(buf
)-n1
, "IP GW: %d.%d.%d.%d\n", ipgw
[0], ipgw
[1], ipgw
[2], ipgw
[3]);
182 int n3
= snprintf(&buf
[n1
+n2
], sizeof(buf
)-n1
-n2
, "IP mask: %d.%d.%d.%d\n", ipmask
[0], ipmask
[1], ipmask
[2], ipmask
[3]);
183 int n4
= snprintf(&buf
[n1
+n2
+n3
], sizeof(buf
)-n1
-n2
-n3
, "MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n",
184 mac_address
[0], mac_address
[1], mac_address
[2], mac_address
[3], mac_address
[4], mac_address
[5]);
185 char *str
= (char *)malloc(n1
+n2
+n3
+n4
+1);
186 memcpy(str
, buf
, n1
+n2
+n3
+n4
);
187 str
[n1
+n2
+n3
+n4
]= '\0';
188 pdr
->set_data_ptr(str
);
193 uint32_t Network::tick(uint32_t dummy
)
200 void Network::on_idle(void *argument
)
202 if (!ethernet
->isUp()) return;
205 if (ethernet
->_receive_frame(uip_buf
, &len
)) {
207 this->handlePacket();
211 if (timer_expired(&periodic_timer
)) { /* no packet but periodic_timer time out (0.1s)*/
212 timer_reset(&periodic_timer
);
214 for (int i
= 0; i
< UIP_CONNS
; i
++) {
216 /* If the above function invocation resulted in data that
217 should be sent out on the network, the global variable
218 uip_len is set to a value > 0. */
221 tapdev_send(uip_buf
, uip_len
);
226 for (int i
= 0; i
< UIP_UDP_CONNS
; i
++) {
228 /* If the above function invocation resulted in data that
229 should be sent out on the network, the global variable
230 uip_len is set to a value > 0. */
233 tapdev_send(uip_buf
, uip_len
);
239 This didn't work actually made it worse,it should have worked though
241 // TODO if the command queue is below a certain amount we should poll any stopped connections
242 if(command_q->size() < 4) {
243 for (struct uip_conn *connr = &uip_conns[0]; connr <= &uip_conns[UIP_CONNS - 1]; ++connr) {
244 if(uip_stopped(connr)){
245 // Force a poll of this
246 printf("Force poll of connection\n");
247 uip_poll_conn(connr);
253 /* Call the ARP timer function every 10 seconds. */
254 if (timer_expired(&arp_timer
)) {
255 timer_reset(&arp_timer
);
261 static void setup_servers()
263 if (webserver_enabled
) {
264 // Initialize the HTTP server, listen to port 80.
266 printf("Webserver initialized\n");
269 if (telnet_enabled
) {
270 // Initialize the telnet server
272 printf("Telnetd initialized\n");
275 // sftpd service, which is lazily created on reciept of first packet
276 uip_listen(HTONS(115));
279 extern "C" void dhcpc_configured(const struct dhcpc_state
*s
)
281 printf("Got IP address %d.%d.%d.%d\n",
282 uip_ipaddr1(&s
->ipaddr
), uip_ipaddr2(&s
->ipaddr
),
283 uip_ipaddr3(&s
->ipaddr
), uip_ipaddr4(&s
->ipaddr
));
284 printf("Got netmask %d.%d.%d.%d\n",
285 uip_ipaddr1(&s
->netmask
), uip_ipaddr2(&s
->netmask
),
286 uip_ipaddr3(&s
->netmask
), uip_ipaddr4(&s
->netmask
));
287 printf("Got DNS server %d.%d.%d.%d\n",
288 uip_ipaddr1(&s
->dnsaddr
), uip_ipaddr2(&s
->dnsaddr
),
289 uip_ipaddr3(&s
->dnsaddr
), uip_ipaddr4(&s
->dnsaddr
));
290 printf("Got default router %d.%d.%d.%d\n",
291 uip_ipaddr1(&s
->default_router
), uip_ipaddr2(&s
->default_router
),
292 uip_ipaddr3(&s
->default_router
), uip_ipaddr4(&s
->default_router
));
293 printf("Lease expires in %ld seconds\n", ntohl(s
->lease_time
));
295 theNetwork
->dhcpc_configured(s
->ipaddr
, s
->netmask
, s
->default_router
);
298 void Network::dhcpc_configured(uint32_t ipaddr
, uint32_t ipmask
, uint32_t ipgw
)
300 memcpy(this->ipaddr
, &ipaddr
, 4);
301 memcpy(this->ipmask
, &ipmask
, 4);
302 memcpy(this->ipgw
, &ipgw
, 4);
304 uip_sethostaddr((u16_t
*)this->ipaddr
);
305 uip_setnetmask((u16_t
*)this->ipmask
);
306 uip_setdraddr((u16_t
*)this->ipgw
);
311 void Network::init(void)
313 // two timers for tcp/ip
314 timer_set(&periodic_timer
, CLOCK_SECOND
/ 2); /* 0.5s */
315 timer_set(&arp_timer
, CLOCK_SECOND
* 10); /* 10s */
317 // Initialize the uIP TCP/IP stack.
320 uip_setethaddr(mac_address
);
322 if (!use_dhcp
) { // manual setup of ip
323 uip_ipaddr_t tip
; /* local IP address */
324 uip_ipaddr(tip
, ipaddr
[0], ipaddr
[1], ipaddr
[2], ipaddr
[3]);
325 uip_sethostaddr(tip
); /* host IP address */
326 printf("IP Addr: %d.%d.%d.%d\n", ipaddr
[0], ipaddr
[1], ipaddr
[2], ipaddr
[3]);
328 uip_ipaddr(tip
, ipgw
[0], ipgw
[1], ipgw
[2], ipgw
[3]);
329 uip_setdraddr(tip
); /* router IP address */
330 printf("IP GW: %d.%d.%d.%d\n", ipgw
[0], ipgw
[1], ipgw
[2], ipgw
[3]);
332 uip_ipaddr(tip
, ipmask
[0], ipmask
[1], ipmask
[2], ipmask
[3]);
333 uip_setnetmask(tip
); /* mask */
334 printf("IP mask: %d.%d.%d.%d\n", ipmask
[0], ipmask
[1], ipmask
[2], ipmask
[3]);
339 dhcpc_init(mac_address
, sizeof(mac_address
));
341 printf("Getting IP address....\n");
346 void Network::on_main_loop(void *argument
)
348 // issue commands here if any available
349 while(command_q
->pop()) {
350 // keep feeding them until empty
354 // select between webserver and telnetd server
355 extern "C" void app_select_appcall(void)
357 switch (uip_conn
->lport
) {
359 if (webserver_enabled
) httpd_appcall();
363 if (telnet_enabled
) Telnetd::appcall();
370 printf("Created sftpd service\n");
376 printf("unknown app for port: %d\n", uip_conn
->lport
);
381 void Network::tapdev_send(void *pPacket
, unsigned int size
)
383 memcpy(ethernet
->request_packet_buffer(), pPacket
, size
);
384 ethernet
->write_packet((uint8_t *) pPacket
, size
);
387 // define this to split full frames into two to illicit an ack from the endpoint
391 extern "C" void uip_split_output(void);
392 extern "C" void tcpip_output()
394 theNetwork
->tapdev_send(uip_buf
, uip_len
);
396 void network_device_send()
402 void network_device_send()
404 tapdev_send(uip_buf
, uip_len
);
408 void Network::handlePacket(void)
410 if (uip_len
> 0) { /* received packet */
411 //printf("handlePacket: %d\n", uip_len);
413 if (BUF
->type
== htons(UIP_ETHTYPE_IP
)) { /* IP packet */
416 /* If the above function invocation resulted in data that
417 should be sent out on the network, the global variable
418 uip_len is set to a value > 0. */
422 network_device_send();
425 } else if (BUF
->type
== htons(UIP_ETHTYPE_ARP
)) { /*ARP packet */
427 /* If the above function invocation resulted in data that
428 should be sent out on the network, the global variable
429 uip_len is set to a value > 0. */
431 tapdev_send(uip_buf
, uip_len
); /* ARP ack*/
435 printf("Unknown ethernet packet type %04X\n", htons(BUF
->type
));