📄 ethernet.c
字号:
} for(i=0;i<state->copy.numSndEntries;i++) { if( regs->sndEntries[i].flag != OS_OWNED || !state->sndAcks[i] ) return; } /* clear the interrupt bit */ if (state->intrPosted) { /* clear the interrupt line */ SIM_DEBUG(('e', "ETHER-trace: %d ClearSlot\n", state->ethernum)); if (state->int_f) state->int_f(state->ethernum, 0); state->intrPosted = 0; /* just like EWOULDBLOCK case */ }}static void SimetherRaiseSlot(SimetherState *state, char* cause){ if (!state->intrPosted) { SIM_DEBUG(('e', "ETHER-trace: %d RaiseSlot (%s)\n", state->ethernum, cause)); if (state->int_f) state->int_f(state->ethernum, 1); state->intrPosted = 1; } else { SIM_DEBUG(('e', "ETHER-trace: %d RaiseSlot (%s) already posted\n", state->ethernum, cause)); }}static void SimetherSendOver(SimetherState *state, int index) { int i,lastChunk; /* release send chunks */ i = state->copy.sndEntries[index].firstChunk; lastChunk = state->copy.sndEntries[index].lastChunk; while( 1 ) { state->chunkOwner[i] = OS_OWNED; if( i==lastChunk ) break; i++; if( i >= state->copy.numSndChunks ) i -= state->copy.numSndChunks ; } /* Packet fully sent */ state->copy.sndEntries[index].flag = OS_OWNED; /* Set done flag immediately. should be base mode only */ SimetherRaiseSlot( state, "send" );}#ifdef VCS_FAKE/* Types of packets */#define VCS_FAKE_REQUEST 0#define VCS_FAKE_REPLY 1#define VCS_FAKE_ERROR 2/* Markers, in case we get lost in the packet */#define VCS_FAKE_MARKER "01xy"#define VCS_FAKE_SMARKER "01xy"#define VCS_FAKE_RMARKER "02xy"#define VCS_FAKE_EMARKER "03xy"#define VCS_FAKE_MSIZE 4#define VCS_FAKE_OFF 0 #define VCS_FAKE_SAVE 1#define VCS_FAKE_MATCH 2/* These two defines are reaching into the structure below. So if that changes (Fat chance!) we must change the defines too. They take a ethernet packet and return the IP ID field or the IP Checksum field*//* #define VCS_FAKE_IPID(x) (*((u_short *)(((u_char *)(x)) + 18))) */#define VCS_FAKE_IPID(x) (((struct ip *)(((u_char *)(x)) + sizeof(struct ether_header)))->ip_id)/* #define VCS_FAKE_IPCKSUM(x) (*((u_short *)(((u_char *)(x)) + 24))) */#define VCS_FAKE_IPCKSUM(x) (((struct ip *)(((u_char *)(x)) + sizeof(struct ether_header)))->ip_sum)/* structure for storing the previously traced packets for comparison */#define VCS_FAKE_MAX_BUF 40 /* maximum number of captured packets */struct ipbuf_t { int len; int replyLen; int used; char *request; char *reply;} ipbuf[VCS_FAKE_MAX_BUF];static int ipbufid = 0;static int vfd; /* file descriptor for storing or matching */static int efd;static char dumpbuf[1600]; /* need this for copying data at various points */int VcsFakeType = 0; /* Type of operation to be done, nothing, save or match */char *VcsFakeFilename = NULL; /* filename for writing or reading packets *//* If we are using VCSFAKESAVE, just open the file to save the packets. If VCSFAKEMATCH, then read in the packets from the file and store them away.*/voidVcsFakeInit(void){ u_long marker, prevmarker = -1, dbuflen; struct ipbuf_t *ptr, *replyPtr; if(VcsFakeType == VCS_FAKE_OFF) { /* default behavior, just return */ return; } /* if in Save mode, just open the file and return */ if(VcsFakeType == VCS_FAKE_SAVE) { if((vfd = open(VcsFakeFilename, O_CREAT|O_RDWR|O_TRUNC, 0777)) == NULL) { CPUError("Error: Could not open dump file %s\n", VcsFakeFilename); vfd = -1; } return; } if(VcsFakeType == VCS_FAKE_MATCH) { if((vfd = open(VcsFakeFilename, O_RDONLY, 0777)) == NULL) { CPUError("Error: Could not open dump file %s\n", VcsFakeFilename); vfd = -1; return; } CPUWarning("Opened VcsFake dumpfile\n"); while(read(vfd, &marker, VCS_FAKE_MSIZE) == VCS_FAKE_MSIZE) { if(!bcmp(&marker, VCS_FAKE_SMARKER, VCS_FAKE_MSIZE)) { marker = VCS_FAKE_REQUEST; } else if(!bcmp(&marker, VCS_FAKE_RMARKER, VCS_FAKE_MSIZE)) { marker = VCS_FAKE_REPLY; } else { CPUError("VcsFakeEther: Unknown marker"); marker = -1; return; } if(marker == VCS_FAKE_REQUEST) { ptr = &(ipbuf[ipbufid++]); ptr->used = 0; read(vfd, &(ptr->len), sizeof(ptr->len)); ptr->request = (char *)ZMALLOC(ptr->len,"etherReq"); read(vfd, ptr->request, ptr->len); VCS_FAKE_IPID(ptr->request) = 0; VCS_FAKE_IPCKSUM(ptr->request) = 0; CPUWarning("REQ (%d): SRC = 0x%x DST = 0x%x\n", ptr->len, *((int *)&(ptr->request[26])), *((int *)&(ptr->request[30]))); ptr->reply = 0; ptr->replyLen = 0; } else if(marker == VCS_FAKE_REPLY) { if(prevmarker == VCS_FAKE_REQUEST) { read(vfd, &(ptr->replyLen), sizeof(ptr->replyLen)); ptr->reply = (char *)ZMALLOC(ptr->replyLen,"VCS"); read(vfd, ptr->reply, ptr->replyLen); CPUWarning("REP (%d): SRC = 0x%x DST = 0x%x\n", ptr->replyLen, *((int *)&(ptr->reply[26])), *((int *)&(ptr->reply[30]))); } else { /* Reply without a matching request */ read(vfd, &(dbuflen), sizeof(u_long)); read(vfd, dumpbuf, dbuflen); CPUWarning("REP (Unsolicited)(%d): SRC = 0x%x DST = 0x%x\n", ptr->replyLen, *((int *)&(dumpbuf[26])), *((int *)&(dumpbuf[30]))); } } prevmarker = marker; } CPUWarning("VcsFake init done\n"); }}#endif/******************************************************************** * SimetherSendPacket * Returns 0 if the interrupt was posted, 1 if the transmission is * still in flight ********************************************************************/static int SimetherSendPacket(SimetherState *state, int index ) {#ifndef i386 int err, i, j, lastChunk; struct msghdr msg; int length = 0; int cpuNum = FIRST_CPU(state->machine); /* The following two cannot be on the stack since in base * mode we get to this point while running on the kernel stack. * They take waayyy to much memory and cause a TLB miss * while in the back door. * * Making them static appears to be safe because each cpu process * gets its own copy. In non-base-mode runs we are safe because * this code is non-reentrant. */ static struct iovec iovec[ETHER_MAX_SND_CHUNKS+1]; static char extraBuf[ETHERMIN + sizeof(struct ether_header)]; j = state->copy.sndEntries[index].firstChunk; lastChunk = state->copy.sndEntries[index].lastChunk; for(i=0;i<ETHER_MAX_SND_CHUNKS+1; i ++) { ASSERT(IS_VALID_PA(M_FROM_CPU(cpuNum), state->copy.sndChunks[j].pAddr)); iovec[i].iov_base = PHYS_TO_MEMADDR(M_FROM_CPU(cpuNum), state->copy.sndChunks[j].pAddr); iovec[i].iov_len = state->copy.sndChunks[j].len; length += state->copy.sndChunks[j].len; if( j == lastChunk ) { i++; break; } j++; if( j >= state->copy.numSndChunks ) j -= state->copy.numSndChunks ; } ASSERT( i <=state->copy.numSndChunks ); if (length < ETHERMIN + sizeof(struct ether_header)) { bzero(extraBuf,sizeof(extraBuf)); iovec[i].iov_base = extraBuf; iovec[i].iov_len = ETHERMIN + sizeof(struct ether_header) - length; length = ETHERMIN + sizeof(struct ether_header); i++; } { int j; SIM_DEBUG_DETAIL(('i', "ETHER-trans", cpuNum, "controller=%d ", state->ethernum)); for(j=0; j<i; j++) { CPUPrint(" %x/%i", iovec[j].iov_base, iovec[j].iov_len); } CPUPrint("\n"); } msg.msg_name = (caddr_t) &state->toaddr; msg.msg_namelen = state->toaddrlen; msg.msg_iov = iovec; msg.msg_iovlen = i; msg.msg_accrights = (caddr_t) 0; msg.msg_accrightslen = 0; if( ClusterSendPacket(cpuNum,iovec, msg.msg_iovlen) || LocalClusterSendPacket(cpuNum, state->ethernum, iovec, msg.msg_iovlen) ) { /* packet sent through the cluster */ /* no timing model for now */ SimetherSendOver(state,index); return 0; /* override the copy */ } else { #ifdef VCS_FAKE if(VcsFakeType == VCS_FAKE_MATCH) { int i, j = 0; struct ipbuf_t *ptr; struct sockaddr_in myaddr; int myaddrlen, matchNoReply = -1; /* Since we have to zero out the checksum and id, make a copy in a single buffer */ for(i=0;i<msg.msg_iovlen;i++) { bcopy(iovec[i].iov_base, &(dumpbuf[j]), iovec[i].iov_len); j += iovec[i].iov_len; } /* zero the IP id and check sum fields of the packet */ VCS_FAKE_IPID(dumpbuf) = 0; VCS_FAKE_IPCKSUM(dumpbuf) = 0; for(i=0;i<ipbufid;i++) { ptr = &(ipbuf[i]); if(!(ptr->used) && (ptr->len == length) && (bcmp(ptr->request, dumpbuf, length) == 0)) { /* found a match */ iovec[0].iov_base = ptr->reply; iovec[0].iov_len = ptr->replyLen; myaddrlen = sizeof(struct sockaddr_in); getsockname(state->fd, &myaddr, &myaddrlen); msg.msg_name = (caddr_t) &myaddr; msg.msg_namelen = myaddrlen; msg.msg_iov = iovec; msg.msg_iovlen = 1; ptr->used = 1; break; } } err = 0; if(i == ipbufid) { /* did not find a match */ CPUError("VcsFakeEther: No match (%d) SRC = 0x%x DST = 0x%x\n", length, *((int *)&(dumpbuf[26])), *((int *)&(dumpbuf[30]))); /* write(vfd, VCS_EMARKER, VCS_MSIZE); write(vfd, &length, sizeof(length)); write(vfd, devPtr->req.buffer, length); */ err = -1; } else if(iovec[0].iov_len) { /* found a match with a reply, send the message. It is has been switched previously to be the reply, addressed to me. */ CPUWarning("VCS_FAKE: Match(%d) SRC = 0x%x DST = 0x%x\n", ptr->len, *((int *)&(ptr->request[26])), *((int *)&(ptr->request[30]))); /* if (sendmsg(state->fd, &msg, 0) < 0) { CPUError("simetherOutput: sendmsg"); err = -1; } */ SimetherSendOver(state,index); if(SimetherReceivePacket(state->ethernum, dumpbuf, length) < 0) { CPUError("simetherOutput: sendmsg"); err = -1; } return(0); } else { /* Found a match, but there was no associated reply. Do nothing */ CPUWarning("VCS_FAKE: Match No reply (%d) SRC = 0x%x DST = 0x%x\n", ptr->len, *((int *)&(ptr->request[26])), *((int *)&(ptr->request[30]))); } SimetherSendOver(state,index); return 0; }#endif if (sendmsg(state->fd, &msg, 0) < 0) { perror("simetherOutput: sendmsg"); err = -1; } else {#ifdef VCS_FAKE if(VcsFakeType == VCS_FAKE_SAVE) { /* Send was successful, save the packet */ int i; write(vfd, VCS_FAKE_SMARKER, VCS_FAKE_MSIZE); write(vfd, &length, sizeof(length)); for(i=0;i<msg.msg_iovlen;i++) { write(vfd, iovec[i].iov_base, iovec[i].iov_len); } }#endif err = 0; } SimetherSendOver(state,index); return err; /* override the copy */ } /* return 1;- make compiler happy */ /* allow the copy */#else Sim_Warning("Uh oh... SimetherSendPacked called\n"); return 1;#endif}/*********************************************************************** * SimetherReceivePacket. * * Called either in interrupt dispatcher (simcp0 poll) when using UDP * to carry or in the normal context of the CPU simulator if we bypass * UPD. * * !!! Never install a callback from when using UDP * ************************************************************************/intSimetherReceivePacket(int iface_num, char *packet, int packetSize){ #ifndef i386 SimetherState *state = simetherState +iface_num; int size = 0; struct sockaddr_in fromaddr; int fromaddrlen; char buffer[SIMETHER_MAX_TRANSFER_SIZE]; int cpuNum = FIRST_CPU(state->machine); ASSERT( iface_num < ETHER_MAX_CONTROLLERS); /* * Choose a free receiving buffer or drop the packet * in this model, we do not drop packets on the floor, but * delay the processing of the UDP packets. */ if( !packet ) { ASSERT( !disableEthernet ); /* the packet comes from the UDP port */ if( state->copy.rcvEntries[state->rcvPtr].flag == OS_OWNED ) { /* * wait for the kernel to process */ SIM_DEBUG(('e', "ETHER-receive: %d Recieve buffers full \n", state->ethernum)); LogEntry("ETHER",cpuNum,"controller=%d receive buffers full\n", state->ethernum);#ifdef sgi sginap( 1 ); /* free up CPU */#endif#ifdef sun sleep(1);#endif return -1; } fromaddrlen = sizeof(fromaddr); size = recvfrom(state->fd, buffer,SIMETHER_MAX_TRANSFER_SIZE, 0, (struct sockaddr *) &fromaddr, &fromaddrlen); if (size < 0) { if (errno != EWOULDBLOCK) perror("simetherRecvProcess:recvfrom"); } else if (size < sizeof(struct ether_header)) { Sim_Warning("simetherRecvProcess: Ethernet packet too small (%d)\n", size); } ASSERT( state->copy.rcvEntries[state->rcvPtr].flag == CONTROLLER_OWNED); packet = buffer; packetSize = size;#ifdef VCS_FAKE if(VcsFakeType == VCS_FAKE_SAVE) { /* save the received packet to the file */ write(vfd, VCS_FAKE_RMARKER, VCS_FAKE_MSIZE); write(vfd, &size, sizeof(size)); write(vfd, buffer, size); }#endif /*DMA the contents of the packet */ } else { if( state->copy.rcvEntries[state->rcvPtr].flag == OS_OWNED ) { CPUWarning("CLUSTER-packet: drop packet \n"); return -1; } ASSERT( packetSize ); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -