ne2k.c (13715B)
1 /* Copyright 1999, Brian J. Swetland. All Rights Reserved. 2 ** This file is provided under the terms of the OpenBLT License 3 */ 4 5 #include "string.h" 6 7 #include <blt/namer.h> 8 #include <blt/syscall.h> 9 #include <blt/conio.h> 10 #include <blt/qsem.h> 11 12 #include <string.h> 13 #include <stdlib.h> 14 #include <stdio.h> 15 16 #include "net.h" 17 18 #define NULL ((void *) 0) 19 20 #include "ne2k.h" 21 22 int find_pci(uint16 vendor, uint16 device, int *iobase, int *irq); 23 24 /* hard code these for now */ 25 #define NIC_IRQ 5 26 #define NIC_ADDR 0x300 27 28 static snic TheSNIC; 29 int snic_irq = NIC_IRQ; 30 int snic_addr = NIC_ADDR; 31 32 33 static unsigned char prom[32]; 34 static unsigned char IP[4] = { 10, 113, 216, 6 }; /* we get our ip from the booter */ 35 36 /* messaging */ 37 static int port_isr = 0; 38 static int port_xmit = 0; 39 40 static qsem_t *sem_xmit_done = NULL; 41 static int port_net = 0; 42 43 qsem_t *mutex = NULL; 44 qsem_t *sem_ring = NULL; 45 46 #define LOG_LEVEL 9999 47 48 /* to keep site's ne2000 code happy */ 49 void kprintf(char *fmt,...) 50 { 51 } 52 53 #define trace(a, b) if (a >= LOG_LEVEL) printf("ne2000: %s\n", b); 54 55 #define RINGSIZE 16 56 #define PACKETSIZE 1536 57 58 typedef struct _pbuf { 59 struct _pbuf *next; /* 4 */ 60 packet_buffer pb; /* 16 */ 61 packet_data pd; /* 8 */ 62 int n; 63 } pbuf; 64 65 #define pb_to_ring(x) ((pbuf *) (((char *) (x)) - 4)) 66 #define pd_to_ring(x) ((pbuf *) (((char *) (x)) - 20)) 67 68 pbuf *p_next = NULL; 69 70 typedef struct pmap pmap; 71 72 struct pmap { 73 struct pmap *next; 74 int udp_port; 75 int blt_port; 76 }; 77 78 pmap *pmaps = NULL; 79 80 pbuf *p_discard; 81 82 void init_ring(void) 83 { 84 int i; 85 pbuf *p; 86 p_next = NULL; 87 88 for(i=0;i<RINGSIZE;i++){ 89 p = (pbuf *) malloc(sizeof(pbuf)); 90 p->next = p_next; 91 p_next = p; 92 p->pb.count = 1; 93 p->pb.buf = &(p->pd); 94 p->pd.ptr = (char *) malloc(PACKETSIZE); 95 p->n = i; 96 } 97 98 p_discard = p_next; 99 p_next = p_next->next; 100 } 101 102 103 /* called by the ne2k core to get a receive buffer */ 104 packet_data *alloc_buffer_data(uint size) 105 { 106 pbuf *P; 107 108 qsem_acquire(sem_ring); 109 if(!p_next){ 110 qsem_release(sem_ring); 111 printf("ne2000: !!! out of packet ringbuffers (recv)\n"); 112 return NULL; 113 } 114 P = p_next; 115 p_next = P->next; 116 qsem_release(sem_ring); 117 118 P->pd.len = size; 119 return &(P->pd); 120 } 121 122 123 /* called by the us to sem_release a received buffer */ 124 void free_buffer_data(packet_data *pd) 125 { 126 pbuf *P = pd_to_ring(pd); 127 qsem_acquire(sem_ring); 128 P->next = p_next; 129 p_next = P; 130 qsem_release(sem_ring); 131 } 132 133 134 /* called by our send data routines to get a send buffer */ 135 pbuf *get_pbuf(void) 136 { 137 pbuf *P; 138 qsem_acquire(sem_ring); 139 if(!p_next){ 140 qsem_release(sem_ring); 141 return p_discard; 142 } 143 P = p_next; 144 p_next = P->next; 145 qsem_release(sem_ring); 146 return P; 147 } 148 149 /* called after a pbuf is xmit'd */ 150 void free_buffer(packet_buffer *ptr) 151 { 152 pbuf *P = pb_to_ring(ptr); 153 154 trace(1, "free_buffer"); 155 156 if(P == p_discard) return; 157 158 qsem_acquire(sem_ring); 159 P->next = p_next; 160 p_next = P; 161 qsem_release(sem_ring); 162 163 qsem_release(sem_xmit_done); 164 } 165 166 int ticks = 0; 167 void idle(void) 168 { 169 int i; 170 for(i=0;i<1000;i++); 171 ticks++; 172 } 173 174 typedef struct 175 { 176 net_ether ether; 177 net_arp arp; 178 } arp_packet; 179 180 void print_arp(unsigned char *p); 181 182 183 void 184 xmit(pbuf *P) 185 { 186 int i; 187 msg_hdr_t mh; 188 /* printf("xmit: P->n = %d\n",P->n);*/ 189 190 if(P == p_discard) return; 191 192 mh.flags = 0; 193 mh.src = port_isr; 194 mh.dst = port_xmit; 195 mh.size = 4; 196 mh.data = &P; 197 if((i = old_port_send(&mh)) != 4) printf("xmit: blargh! %d\n",i); 198 199 } 200 201 void handle_arp(arp_packet *req, pbuf *packet) 202 { 203 if(htons(req->arp.arp_op) == ARP_OP_REQUEST){ 204 if(!memcmp(&(req->arp.arp_ip_target),IP,4)){ 205 pbuf *P; 206 arp_packet *resp; 207 P = get_pbuf(); 208 resp = (arp_packet *) P->pd.ptr; 209 210 /* printf("handle_arp: IS the one!\n");*/ 211 memcpy(&(resp->ether.src),prom,6); 212 memcpy(&(resp->ether.dst),&(req->ether.src),6); 213 resp->ether.type = htons(0x0806); 214 resp->arp.arp_hard_type = htons(1); 215 resp->arp.arp_prot_type = htons(0x0800); 216 resp->arp.arp_hard_size = 6; 217 resp->arp.arp_prot_size = 4; 218 resp->arp.arp_op = htons(ARP_OP_REPLY); 219 memcpy(&(resp->arp.arp_enet_sender),prom,6); 220 memcpy(&(resp->arp.arp_ip_sender),IP,4); 221 memcpy(&(resp->arp.arp_enet_target),&(req->arp.arp_enet_sender),6); 222 memcpy(&(resp->arp.arp_ip_target),&(req->arp.arp_ip_sender),4); 223 print_arp((unsigned char *) &(resp->arp)); 224 225 P->pd.len = sizeof(arp_packet); 226 P->pb.len = sizeof(arp_packet); 227 228 xmit(P); 229 } else { 230 /*printf("handle_arp: NOT the one.\n"); */ 231 } 232 } 233 } 234 235 void print_arp(unsigned char *p) 236 { 237 net_arp *arp = (net_arp *) p; 238 unsigned char *b; 239 unsigned short t; 240 241 printf(" ARP: "); 242 t = htons(arp->arp_op); 243 if(t == ARP_OP_REQUEST) printf("req "); 244 else if(t == ARP_OP_REPLY) printf("rep "); 245 else printf("??? "); 246 247 b = (unsigned char *) &(arp->arp_enet_sender); 248 printf("source: %X:%X:%X:%X:%X:%X ",b[0],b[1],b[2],b[3],b[4],b[5]); 249 b = (unsigned char *) &(arp->arp_ip_sender); 250 printf("(%d.%d.%d.%d)\n",b[0],b[1],b[2],b[3]); 251 252 printf(" ARP: target: "); 253 254 b = (unsigned char *) &(arp->arp_enet_target); 255 printf("%X:%X:%X:%X:%X:%X ",b[0],b[1],b[2],b[3],b[4],b[5]); 256 b = (unsigned char *) &(arp->arp_ip_target); 257 printf("(%d.%d.%d.%d)\n",b[0],b[1],b[2],b[3]); 258 259 } 260 261 void print_ip(unsigned char *p) 262 { 263 } 264 265 int ipchksum(void *_ip, int len) 266 { 267 register unsigned short *ip = (unsigned short *) _ip; 268 register unsigned long sum = 0; 269 len >>= 1; 270 while (len--) { 271 sum += *(ip++); 272 if (sum > 0xFFFF) 273 sum -= 0xFFFF; 274 } 275 return((~sum) & 0x0000FFFF); 276 } 277 278 279 void 280 handle_icmp(icmp_packet *icmp) 281 { 282 pbuf *P; 283 icmp_packet *resp; 284 285 if(icmp->icmp.icmp_type == ICMP_PING_REQ){ 286 P = get_pbuf(); 287 resp = (icmp_packet *) P->pd.ptr; 288 289 memcpy(&(resp->ether.src),prom,6); 290 memcpy(&(resp->ether.dst),&(icmp->ether.src),6); 291 memcpy(&(resp->ether.type),&(icmp->ether.type),2); 292 293 resp->ip.ip_hdr_len = 5; 294 resp->ip.ip_version = 4; 295 resp->ip.ip_tos = 0; 296 resp->ip.ip_len = icmp->ip.ip_len; 297 resp->ip.ip_id = 0; 298 resp->ip.ip_off = 0; 299 resp->ip.ip_ttl = 64; 300 resp->ip.ip_proto = 0x01; 301 resp->ip.ip_chk = 0; 302 (int) resp->ip.ip_src = *(int *) IP; 303 resp->ip.ip_dst = icmp->ip.ip_src; 304 resp->ip.ip_chk = ipchksum(&(resp->ip),sizeof(net_ip)); 305 306 resp->icmp.icmp_type = ICMP_PING_REP; 307 resp->icmp.icmp_code = 0; 308 resp->icmp.icmp_chk = 0; 309 resp->icmp.data.ping.id = icmp->icmp.data.ping.id; 310 resp->icmp.data.ping.seq = icmp->icmp.data.ping.seq; 311 memcpy(resp->icmp.data.ping.data,icmp->icmp.data.ping.data, 312 ntohs(icmp->ip.ip_len) - 28); 313 314 resp->icmp.icmp_chk = ipchksum(&(resp->ip),ntohs(resp->ip.ip_len)); 315 /* printf("ICMP resp l = %d\n",ntohs(resp->ip.ip_len));*/ 316 317 P->pb.len = P->pd.len = ntohs(resp->ip.ip_len)+14; 318 319 xmit(P); 320 } 321 } 322 323 324 void 325 handle_udp(udp_packet *udp, pbuf *packet) 326 { 327 pmap *m; 328 msg_hdr_t msg; 329 int i; 330 331 for(m = pmaps; m; m = m->next){ 332 if(m->udp_port == ntohs(udp->udp.udp_dst)){ 333 msg.src = port_isr; 334 msg.dst = m->blt_port; 335 msg.flags = 0; 336 msg.size = ntohs(udp->udp.udp_len) - 8; 337 msg.data = udp->data; 338 339 if((i = old_port_send(&msg)) <0) { 340 /* XXX: if resource is gone, tear down this mapping */ 341 /* printf("aieee %d / %d / %x\n",i,msg.size,msg.data); */ 342 } 343 } 344 } 345 346 347 /* printf("UDP %d.%d.%d.%d:%d -> %d.%d.%d.%d:%d\n", 348 src[0],src[1],src[2],src[3],ntohs(udp->udp.udp_src), 349 dst[0],dst[1],dst[2],dst[3],ntohs(udp->udp.udp_dst) 350 );*/ 351 } 352 353 354 void 355 handle_tcp(tcp_packet *tcp, pbuf *packet) 356 { 357 trace(2, "handle_tcp"); 358 /* full of worms */ 359 } 360 361 362 void 363 handle_ip(ip_packet *ip, pbuf *packet) 364 { 365 unsigned char *dst = (unsigned char *) &(ip->ip.ip_dst); 366 367 trace(2, "handle_ip"); 368 369 if(!memcmp(dst,IP,4) || (dst[3] == 0xFF)){ /*!memcmp(dst,bcip,4)){*/ 370 #ifdef DEBUG 371 printf("IP %d.%d.%d.%d -> %d.%d.%d.%d\n", 372 src[0],src[1],src[2],src[3], 373 dst[0],dst[1],dst[2],dst[3] 374 ); 375 #endif 376 377 switch(ip->ip.ip_proto){ 378 case 0x01: 379 handle_icmp((icmp_packet *) ip); 380 break; 381 case 0x11: 382 handle_udp((udp_packet *) ip, packet); 383 break; 384 case 0x6: 385 handle_tcp((tcp_packet *) ip, packet); 386 break; 387 } 388 } 389 } 390 391 392 void 393 receive(void *cb, packet_data *_packet) 394 { 395 pbuf *packet = pd_to_ring(_packet); 396 unsigned char *b = (unsigned char *) packet->pd.ptr; 397 398 trace(1, "receive"); 399 400 if(b[12] == 0x08){ 401 if(b[13] == 0x00) { 402 handle_ip((ip_packet *) b, packet); 403 } else if (b[13] == 0x06) { 404 handle_arp((arp_packet *) b, packet); 405 } 406 } 407 free_buffer_data(&(packet->pd)); 408 } 409 410 #define NET_CONNECT 1 411 #define NET_SEND 2 412 #define NET_IP 3 413 typedef struct 414 { 415 int cmd; 416 int port; 417 char data[0]; 418 } net_cmd; 419 420 421 unsigned char bcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 422 423 void send_udp(int src_port, int dst_port, unsigned char *ip, void *data, int size) 424 { 425 pbuf *P; 426 udp_packet *udp; 427 428 P = get_pbuf(); 429 udp = (udp_packet *) P->pd.ptr; 430 431 memcpy(&(udp->ether.src),prom,6); 432 memcpy(&(udp->ether.dst),bcast,6); 433 udp->ether.type = ntohs(0x0800); 434 435 udp->ip.ip_hdr_len = 5; 436 udp->ip.ip_version = 4; 437 udp->ip.ip_tos = 0; 438 udp->ip.ip_len = htons(20 + 8 + size); 439 udp->ip.ip_id = 0; 440 udp->ip.ip_off = 0; 441 udp->ip.ip_ttl = 64; 442 udp->ip.ip_proto = 17; 443 udp->ip.ip_chk = 0; 444 memcpy(&(udp->ip.ip_src),IP,4); 445 memcpy(&(udp->ip.ip_dst),bcast,4); 446 udp->ip.ip_chk = ipchksum(&(udp->ip),sizeof(net_ip)); 447 448 udp->udp.udp_src = htons(src_port); 449 udp->udp.udp_dst = htons(dst_port); 450 udp->udp.udp_len = htons(size + 8); 451 udp->udp.udp_chk = 0; 452 453 memcpy(udp->data, data, size); 454 455 /* printf("sending UDP to %d / %d\n",port,size);*/ 456 P->pb.len = P->pd.len = 14 + 20 + 8 + size; 457 458 xmit(P); 459 460 } 461 462 void 463 control(void) 464 { 465 msg_hdr_t msg; 466 char cbuf[1500]; 467 net_cmd *cmd = (net_cmd *) cbuf; 468 int size; 469 470 msg.flags=0; 471 472 for(;;){ 473 msg.dst = port_net; 474 msg.src = 0; 475 msg.data = cbuf; 476 msg.size = 1500; 477 size = old_port_recv(&msg); 478 479 if(size >= 8){ 480 switch(cmd->cmd){ 481 case NET_IP: 482 memcpy(cbuf,IP,4); 483 msg.size = 4; 484 msg.data = cbuf; 485 msg.dst = msg.src; 486 msg.src = port_isr; 487 old_port_send(&msg); 488 break; 489 490 case NET_CONNECT: { 491 pmap *m = (pmap *) malloc(sizeof(pmap)); 492 if(m) { 493 m->udp_port = cmd->port; 494 m->blt_port = msg.src; 495 m->next = pmaps; 496 pmaps = m; 497 printf("ne2000: routing udp:%d -> blt:%d\n", 498 cmd->port, msg.src); 499 } 500 break; 501 } 502 case NET_SEND: { 503 pmap *m; 504 for(m = pmaps; m; m = m->next){ 505 if(msg.src == m->blt_port) { 506 send_udp(m->udp_port, cmd->port, NULL, cmd->data, size-8); 507 } 508 } 509 break; 510 } 511 } 512 513 } 514 } 515 516 } 517 518 void 519 sender(void) 520 { 521 msg_hdr_t mh; 522 pbuf *packet; 523 524 mh.flags = 0; 525 mh.src = port_isr; 526 mh.size = 4; 527 mh.data = &packet; 528 529 for(;;){ 530 /* wait for a send request */ 531 mh.dst = port_xmit; 532 if(old_port_recv(&mh) == 4){ 533 trace(2, "sender: sending packet"); 534 /* send the packet */ 535 qsem_acquire(mutex); 536 nic_send_packet(&TheSNIC, &(packet->pb)); 537 qsem_release(mutex); 538 539 qsem_acquire(sem_xmit_done); 540 } 541 } 542 } 543 544 void ISR(void) 545 { 546 os_handle_irq(snic_irq); 547 548 for(;;){ 549 os_sleep_irq(); 550 qsem_acquire(mutex); 551 nic_isr(&TheSNIC); 552 qsem_release(mutex); 553 } 554 } 555 556 int main(int argc, char **argv) 557 { 558 int i; 559 560 if(argc == 5){ 561 for(i=0;i<4;i++){ 562 IP[i] = atoi(argv[i+1]); 563 } 564 } 565 566 if(find_pci(0x10ec, 0x8029, &snic_addr, &snic_irq)){ 567 printf("ne2000: found PCI device\n"); 568 } 569 570 os_brk(RINGSIZE*PACKETSIZE*2); 571 572 sem_ring = qsem_create(1); 573 mutex = qsem_create(1); 574 575 /* create our send port */ 576 port_isr = port_create(0,"net_send_port"); 577 port_set_restrict(port_isr, port_isr); 578 port_option(port_isr, PORT_OPT_NOWAIT, 1); 579 580 namer_register(port_isr,"net_xmit"); 581 582 init_ring(); 583 TheSNIC.iobase = 0; 584 nic_init(&TheSNIC, snic_addr, prom, NULL); 585 586 printf("ne2000: irq %d @ 0x%S mac = %X:%X:%X:%X:%X:%X\n", 587 snic_irq,snic_addr,prom[0],prom[1],prom[2],prom[3],prom[4],prom[5]); 588 589 nic_register_notify(&TheSNIC,receive,NULL); 590 printf("ne2000: IP %d.%d.%d.%d\n",IP[0],IP[1],IP[2],IP[3]); 591 592 printf("ne2000: starting sender, dispatcher, and control\n"); 593 594 namer_register(port_net = port_create(0,"net_listen_port"),"net"); 595 596 port_xmit = port_create(port_isr,"net_isr_port"); 597 sem_xmit_done = qsem_create(0); 598 599 os_thread(sender); 600 os_thread(control); 601 602 printf("ne2000: starting NIC\n"); 603 nic_start(&TheSNIC,0); 604 printf("ne2000: \033[32mready.\033[37m\n"); 605 606 os_thread(ISR); 607 608 return 0; 609 }