void abort_tx_frame(interface *i,void *frame){ const omphalos_ctx *octx = get_octx(); struct tpacket_hdr *thdr = frame; ++i->txaborts; thdr->tp_status = TP_STATUS_AVAILABLE; if(octx->mode != OMPHALOS_MODE_SILENT){ diagnostic("Aborted TX %ju on %s",i->txaborts,i->name); } }
// Mark a frame as ready-to-send. Must have come from get_tx_frame() using this // same interface. Yes, we will see packets we generate on the RX ring. int send_tx_frame(interface *i,void *frame){ const omphalos_ctx *octx = get_octx(); struct tpacket_hdr *thdr = frame; int ret = 0; assert(thdr->tp_status == TP_STATUS_PREPARING); if(octx->mode != OMPHALOS_MODE_SILENT){ int self,out; categorize_tx(i,(const char *)frame + thdr->tp_mac,&self,&out); if(self){ int r; r = send_to_self(i,frame); if(r < 0){ ++i->txerrors; }else{ i->txbytes += r; ++i->txframes; } ret |= r < 0 ? -1 : 0; } if(out){ uint32_t tplen = thdr->tp_len; int r; //thdr->tp_status = TP_STATUS_SEND_REQUEST; //r = send(i->fd,NULL,0,0); r = send(i->fd,(const char *)frame + thdr->tp_mac,tplen,0); if(r == 0){ r = tplen; } //diagnostic("Transmitted %d on %s",ret,i->name); if(r < 0){ diagnostic("Error out-TXing %u on %s (%s)",tplen,i->name,strerror(errno)); ++i->txerrors; }else{ i->txbytes += r; ++i->txframes; } ret |= r < 0 ? -1 : 0; } thdr->tp_status = TP_STATUS_AVAILABLE; }else{ abort_tx_frame(i,frame); ret = 0; } return ret; }
void observe_service(interface *i,struct l2host *l2,struct l3host *l3, unsigned proto,unsigned port, const wchar_t *srv,const wchar_t *srvver){ const omphalos_ctx *octx = get_octx(); l4srv *services,**prev,*cur; services = l3_getservices(l3); for(prev = &services ; (cur = *prev) ; prev = &cur->next){ if(cur->proto > proto){ break; }else if(cur->proto == proto){ if(cur->port > port){ break; }else if(cur->port == port){ int r; if((r = wcscmp(cur->srv,srv)) == 0){ return; }else if(r > 0){ break; } } } } if((cur = new_service(proto,port,srv,srvver)) == NULL){ return; } cur->next = *prev; *prev = cur; if(l3_setservices(l3,services)){ *prev = cur->next; free_service(cur); }else if(octx->iface.srv_event){ cur->opaque = octx->iface.srv_event(i,l2,l3,cur); } }
#include <omphalos/radiotap.h> #include <omphalos/interface.h> #define MAXINTERFACES (1u << 16) // lame FIXME // Master lock across interfaces[], used to lazily initialize interface objects static pthread_mutex_t iface_lock = PTHREAD_MUTEX_INITIALIZER; static int ifaces[MAXINTERFACES]; // 1 for initialized, else 0 static interface interfaces[MAXINTERFACES]; // FIXME what the hell to do here...? static void handle_void_packet(omphalos_packet *op,const void *frame __attribute__ ((unused)), size_t len __attribute__ ((unused))) { const struct omphalos_ctx *ctx = get_octx(); const omphalos_iface *octx = &ctx->iface; assert(op->i); if(octx->packet_read) { octx->packet_read(op); } } static int init_iface(interface *iface) { pthread_mutexattr_t attr; if(pthread_mutexattr_init(&attr)) { return -1; }
// -1: error; don't call us anymore. 0: handled frame. 1: interrupted; we // return for a cancellation check, and the frameptr oughtn't be advanced. The // interface lock must be held upon entry. int handle_ring_packet(interface *iface,int fd,void *frame){ const struct omphalos_ctx *ctx = get_octx(); const omphalos_iface *octx = &ctx->iface; struct tpacket_hdr *thdr = frame; omphalos_packet packet; int len; memset(&packet,0,sizeof(packet)); packet.i = iface; while(thdr->tp_status == 0){ struct pollfd pfd[1]; int events,msec; pfd[0].fd = fd; pfd[0].revents = 0; pfd[0].events = POLLIN | POLLRDNORM | POLLERR; msec = IFACE_TIMESTAT_USECS / 1000; pthread_mutex_unlock(&iface->lock); events = poll(pfd,sizeof(pfd) / sizeof(*pfd),msec); pthread_mutex_lock(&iface->lock); if(events == 0){ gettimeofday(&packet.tv,NULL); timestat_inc(&iface->fps,&packet.tv,0); timestat_inc(&iface->bps,&packet.tv,0); if(octx->packet_read){ octx->packet_read(&packet); } return 1; }else if(events < 0){ if(errno != EINTR){ diagnostic("Error in poll() on %s (%s?)", iface->name,strerror(errno)); return -1; } return 1; }else if(pfd[0].revents & POLLERR){ // FIXME don't want to print this every time a device // is removed from underneath us, but also don't want // to race against notification...check to see if // device is down here? FIXME //diagnostic("Error polling psocket %d on %s",fd,i->name); return -1; } } ++iface->frames; packet.tv.tv_sec = thdr->tp_sec; packet.tv.tv_usec = thdr->tp_usec; timestat_inc(&iface->fps,&packet.tv,1); if(thdr->tp_status & TP_STATUS_LOSING){ struct tpacket_stats tstats; socklen_t slen; // FIXME only call once for each burst of TP_STATUS_LOSING slen = sizeof(tstats); if(getsockopt(fd,SOL_PACKET,PACKET_STATISTICS,&tstats,&slen)){ diagnostic("Error reading stats on %s (%s?)",iface->name,strerror(errno)); }else if(tstats.tp_drops){ iface->drops += tstats.tp_drops; diagnostic("[%s] %u/%ju drops",iface->name,tstats.tp_drops,iface->drops); } } if((thdr->tp_status & TP_STATUS_COPY) || thdr->tp_snaplen != thdr->tp_len){ ++iface->truncated; if((len = recover_truncated_packet(iface,fd,thdr->tp_len)) <= 0){ diagnostic("Partial capture on %s (%u/%ub)", iface->name,thdr->tp_snaplen,thdr->tp_len); frame = (char *)frame + thdr->tp_mac; len = thdr->tp_snaplen; }else{ frame = iface->truncbuf; ++iface->truncated_recovered; len = thdr->tp_len; } }else{ frame = (char *)frame + thdr->tp_mac; len = thdr->tp_len; } timestat_inc(&iface->bps,&packet.tv,len); iface->bytes += len; iface->analyzer(&packet,frame,len); thdr->tp_status = TP_STATUS_KERNEL; // return the frame if(packet.l2s){ l2srcpkt(packet.l2s); } if(packet.l2d){ l2dstpkt(packet.l2d); } if(packet.l3s){ l3_srcpkt(packet.l3s); } if(packet.l3d){ l3_dstpkt(packet.l3d); } if(packet.malformed || packet.noproto){ if(packet.malformed){ ++iface->malformed; } if(packet.noproto){ ++iface->noprotocol; } if(packet.pcap_ethproto){ struct pcap_pkthdr pcap; size_t scribble = 0; struct pcap_ll pll; if(frame != iface->truncbuf){ scribble = thdr->tp_mac; frame -= thdr->tp_mac; }else{ scribble = 0; } pcap.caplen = pcap.len = len + scribble; pcap.ts = packet.tv; memset(&pll,0,sizeof(pll)); pll.arphrd = htons(packet.i->arptype); pll.llen = htons(packet.i->addrlen); if(packet.l2s){ hwaddrint hw = get_hwaddr(packet.l2s); memcpy(&pll.haddr,&hw,packet.i->addrlen > sizeof(pll.haddr) ? sizeof(pll.haddr) : packet.i->addrlen); // FIXME handle other pkttypes if(memcmp(&hw,packet.i->addr,packet.i->addrlen) == 0){ pll.pkttype = htons(4); } } pll.ethproto = htons(packet.pcap_ethproto); // 'frame' starts at the L2 header, *not* the tpacket_thdr log_pcap_packet(&pcap,frame,packet.i->l2hlen + scribble,&pll); if(scribble){ frame += thdr->tp_mac; } } } if(octx->packet_read){ octx->packet_read(&packet); } return 0; }