mini-ip.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. #include <stdio.h>
  2. #include <stdint.h>
  3. #include "sledge/minilisp.h"
  4. #include "sledge/alloc.h"
  5. // mini-ip is part of interim OS, written in 2015 by mntmn.
  6. #define ETH_TYPE_ARP 0x0806
  7. #define ETH_TYPE_IP 0x0800
  8. #define PROTO_IP 0x800
  9. #define ARP_REQUEST 1
  10. #define ARP_REPLY 2
  11. #define PROTO_IP_UDP 0x11
  12. #define PROTO_IP_TCP 0x6
  13. #define PROTO_IP_ICMP 0x1
  14. #define TCP_NS 256
  15. #define TCP_CWR 128
  16. #define TCP_ECE 64
  17. #define TCP_URG 32
  18. #define TCP_ACK 16
  19. #define TCP_PSH 8
  20. #define TCP_RST 4
  21. #define TCP_SYN 2
  22. #define TCP_FIN 1
  23. // size: 14
  24. typedef struct eth_header {
  25. uint8_t dest_mac[6];
  26. uint8_t src_mac[6];
  27. uint16_t type;
  28. uint8_t payload;
  29. } eth_header;
  30. // size: 28
  31. typedef struct arp_packet {
  32. uint16_t hwtype;
  33. uint16_t proto;
  34. uint8_t hwsize;
  35. uint8_t proto_size;
  36. uint16_t opcode;
  37. uint8_t sender_mac[6];
  38. uint8_t sender_ip[4];
  39. uint8_t target_mac[6];
  40. uint8_t target_ip[4];
  41. } arp_packet;
  42. // size: 20
  43. typedef struct ipv4_packet {
  44. uint8_t version;
  45. uint8_t services;
  46. uint16_t size;
  47. uint16_t id;
  48. uint8_t flags;
  49. uint8_t frag_offset; // 0x4000?
  50. uint8_t ttl;
  51. uint8_t proto;
  52. uint16_t checksum;
  53. uint8_t src_ip[4];
  54. uint8_t dest_ip[4];
  55. uint8_t data;
  56. } ipv4_packet;
  57. typedef struct udp_packet {
  58. uint16_t src_port;
  59. uint16_t dest_port;
  60. uint16_t size; // size-8 = body size in bytes
  61. uint16_t checksum;
  62. uint8_t data;
  63. } udp_packet;
  64. typedef struct tcp_packet {
  65. uint16_t src_port;
  66. uint16_t dest_port;
  67. uint32_t seqnum;
  68. uint32_t acknum;
  69. uint8_t data_offset;
  70. uint8_t flags;
  71. uint16_t window;
  72. uint16_t checksum;
  73. uint16_t urg_pointer;
  74. uint8_t data;
  75. } tcp_packet;
  76. typedef struct icmp_packet {
  77. uint8_t type;
  78. uint8_t code;
  79. uint16_t checksum;
  80. uint16_t identifier;
  81. uint16_t seqnum;
  82. uint8_t data;
  83. } icmp_packet;
  84. // no swapping on ARM
  85. uint16_t swap16(uint16_t in) {
  86. uint16_t out = in<<8 | ((in&0xff00)>>8);
  87. return out;
  88. //return in;
  89. }
  90. uint32_t swap32(uint32_t in) {
  91. uint32_t out = in<<24 | ((in&0xff00)<<8) | ((in&0xff0000)>>8) | ((in&0xff000000)>>24);
  92. return out;
  93. //return in;
  94. }
  95. char broadcast_mac[] = {0xff,0xff,0xff,0xff,0xff,0xff};
  96. char my_mac[] = {0xde,0xad,0xbe,0xef,0x02,0x42};
  97. char their_mac[] = {0xff,0xff,0xff,0xff,0xff,0xff};
  98. char my_ip[] = {192,168,1,242};
  99. char their_ip[] = {192,168,1,1};
  100. //char their_ip[] = {91,250,115,15};
  101. //char their_ip[] = {91,217,189,42};
  102. char* tx_packet;
  103. char* rx_packet;
  104. static Cell* udp_cell;
  105. static uint32_t my_seqnum = 23;
  106. static uint32_t their_seqnum = 0;
  107. static uint32_t my_tcp_port = 5000;
  108. static Cell* my_tcp_connected_callback;
  109. static Cell* my_tcp_data_callback;
  110. extern int ethernet_rx(uint8_t* packet);
  111. extern void ethernet_tx(uint8_t* packet, int len);
  112. void send_tcp_packet(int srcport, int port, uint8_t flags, uint32_t seqnum, uint32_t acknum, uint8_t* data, uint16_t size);
  113. void init_mini_ip() {
  114. //udp_cell = buffer_cell;
  115. rx_packet = malloc(64*1024);
  116. tx_packet = malloc(64*1024);
  117. my_tcp_connected_callback = NULL;
  118. my_tcp_data_callback = NULL;
  119. printf("-- init_mini_ip done.\r\n");
  120. }
  121. uint16_t read_word16(void* ptr) {
  122. uint8_t* p = ptr;
  123. return ((uint16_t)p[0])|(p[1]<<8);
  124. }
  125. uint32_t read_word32(void* ptr) {
  126. uint8_t* p = ptr;
  127. return ((uint32_t)p[0])|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
  128. }
  129. void write_word16(void* p, uint16_t value) {
  130. uint8_t* buf = (uint8_t*)p;
  131. *(buf)=value&0xff;
  132. *(buf+1)=(value&0xff00)>>8;
  133. }
  134. void write_word32(void* p, uint32_t value) {
  135. uint8_t* buf = (uint8_t*)p;
  136. *(buf)=value&0xff;
  137. *(buf+1)=(value&0xff00)>>8;
  138. *(buf+2)=(value&0xffff00)>>16;
  139. *(buf+3)=(value&0xffffff00)>>24;
  140. }
  141. int compare_ip(uint8_t* a, uint8_t* b) {
  142. return 0;
  143. }
  144. /*uint32_t write32(uint8_t* p) {
  145. return (p[0])|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
  146. }*/
  147. Cell* eth_task() {
  148. int len = 0;
  149. len = ethernet_rx(rx_packet);
  150. if (len) {
  151. printf("[eth_task] rx: %d\r\n",len);
  152. //b_system_misc(debug_dump_mem, rx_packet, len);
  153. //printf("\n");
  154. eth_header* e = (eth_header*)rx_packet;
  155. //printf("ETH type: %x\r\n",swap16(e->type));
  156. if (swap16(e->type) == ETH_TYPE_ARP) {
  157. arp_packet* arp = (arp_packet*)(((uint8_t*)e)+14);
  158. if (swap16(arp->opcode) == ARP_REQUEST) {
  159. uint8_t* sip = arp->sender_ip;
  160. uint8_t* tip = arp->target_ip;
  161. printf("arp opcode: %x %d.%d.%d.%d looking for: %d.%d.%d.%d\r\n",swap16(arp->opcode),
  162. sip[0],sip[1],sip[2],sip[3],
  163. tip[0],tip[1],tip[2],tip[3]);
  164. if (read_word32(tip) == read_word32(my_ip)) {
  165. //printf("[eth] (arp) they're talking to us.\r\n");
  166. // build response
  167. eth_header* te = (eth_header*)tx_packet;
  168. memcpy(te->dest_mac, arp->sender_mac, 6);
  169. memcpy(te->src_mac, my_mac, 6);
  170. te->type = swap16(ETH_TYPE_ARP);
  171. arp_packet* ta = (arp_packet*)(((uint8_t*)te)+14);
  172. ta->hwtype = swap16(1);
  173. ta->proto = swap16(PROTO_IP);
  174. ta->hwsize = 6;
  175. ta->proto_size = 4;
  176. ta->opcode = swap16(ARP_REPLY);
  177. memcpy(ta->sender_mac, my_mac, 6);
  178. memcpy(ta->sender_ip, arp->target_ip, 4);
  179. memcpy(ta->target_mac, arp->sender_mac, 6);
  180. memcpy(ta->target_ip, arp->sender_ip, 4);
  181. //printf("sending arp reply.\r\n");
  182. ethernet_tx(tx_packet, 14+28);
  183. // their mac address is probably the router :3
  184. memcpy(their_mac, e->src_mac, 6);
  185. }
  186. } else {
  187. //printf("unhandled arp opcode: %x\n",swap16(arp->opcode));
  188. }
  189. }
  190. else if (swap16(e->type) == ETH_TYPE_IP) {
  191. ipv4_packet* i4 = (ipv4_packet*)(((uint8_t*)e)+14);
  192. printf("ip packet! proto: %x\n",i4->proto);
  193. if (i4->proto == PROTO_IP_UDP) {
  194. udp_packet* u = (udp_packet*)(&i4->data);
  195. uint8_t* sip = i4->src_ip;
  196. // TODO: we need an arp table
  197. memcpy(their_mac, e->src_mac, 6);
  198. int size = swap16(u->size)-8;
  199. printf("got UDP packet from %d.%d.%d.%d. size: %d\r\n",sip[0],sip[1],sip[2],sip[3], size);
  200. ((uint8_t*)&u->data)[size]=0;
  201. printf("> %s\r\n",&u->data);
  202. Cell* packet = alloc_num_bytes(size);
  203. memcpy(packet->addr, &u->data, size);
  204. return packet;
  205. }
  206. else if (i4->proto == PROTO_IP_ICMP) {
  207. uint8_t* sip = i4->src_ip;
  208. uint8_t* dip = i4->dest_ip;
  209. printf("got ICMP packet from %d.%d.%d.%d -> %d.%d.%d.%d.\r\n",sip[0],sip[1],sip[2],sip[3],dip[0],dip[1],dip[2],dip[3]);
  210. icmp_packet* icmp = (icmp_packet*)(&i4->data);
  211. printf("ICMP type: %d id: seqnum: %d\r\n",icmp->type,icmp->identifier,icmp->seqnum);
  212. }
  213. else if (i4->proto == PROTO_IP_TCP) {
  214. tcp_packet* rxt = (tcp_packet*)(&i4->data);
  215. int payload_size = swap16(read_word16(&i4->size))-20-20;
  216. printf("got TCP packet, flags: %x, payload_size: %d\r\n",rxt->flags,payload_size);
  217. if (rxt->flags == (TCP_SYN|TCP_ACK)) {
  218. // reply to SYN ACK
  219. my_seqnum++;
  220. their_seqnum = swap32(read_word32(&rxt->seqnum))+1;
  221. printf("REPLY TO SYN ACK: %x\n",rxt->flags);
  222. send_tcp_packet(swap16(read_word16(&rxt->dest_port)),swap16(read_word16(&rxt->src_port)),TCP_ACK,my_seqnum,their_seqnum,NULL,0);
  223. /*if (my_tcp_connected_callback) {
  224. funcptr fn = (funcptr)my_tcp_connected_callback->next;
  225. fn();
  226. return;
  227. }*/
  228. }
  229. else if ((rxt->flags&TCP_FIN) == TCP_FIN) {
  230. send_tcp_packet(swap16(read_word16(&rxt->dest_port)),swap16(read_word16(&rxt->src_port)),TCP_RST,my_seqnum,their_seqnum,NULL,0);
  231. my_seqnum++;
  232. }
  233. else if (payload_size>0) {
  234. // receive and reply to data
  235. uint32_t old_seqnum = their_seqnum;
  236. their_seqnum = swap32(read_word32(&rxt->seqnum))+payload_size;
  237. //printf("REPLY TO PSH acknum: %d\r\n",their_seqnum);
  238. send_tcp_packet(swap16(read_word16(&rxt->dest_port)),swap16(read_word16(&rxt->src_port)),TCP_ACK,my_seqnum,their_seqnum,NULL,0);
  239. printf("got data, copying payload size %d\r\n",payload_size);
  240. Cell* packet = alloc_num_bytes(payload_size+1);
  241. memcpy(packet->addr, &rxt->data, payload_size);
  242. *((uint8_t*)packet->addr+payload_size) = 0;
  243. if (old_seqnum != their_seqnum) {
  244. /*if (my_tcp_data_callback) {
  245. funcptr fn = (funcptr)my_tcp_data_callback->next;
  246. fn(udp_cell);
  247. return;
  248. }*/
  249. return packet;
  250. } // else duplicate packet received
  251. }
  252. }
  253. }
  254. }
  255. return alloc_num_bytes(0);
  256. }
  257. /* taken from TCP/IP Illustrated Vol. 2(1995) by Gary R. Wright and W. Richard
  258. Stevens. Page 236 */
  259. uint16_t cksum(uint16_t* ip, int len){
  260. long sum = 0; /* assume 32 bit long, 16 bit short */
  261. while(len > 1){
  262. uint16_t word = swap16(*ip);
  263. sum += word;
  264. ip++;
  265. if(sum & 0x80000000) { /* if high order bit set, fold */
  266. sum = (sum & 0xFFFF) + (sum >> 16);
  267. }
  268. len -= 2;
  269. }
  270. if(len) { /* take care of left over byte */
  271. sum += swap16((uint16_t) *(unsigned char *)ip);
  272. }
  273. while(sum>>16) {
  274. sum = (sum & 0xFFFF) + (sum >> 16);
  275. }
  276. return ~sum;
  277. }
  278. uint16_t transport_cksum(void* packet, uint16_t protocol, ipv4_packet* i4, uint16_t len) {
  279. long sum = 0; /* assume 32 bit long, 16 bit short */
  280. uint16_t* data = (uint16_t*)packet;
  281. uint16_t i = len;
  282. while(i > 1){
  283. uint16_t word = swap16(*data);
  284. sum += word;
  285. data++;
  286. if(sum & 0x80000000) /* if high order bit set, fold */
  287. sum = (sum & 0xFFFF) + (sum >> 16);
  288. i -= 2;
  289. }
  290. if (i) { /* take care of left over byte */
  291. uint16_t word = swap16((uint16_t) *(unsigned char *)data);
  292. sum += word;
  293. }
  294. // add pseudo header
  295. sum += swap16(((uint16_t*)i4->src_ip)[0]);
  296. sum += swap16(((uint16_t*)i4->src_ip)[1]);
  297. sum += swap16(((uint16_t*)i4->dest_ip)[0]);
  298. sum += swap16(((uint16_t*)i4->dest_ip)[1]);
  299. sum += protocol;
  300. sum += len;
  301. while(sum>>16) {
  302. sum = (sum & 0xFFFF) + (sum >> 16);
  303. }
  304. return ~sum;
  305. }
  306. Cell* machine_send_udp(Cell* data_cell) {
  307. if (!data_cell || (data_cell->tag!=TAG_BYTES && data_cell->tag!=TAG_STR)) return alloc_error(ERR_INVALID_PARAM_TYPE);
  308. int len = data_cell->size;
  309. uint8_t* data = (uint8_t*)data_cell->addr;
  310. eth_header* te = (eth_header*)tx_packet;
  311. memcpy(te->dest_mac, their_mac, 6);
  312. memcpy(te->src_mac, my_mac, 6);
  313. te->type = swap16(ETH_TYPE_IP);
  314. ipv4_packet* i4 = (ipv4_packet*)(((uint8_t*)te)+14);
  315. i4->version = (4<<4) | 5; // ipv4 + ihl5 (5*4 bytes header)
  316. i4->services = 0;
  317. i4->size = swap16(20+8+len); // patch later i4+udp
  318. i4->id = swap16(0xbeef);
  319. i4->flags = 0x40; // don't fragment
  320. i4->frag_offset = 0; // cargo cult
  321. i4->ttl = 64;
  322. i4->proto = PROTO_IP_UDP;
  323. i4->checksum = 0;
  324. memcpy(i4->src_ip, my_ip, 4);
  325. memcpy(i4->dest_ip, their_ip, 4);
  326. i4->checksum = swap16(cksum((uint16_t*)i4, 20));
  327. udp_packet* u = (udp_packet*)(&i4->data);
  328. u->dest_port = swap16(4001);
  329. u->src_port = swap16(4000);
  330. u->size = swap16(len+8);
  331. u->checksum = 0; // fixme
  332. if (data && len) {
  333. memcpy(&u->data, data, len);
  334. }
  335. int packet_len = len+8+20+14; // data + udp + i4 + eth
  336. u->checksum = swap16(transport_cksum(u, PROTO_IP_UDP, i4, len+8));
  337. printf("sending udp packet.\r\n");
  338. ethernet_tx(tx_packet, packet_len);
  339. return alloc_int(1);
  340. }
  341. Cell* machine_bind_tcp(Cell* port_cell, Cell* fn_cell) {
  342. }
  343. void send_tcp_packet(int srcport, int port, uint8_t flags, uint32_t seqnum, uint32_t acknum, uint8_t* data, uint16_t size) {
  344. memset(tx_packet, 0, 64*1024);
  345. // hardcoded router
  346. their_mac[0] = 0x84;
  347. their_mac[1] = 0xa8;
  348. their_mac[2] = 0xe4;
  349. their_mac[3] = 0x67;
  350. their_mac[4] = 0x08;
  351. their_mac[5] = 0x12;
  352. int len = size;
  353. eth_header* te = (eth_header*)tx_packet;
  354. memcpy(te->dest_mac, their_mac, 6);
  355. memcpy(te->src_mac, my_mac, 6);
  356. te->type = swap16(ETH_TYPE_IP);
  357. ipv4_packet* i4 = (ipv4_packet*)(((uint8_t*)te)+14);
  358. i4->version = (4<<4) | 5; // ipv4 + ihl5 (5*4 bytes header)
  359. i4->services = 0;
  360. i4->size = swap16(20+20+len); // patch later i4+tcp
  361. i4->id = swap16(0xbeef);
  362. i4->flags = 0x40; // don't fragment
  363. i4->frag_offset = 0;
  364. i4->ttl = 64;
  365. i4->proto = PROTO_IP_TCP;
  366. i4->checksum = 0;
  367. memcpy(i4->src_ip, my_ip, 4);
  368. memcpy(i4->dest_ip, their_ip, 4);
  369. i4->checksum = swap16(cksum((uint16_t*)i4, 20));
  370. tcp_packet* t = (tcp_packet*)(&i4->data);
  371. t->dest_port = swap16(port);
  372. t->src_port = swap16(srcport);
  373. write_word32(&t->seqnum, swap32(seqnum));
  374. write_word32(&t->acknum, swap32(acknum));
  375. t->data_offset = (5<<4);
  376. t->flags = flags;
  377. write_word16(&t->window, swap16(0x7210));
  378. t->urg_pointer = 0;
  379. t->checksum = 0;
  380. memcpy(&t->data, data, len);
  381. t->checksum = swap16(transport_cksum(t, PROTO_IP_TCP, i4, len+5*4));
  382. int packet_len = len+5*4+20+14; // data + tcp + i4 + eth
  383. printf("sending tcp packet (%d).\n",packet_len);
  384. ethernet_tx(tx_packet, packet_len);
  385. }
  386. static int their_tcp_port = 8000;
  387. int connect_tcp(char* host_ip, int port) {
  388. //if (!host_cell || (host_cell->tag!=TAG_BYTES && host_cell->tag!=TAG_STR)) return alloc_error(ERR_INVALID_PARAM_TYPE);
  389. //if (!port_cell || (port_cell->tag!=TAG_INT)) return alloc_error(ERR_INVALID_PARAM_TYPE);
  390. //my_tcp_connected_callback = connected_fn_cell;
  391. //my_tcp_data_callback = data_fn_cell;
  392. their_tcp_port = port;
  393. memcpy(their_ip,host_ip,4);
  394. my_seqnum++;
  395. send_tcp_packet(my_tcp_port,port,TCP_RST,my_seqnum,0,NULL,0);
  396. my_tcp_port++;
  397. my_seqnum+=10;
  398. send_tcp_packet(my_tcp_port,port,TCP_SYN,my_seqnum,0,NULL,0);
  399. return 1;
  400. }
  401. Cell* send_tcp(Cell* data_cell) {
  402. if (!data_cell || (data_cell->tag!=TAG_BYTES && data_cell->tag!=TAG_STR)) return alloc_error(ERR_INVALID_PARAM_TYPE);
  403. send_tcp_packet(my_tcp_port,their_tcp_port,TCP_PSH|TCP_ACK,my_seqnum,their_seqnum,data_cell->addr,data_cell->size);
  404. my_seqnum+=data_cell->size;
  405. return alloc_int(1);
  406. }