openblt

a hobby OS from the late 90s
git clone http://frotz.net/git/openblt.git
Log | Files | Refs | LICENSE

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 }