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"
10 #include "PublicDataRequest.h"
11 #include "PlayerPublicAccess.h"
14 #include "clock-arch.h"
18 #include "webserver.h"
25 #define BUF ((struct uip_eth_hdr *)&uip_buf[0])
27 extern "C" void uip_log(char *m
)
29 printf("uIP log message: %s\n", m
);
32 static bool webserver_enabled
, telnet_enabled
, use_dhcp
;
33 static Network
*theNetwork
;
35 static CommandQueue
*command_q
= CommandQueue::getInstance();
37 Network
* Network::instance
;
40 ethernet
= new LPC17XX_Ethernet();
52 static uint32_t getSerialNumberHash()
54 #define IAP_LOCATION 0x1FFF1FF1
57 typedef void (*IAP
)(uint32_t *, uint32_t *);
58 IAP iap
= (IAP
) IAP_LOCATION
;
65 return crc32((uint8_t *)&result
[1], 4 * 4);
68 static bool parse_ip_str(const string
&s
, uint8_t *a
, int len
, char sep
= '.')
72 for (int i
= 0; i
< len
; i
++) {
74 size_t o
= s
.find(sep
, p
);
75 if (o
== string::npos
) return false;
76 n
= s
.substr(p
, o
- p
).c_str();
79 n
= s
.substr(p
).c_str();
86 void Network::on_module_loaded()
88 if ( !THEKERNEL
->config
->value( network_checksum
, network_enable_checksum
)->by_default(false)->as_bool() ) {
89 // as not needed free up resource
94 webserver_enabled
= THEKERNEL
->config
->value( network_checksum
, network_webserver_checksum
, network_enable_checksum
)->by_default(false)->as_bool();
95 telnet_enabled
= THEKERNEL
->config
->value( network_checksum
, network_telnet_checksum
, network_enable_checksum
)->by_default(false)->as_bool();
97 string mac
= THEKERNEL
->config
->value( network_checksum
, network_mac_override_checksum
)->by_default("")->as_string();
98 if (mac
.size() == 17 ) { // parse mac address
99 if (!parse_ip_str(mac
, mac_address
, 6, ':')) {
100 printf("Invalid MAC address: %s\n", mac
.c_str());
101 printf("Network not started due to errors in config");
105 } else { // autogenerate
106 uint32_t h
= getSerialNumberHash();
107 mac_address
[0] = 0x00; // OUI
108 mac_address
[1] = 0x1F; // OUI
109 mac_address
[2] = 0x11; // OUI
110 mac_address
[3] = 0x02; // Openmoko allocation for smoothie board
111 mac_address
[4] = 0x04; // 04-14 03 bits -> chip id, 1 bits -> hashed serial
112 mac_address
[5] = h
& 0xFF; // 00-FF 8bits -> hashed serial
115 ethernet
->set_mac(mac_address
);
117 // get IP address, mask and gateway address here....
119 string s
= THEKERNEL
->config
->value( network_checksum
, network_ip_address_checksum
)->by_default("192.168.3.222")->as_string();
125 if (!parse_ip_str(s
, ipaddr
, 4)) {
126 printf("Invalid IP address: %s\n", s
.c_str());
129 s
= THEKERNEL
->config
->value( network_checksum
, network_ip_mask_checksum
)->by_default("255.255.255.0")->as_string();
130 if (!parse_ip_str(s
, ipmask
, 4)) {
131 printf("Invalid IP Mask: %s\n", s
.c_str());
134 s
= THEKERNEL
->config
->value( network_checksum
, network_ip_gateway_checksum
)->by_default("192.168.3.1")->as_string();
135 if (!parse_ip_str(s
, ipgw
, 4)) {
136 printf("Invalid IP gateway: %s\n", s
.c_str());
141 printf("Network not started due to errors in config");
146 THEKERNEL
->add_module( ethernet
);
147 THEKERNEL
->slow_ticker
->attach( 100, this, &Network::tick
);
149 // Register for events
150 this->register_for_event(ON_IDLE
);
151 this->register_for_event(ON_MAIN_LOOP
);
152 this->register_for_event(ON_GET_PUBLIC_DATA
);
157 void Network::on_get_public_data(void* argument
) {
158 PublicDataRequest
* pdr
= static_cast<PublicDataRequest
*>(argument
);
160 if(!pdr
->starts_with(network_checksum
)) return;
162 if(pdr
->second_element_is(get_ip_checksum
)) {
163 pdr
->set_data_ptr(this->ipaddr
);
166 }else if(pdr
->second_element_is(get_ipconfig_checksum
)) {
167 // NOTE caller must free the returned string when done
169 int n1
= snprintf(buf
, sizeof(buf
), "IP Addr: %d.%d.%d.%d\n", ipaddr
[0], ipaddr
[1], ipaddr
[2], ipaddr
[3]);
170 int n2
= snprintf(&buf
[n1
], sizeof(buf
)-n1
, "IP GW: %d.%d.%d.%d\n", ipgw
[0], ipgw
[1], ipgw
[2], ipgw
[3]);
171 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]);
172 int n4
= snprintf(&buf
[n1
+n2
+n3
], sizeof(buf
)-n1
-n2
-n3
, "MAC Address: %02X:%02X:%02X:%02X:%02X:%02X\n",
173 mac_address
[0], mac_address
[1], mac_address
[2], mac_address
[3], mac_address
[4], mac_address
[5]);
174 char *str
= (char *)malloc(n1
+n2
+n3
+n4
+1);
175 memcpy(str
, buf
, n1
+n2
+n3
+n4
);
176 str
[n1
+n2
+n3
+n4
]= '\0';
177 pdr
->set_data_ptr(str
);
182 uint32_t Network::tick(uint32_t dummy
)
189 void Network::on_idle(void *argument
)
191 if (!ethernet
->isUp()) return;
194 if (ethernet
->_receive_frame(uip_buf
, &len
)) {
196 this->handlePacket();
200 if (timer_expired(&periodic_timer
)) { /* no packet but periodic_timer time out (0.1s)*/
201 timer_reset(&periodic_timer
);
203 for (int i
= 0; i
< UIP_CONNS
; i
++) {
205 /* If the above function invocation resulted in data that
206 should be sent out on the network, the global variable
207 uip_len is set to a value > 0. */
210 tapdev_send(uip_buf
, uip_len
);
215 for (int i
= 0; i
< UIP_UDP_CONNS
; i
++) {
217 /* If the above function invocation resulted in data that
218 should be sent out on the network, the global variable
219 uip_len is set to a value > 0. */
222 tapdev_send(uip_buf
, uip_len
);
228 This didn't work actually made it worse,it should have worked though
230 // TODO if the command queue is below a certain amount we should poll any stopped connections
231 if(command_q->size() < 4) {
232 for (struct uip_conn *connr = &uip_conns[0]; connr <= &uip_conns[UIP_CONNS - 1]; ++connr) {
233 if(uip_stopped(connr)){
234 // Force a poll of this
235 printf("Force poll of connection\n");
236 uip_poll_conn(connr);
242 /* Call the ARP timer function every 10 seconds. */
243 if (timer_expired(&arp_timer
)) {
244 timer_reset(&arp_timer
);
250 static void setup_servers()
252 if (webserver_enabled
) {
253 // Initialize the HTTP server, listen to port 80.
255 printf("Webserver initialized\n");
258 if (telnet_enabled
) {
259 // Initialize the telnet server
261 printf("Telnetd initialized\n");
264 // sftpd service, which is lazily created on reciept of first packet
265 uip_listen(HTONS(115));
268 extern "C" void dhcpc_configured(const struct dhcpc_state
*s
)
270 printf("Got IP address %d.%d.%d.%d\n",
271 uip_ipaddr1(&s
->ipaddr
), uip_ipaddr2(&s
->ipaddr
),
272 uip_ipaddr3(&s
->ipaddr
), uip_ipaddr4(&s
->ipaddr
));
273 printf("Got netmask %d.%d.%d.%d\n",
274 uip_ipaddr1(&s
->netmask
), uip_ipaddr2(&s
->netmask
),
275 uip_ipaddr3(&s
->netmask
), uip_ipaddr4(&s
->netmask
));
276 printf("Got DNS server %d.%d.%d.%d\n",
277 uip_ipaddr1(&s
->dnsaddr
), uip_ipaddr2(&s
->dnsaddr
),
278 uip_ipaddr3(&s
->dnsaddr
), uip_ipaddr4(&s
->dnsaddr
));
279 printf("Got default router %d.%d.%d.%d\n",
280 uip_ipaddr1(&s
->default_router
), uip_ipaddr2(&s
->default_router
),
281 uip_ipaddr3(&s
->default_router
), uip_ipaddr4(&s
->default_router
));
282 printf("Lease expires in %ld seconds\n", ntohl(s
->lease_time
));
284 theNetwork
->dhcpc_configured(s
->ipaddr
, s
->netmask
, s
->default_router
);
287 void Network::dhcpc_configured(uint32_t ipaddr
, uint32_t ipmask
, uint32_t ipgw
)
289 memcpy(this->ipaddr
, &ipaddr
, 4);
290 memcpy(this->ipmask
, &ipmask
, 4);
291 memcpy(this->ipgw
, &ipgw
, 4);
293 uip_sethostaddr((u16_t
*)this->ipaddr
);
294 uip_setnetmask((u16_t
*)this->ipmask
);
295 uip_setdraddr((u16_t
*)this->ipgw
);
300 void Network::init(void)
302 // two timers for tcp/ip
303 timer_set(&periodic_timer
, CLOCK_SECOND
/ 2); /* 0.5s */
304 timer_set(&arp_timer
, CLOCK_SECOND
* 10); /* 10s */
306 // Initialize the uIP TCP/IP stack.
309 uip_setethaddr(mac_address
);
311 if (!use_dhcp
) { // manual setup of ip
312 uip_ipaddr_t tip
; /* local IP address */
313 uip_ipaddr(tip
, ipaddr
[0], ipaddr
[1], ipaddr
[2], ipaddr
[3]);
314 uip_sethostaddr(tip
); /* host IP address */
315 printf("IP Addr: %d.%d.%d.%d\n", ipaddr
[0], ipaddr
[1], ipaddr
[2], ipaddr
[3]);
317 uip_ipaddr(tip
, ipgw
[0], ipgw
[1], ipgw
[2], ipgw
[3]);
318 uip_setdraddr(tip
); /* router IP address */
319 printf("IP GW: %d.%d.%d.%d\n", ipgw
[0], ipgw
[1], ipgw
[2], ipgw
[3]);
321 uip_ipaddr(tip
, ipmask
[0], ipmask
[1], ipmask
[2], ipmask
[3]);
322 uip_setnetmask(tip
); /* mask */
323 printf("IP mask: %d.%d.%d.%d\n", ipmask
[0], ipmask
[1], ipmask
[2], ipmask
[3]);
328 dhcpc_init(mac_address
, sizeof(mac_address
));
330 printf("Getting IP address....\n");
335 void Network::on_main_loop(void *argument
)
337 // issue commands here if any available
338 while(command_q
->pop()) {
339 // keep feeding them until empty
343 // select between webserver and telnetd server
344 extern "C" void app_select_appcall(void)
346 switch (uip_conn
->lport
) {
348 if (webserver_enabled
) httpd_appcall();
352 if (telnet_enabled
) Telnetd::appcall();
359 printf("Created sftpd service\n");
365 printf("unknown app for port: %d\n", uip_conn
->lport
);
370 void Network::tapdev_send(void *pPacket
, unsigned int size
)
372 memcpy(ethernet
->request_packet_buffer(), pPacket
, size
);
373 ethernet
->write_packet((uint8_t *) pPacket
, size
);
376 // define this to split full frames into two to illicit an ack from the endpoint
380 extern "C" void uip_split_output(void);
381 extern "C" void tcpip_output()
383 theNetwork
->tapdev_send(uip_buf
, uip_len
);
385 void network_device_send()
391 void network_device_send()
393 tapdev_send(uip_buf
, uip_len
);
397 void Network::handlePacket(void)
399 if (uip_len
> 0) { /* received packet */
400 //printf("handlePacket: %d\n", uip_len);
402 if (BUF
->type
== htons(UIP_ETHTYPE_IP
)) { /* IP packet */
405 /* If the above function invocation resulted in data that
406 should be sent out on the network, the global variable
407 uip_len is set to a value > 0. */
411 network_device_send();
414 } else if (BUF
->type
== htons(UIP_ETHTYPE_ARP
)) { /*ARP 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. */
420 tapdev_send(uip_buf
, uip_len
); /* ARP ack*/
424 printf("Unknown ethernet packet type %04X\n", htons(BUF
->type
));