int packet_get_line(struct strbuf *out, char **src_buf, size_t *src_len) { int len; if (*src_len < 4) return -1; len = packet_length(*src_buf); if (len < 0) return -1; if (!len) { *src_buf += 4; *src_len -= 4; packet_trace("0000", 4, 0); return 0; } if (*src_len < len) return -2; *src_buf += 4; *src_len -= 4; len -= 4; strbuf_add(out, *src_buf, len); *src_buf += len; *src_len -= len; packet_trace(out->buf, out->len, 0); return len; }
int packet_read(int fd, char **src_buf, size_t *src_len, char *buffer, unsigned size, int options) { int len, ret; char linelen[4]; ret = get_packet_data(fd, src_buf, src_len, linelen, 4, options); if (ret < 0) return ret; len = packet_length(linelen); if (len < 0) die("protocol error: bad line length character: %.4s", linelen); if (!len) { packet_trace("0000", 4, 0); return 0; } len -= 4; if (len >= size) die("protocol error: bad line length %d", len); ret = get_packet_data(fd, src_buf, src_len, buffer, len, options); if (ret < 0) return ret; if ((options & PACKET_READ_CHOMP_NEWLINE) && len && buffer[len-1] == '\n') len--; buffer[len] = 0; packet_trace(buffer, len, 0); return len; }
int packet_flush_gently(int fd) { packet_trace("0000", 4, 1); if (write_in_full(fd, "0000", 4) == 4) return 0; return error("flush packet write failed"); }
int packet_read_line(int fd, char *buffer, unsigned size) { int len; char linelen[4]; safe_read(fd, linelen, 4); len = packet_length(linelen); if (len < 0) die("protocol error: bad line length character: %.4s", linelen); if (!len) { packet_trace("0000", 4, 0); return 0; } len -= 4; if (len >= size) die("protocol error: bad line length %d", len); safe_read(fd, buffer, len); buffer[len] = 0; packet_trace(buffer, len, 0); return len; }
/*************************************************************************** * wrapper for libpcap's sendpacket * * PORTABILITY: WINDOWS and PF_RING * For performance, Windows and PF_RING can queue up multiple packets, then * transmit them all in a chunk. If we stop and wait for a bit, we need * to flush the queue to force packets to be transmitted immediately. ***************************************************************************/ int rawsock_send_packet( struct Adapter *adapter, const unsigned char *packet, unsigned length, unsigned flush) { if (adapter == 0) return 0; /* Print --packet-trace if debugging */ if (adapter->is_packet_trace) { packet_trace(stdout, adapter->pt_start, packet, length, 1); } /* PF_RING */ if (adapter->ring) { int err = PF_RING_ERROR_NO_TX_SLOT_AVAILABLE; while (err == PF_RING_ERROR_NO_TX_SLOT_AVAILABLE) { err = PFRING.send(adapter->ring, packet, length, (unsigned char)flush); } if (err < 0) LOG(1, "pfring:xmit: ERROR %d\n", err); return err; } /* WINDOWS PCAP */ if (adapter->sendq) { int err; struct pcap_pkthdr hdr; hdr.len = length; hdr.caplen = length; err = pcap_sendqueue_queue(adapter->sendq, &hdr, packet); if (err) { rawsock_flush(adapter); pcap_sendqueue_queue(adapter->sendq, &hdr, packet); } if (flush) { rawsock_flush(adapter); } return 0; } /* LIBPCAP */ if (adapter->pcap) return pcap_sendpacket(adapter->pcap, packet, length); return 0; }
static void format_packet(struct strbuf *out, const char *fmt, va_list args) { size_t orig_len, n; orig_len = out->len; strbuf_addstr(out, "0000"); strbuf_vaddf(out, fmt, args); n = out->len - orig_len; if (n > LARGE_PACKET_MAX) die("protocol error: impossibly long line"); set_packet_header(&out->buf[orig_len], n); packet_trace(out->buf + orig_len + 4, n - 4, 1); }
static int packet_write_gently(const int fd_out, const char *buf, size_t size) { static char packet_write_buffer[LARGE_PACKET_MAX]; size_t packet_size; if (size > sizeof(packet_write_buffer) - 4) return error("packet write failed - data exceeds max packet size"); packet_trace(buf, size, 1); packet_size = size + 4; set_packet_header(packet_write_buffer, packet_size); memcpy(packet_write_buffer + 4, buf, size); if (write_in_full(fd_out, packet_write_buffer, packet_size) == packet_size) return 0; return error("packet write failed"); }
static unsigned format_packet(const char *fmt, va_list args) { static char hexchar[] = "0123456789abcdef"; unsigned n; n = vsnprintf(buffer + 4, sizeof(buffer) - 4, fmt, args); if (n >= sizeof(buffer)-4) die("protocol error: impossibly long line"); n += 4; buffer[0] = hex(n >> 12); buffer[1] = hex(n >> 8); buffer[2] = hex(n >> 4); buffer[3] = hex(n); packet_trace(buffer+4, n-4, 1); return n; }
static void CTCT_Write( DEVBLK* pDEVBLK, U32 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U32* pResidual ) { PCTCIHDR pFrame; // -> Frame header PCTCISEG pSegment; // -> Segment in buffer U16 sOffset; // Offset of next frame U16 sSegLen; // Current segment length U16 sDataLen; // Length of IP Frame data int iPos; // Offset into buffer U16 i; // Array subscript int rc; // Return code BYTE szStackID[33]; // VSE IP stack identity U32 iStackCmd; // VSE IP stack command // Check that CCW count is sufficient to contain block header if( sCount < sizeof( CTCIHDR ) ) { WRMSG(HHC00906, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, sCount ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Fix-up frame pointer pFrame = (PCTCIHDR)pIOBuf; // Extract the frame length from the header FETCH_HW( sOffset, pFrame->hwOffset ); // Check for special VSE TCP/IP stack command packet if( sOffset == 0 && sCount == 40 ) { // Extract the 32-byte stack identity string for( i = 0; i < sizeof( szStackID ) - 1 && i < sCount - 4; i++) szStackID[i] = guest_to_host( pIOBuf[i+4] ); szStackID[i] = '\0'; // Extract the stack command word FETCH_FW( iStackCmd, *((FWORD*)&pIOBuf[36]) ); // Display stack command and discard the packet WRMSG(HHC00907, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, szStackID, iStackCmd ); *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; return; } // Check for special L/390 initialization packet if( sOffset == 0 ) { // Return normal status and discard the packet *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; return; } #if 0 // Notes: It appears that TurboLinux has gotten sloppy in their // ways. They are now giving us buffer sizes that are // greater than the CCW count, but the segment size // is within the count. // Check that the frame offset is valid if( sOffset < sizeof( CTCIHDR ) || sOffset > sCount ) { logmsg( _("CTC101W %4.4X: Write buffer contains invalid " "frame offset %u\n"), pDEVBLK->devnum, sOffset ); pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } #endif // Adjust the residual byte count *pResidual -= sizeof( CTCIHDR ); // Process each segment in the buffer for( iPos = sizeof( CTCIHDR ); iPos < sOffset; iPos += sSegLen ) { // Check that the segment is fully contained within the block if( iPos + sizeof( CTCISEG ) > sOffset ) { WRMSG(HHC00908, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, iPos ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Fix-up segment header in the I/O buffer pSegment = (PCTCISEG)(pIOBuf + iPos); // Extract the segment length from the segment header FETCH_HW( sSegLen, pSegment->hwLength ); // Check that the segment length is valid if( ( sSegLen < sizeof( CTCISEG ) ) || ( (U32)iPos + sSegLen > sOffset ) || ( (U32)iPos + sSegLen > sCount ) ) { WRMSG(HHC00909, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, sSegLen, iPos ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Calculate length of IP frame data sDataLen = sSegLen - sizeof( CTCISEG ); // Trace the IP packet before sending if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) { WRMSG(HHC00934, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->filename ); if( pDEVBLK->ccwtrace ) packet_trace( pSegment->bData, sDataLen, '>' ); } // Write the IP packet rc = write_socket( pDEVBLK->fd, pSegment->bData, sDataLen ); if( rc < 0 ) { WRMSG(HHC00936, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->filename, strerror( HSO_errno ) ); pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Adjust the residual byte count *pResidual -= sSegLen; // We are done if current segment satisfies CCW count if( (U32)iPos + sSegLen == sCount ) { *pResidual -= sSegLen; *pUnitStat = CSW_CE | CSW_DE; return; } } // Set unit status and residual byte count *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; }
/* * If we buffered things up above (we don't, but we should), * we'd flush it here */ void packet_flush(int fd) { packet_trace("0000", 4, 1); write_or_die(fd, "0000", 4); }
void CTCI_Write( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual ) { PCTCBLK pCTCBLK = (PCTCBLK)pDEVBLK->dev_data; PCTCIHDR pFrame; // -> Frame header PCTCISEG pSegment; // -> Segment in buffer U16 sOffset; // Offset of next frame U16 sSegLen; // Current segment length U16 sDataLen; // Length of IP Frame data int iPos; // Offset into buffer U16 i; // Array subscript int rc; // Return code BYTE szStackID[33]; // VSE IP stack identity U32 iStackCmd; // VSE IP stack command // Check that CCW count is sufficient to contain block header if( sCount < sizeof( CTCIHDR ) ) { logmsg( _("HHCCT042E %4.4X: Write CCW count %u is invalid\n"), pDEVBLK->devnum, sCount ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Fix-up frame pointer pFrame = (PCTCIHDR)pIOBuf; // Extract the frame length from the header FETCH_HW( sOffset, pFrame->hwOffset ); // Check for special VSE TCP/IP stack command packet if( sOffset == 0 && sCount == 40 ) { // Extract the 32-byte stack identity string for( i = 0; i < sizeof( szStackID ) - 1 && i < sCount - 4; i++) szStackID[i] = guest_to_host( pIOBuf[i+4] ); szStackID[i] = '\0'; // Extract the stack command word FETCH_FW( iStackCmd, *((FWORD*)&pIOBuf[36]) ); // Display stack command and discard the packet logmsg( _("HHCCT043I %4.4X: Interface command: %s %8.8X\n"), pDEVBLK->devnum, szStackID, iStackCmd ); *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; return; } // Check for special L/390 initialization packet if( sOffset == 0 ) { // Return normal status and discard the packet *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; return; } #if 0 // Notes: It appears that TurboLinux has gotten sloppy in their // ways. They are now giving us buffer sizes that are // greater than the CCW count, but the segment size // is within the count. // Check that the frame offset is valid if( sOffset < sizeof( CTCIHDR ) || sOffset > sCount ) { logmsg( _("CTC101W %4.4X: Write buffer contains invalid " "frame offset %u\n"), pDEVBLK->devnum, sOffset ); pDEVBLK->sense[0] = SENSE_CR; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } #endif // Adjust the residual byte count *pResidual -= sizeof( CTCIHDR ); // Process each segment in the buffer for( iPos = sizeof( CTCIHDR ); iPos < sOffset; iPos += sSegLen ) { // Check that the segment is fully contained within the block if( iPos + sizeof( CTCISEG ) > sOffset ) { logmsg( _("HHCCT044E %4.4X: Write buffer contains incomplete " "segment header at offset %4.4X\n"), pDEVBLK->devnum, iPos ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Fix-up segment header in the I/O buffer pSegment = (PCTCISEG)(pIOBuf + iPos); // Extract the segment length from the segment header FETCH_HW( sSegLen, pSegment->hwLength ); // Check that the segment length is valid if( ( sSegLen < sizeof( CTCISEG ) ) || ( iPos + sSegLen > sOffset ) || ( iPos + sSegLen > sCount ) ) { logmsg( _("HHCCT045E %4.4X: Write buffer contains invalid " "segment length %u at offset %4.4X\n"), pDEVBLK->devnum, sSegLen, iPos ); pDEVBLK->sense[0] = SENSE_DC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Calculate length of IP frame data sDataLen = sSegLen - sizeof( CTCISEG ); // Trace the IP packet before sending to TUN device if( pCTCBLK->fDebug ) { logmsg( _("HHCCT046I %4.4X: Sending packet to %s:\n"), pDEVBLK->devnum, pCTCBLK->szTUNDevName ); packet_trace( pSegment->bData, sDataLen ); } // Write the IP packet to the TUN/TAP interface rc = TUNTAP_Write( pCTCBLK->fd, pSegment->bData, sDataLen ); if( rc < 0 ) { logmsg( _("HHCCT047E %4.4X: Error writing to %s: rc=%d errno=%d %s\n"), pDEVBLK->devnum, pCTCBLK->szTUNDevName, rc, errno, strerror(errno)); } /* Kludge for Ubuntu 10.04 by Martin Truebner */ if (rc == -1 && errno == 22) rc = 0; if (rc < 0) { pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Adjust the residual byte count *pResidual -= sSegLen; // We are done if current segment satisfies CCW count if( iPos + sSegLen == sCount ) { *pResidual -= sSegLen; *pUnitStat = CSW_CE | CSW_DE; return; } } // Set unit status and residual byte count *pUnitStat = CSW_CE | CSW_DE; *pResidual = 0; }
/*************************************************************************** * wrapper for libpcap's sendpacket * * PORTABILITY: WINDOWS and PF_RING * For performance, Windows and PF_RING can queue up multiple packets, then * transmit them all in a chunk. If we stop and wait for a bit, we need * to flush the queue to force packets to be transmitted immediately. ***************************************************************************/ int rawsock_send_packet( struct Adapter *adapter, const unsigned char *packet, unsigned length, unsigned flush) { if (adapter == 0) return 0; /* Print --packet-trace if debugging */ if (adapter->is_packet_trace) { packet_trace(stdout, packet, length, 1); } /* PF_RING */ if (adapter->ring) { int err = PF_RING_ERROR_NO_TX_SLOT_AVAILABLE; while (err == PF_RING_ERROR_NO_TX_SLOT_AVAILABLE) { err = PFRING.send(adapter->ring, packet, length, (unsigned char)flush); } if (err < 0) LOG(1, "pfring:xmit: ERROR %d\n", err); return err; } /* WINDOWS PCAP */ if (adapter->sendq) { int err; struct pcap_pkthdr hdr; hdr.len = length; hdr.caplen = length; err = pcap_sendqueue_queue(adapter->sendq, &hdr, packet); if (err) { //printf("sendpacket() failed %d\n", x); //for (;;) pcap_sendqueue_transmit(adapter->pcap, adapter->sendq, 0); //printf("pcap_send_queue)() returned %u\n", x); pcap_sendqueue_destroy(adapter->sendq); adapter->sendq = pcap_sendqueue_alloc(SENDQ_SIZE); pcap_sendqueue_queue(adapter->sendq, &hdr, packet); //("sendpacket() returned %d\n", x); //exit(1); } else ; //printf("+%u\n", count++); if (flush) { pcap_sendqueue_transmit(adapter->pcap, adapter->sendq, 0); /* Dude, I totally forget why this step is necessary. I vaguely * remember there's a good reason for it though */ pcap_sendqueue_destroy(adapter->sendq); adapter->sendq = pcap_sendqueue_alloc(SENDQ_SIZE); } return 0; } /* LIBPCAP */ if (adapter->pcap) return pcap_sendpacket(adapter->pcap, packet, length); return 0; }
/* * If we buffered things up above (we don't, but we should), * we'd flush it here */ void packet_flush(int fd) { packet_trace("0000", 4, 1); safe_write(fd, "0000", 4); }
/*************************************************************************** * * Asynchronous receive thread * * The transmit and receive threads run independently of each other. There * is no record what was transmitted. Instead, the transmit thread sets a * "SYN-cookie" in transmitted packets, which the receive thread will then * use to match up requests with responses. ***************************************************************************/ static void receive_thread(void *v) { struct ThreadPair *parms = (struct ThreadPair *)v; const struct Masscan *masscan = parms->masscan; struct Output *out; struct DedupTable *dedup; struct PcapFile *pcapfile = NULL; struct TCP_ConnectionTable *tcpcon = 0; LOG(1, "recv: start receive thread #%u\n", parms->nic_index); /* Lock this thread to a CPU. Transmit threads are on even CPUs, * receive threads on odd CPUs */ if (pixie_cpu_get_count() > 1) { unsigned cpu_count = pixie_cpu_get_count(); unsigned cpu = parms->nic_index * 2 + 1; while (cpu >= cpu_count) { cpu -= cpu_count; cpu++; } pixie_cpu_set_affinity(cpu); } /* * If configured, open a --pcap file for saving raw packets. This is * so that we can debug scans, but also so that we can look at the * strange things people send us. Note that we don't record transmitted * packets, just the packets we've received. */ /*if (masscan->pcap_filename[0]) pcapfile = pcapfile_openwrite(masscan->pcap_filename, 1);*/ /* * Open output. This is where results are reported when saving * the --output-format to the --output-filename */ out = output_create(masscan); /* * Create deduplication table. This is so when somebody sends us * multiple responses, we only record the first one. */ dedup = dedup_create(); /* * Create a TCP connection table for interacting with live * connections when doing --banners */ if (masscan->is_banners) { tcpcon = tcpcon_create_table( (size_t)((masscan->max_rate/5) / masscan->nic_count), parms->transmit_queue, parms->packet_buffers, &parms->tmplset->pkts[Proto_TCP], output_report_banner, out, masscan->tcb.timeout ); if (masscan->http_user_agent_length) tcpcon_set_parameter( tcpcon, "http-user-agent", masscan->http_user_agent_length, masscan->http_user_agent); } /* * In "offline" mode, we don't have any receive threads, so simply * wait until transmitter thread is done then go to the end */ if (masscan->is_offline) { while (!control_c_pressed_again) pixie_usleep(10000); parms->done_receiving = 1; goto end; } /* * Receive packets. This is where we catch any responses and print * them to the terminal. */ LOG(1, "begin receive thread\n"); while (!control_c_pressed_again) { int status; unsigned length; unsigned secs; unsigned usecs; const unsigned char *px; int err; unsigned x; struct PreprocessedInfo parsed; unsigned ip_me; unsigned port_me; unsigned ip_them; unsigned port_them; unsigned seqno_me; unsigned seqno_them; unsigned cookie; /* * RECIEVE * * This is the boring part of actually receiving a packet */ err = rawsock_recv_packet( parms->adapter, &length, &secs, &usecs, &px); if (err != 0) continue; /* * Do any TCP event timeouts based on the current timestamp from * the packet. For example, if the connection has been open for * around 10 seconds, we'll close the connection. (--banners) */ if (tcpcon) { tcpcon_timeouts(tcpcon, secs, usecs); } if (length > 1514) continue; /* * "Preprocess" the response packet. This means to go through and * figure out where the TCP/IP headers are and the locations of * some fields, like IP address and port numbers. */ x = preprocess_frame(px, length, 1, &parsed); if (!x) continue; /* corrupt packet */ ip_me = parsed.ip_dst[0]<<24 | parsed.ip_dst[1]<<16 | parsed.ip_dst[2]<< 8 | parsed.ip_dst[3]<<0; ip_them = parsed.ip_src[0]<<24 | parsed.ip_src[1]<<16 | parsed.ip_src[2]<< 8 | parsed.ip_src[3]<<0; port_me = parsed.port_dst; port_them = parsed.port_src; seqno_them = TCP_SEQNO(px, parsed.transport_offset); seqno_me = TCP_ACKNO(px, parsed.transport_offset); cookie = syn_cookie(ip_them, port_them, ip_me, port_me) & 0xFFFFFFFF; /* verify: my IP address */ if (!is_my_ip(&parms->src, ip_me)) continue; /* * Handle non-TCP protocols */ switch (parsed.found) { case FOUND_ARP: LOGip(2, ip_them, 0, "-> ARP [%u] \n", px[parsed.found_offset]); switch (px[parsed.found_offset + 6]<<8 | px[parsed.found_offset+7]) { case 1: /* request */ /* This function will transmit a "reply" to somebody's ARP request * for our IP address (as part of our user-mode TCP/IP). * Since we completely bypass the TCP/IP stack, we have to handle ARPs * ourself, or the router will lose track of us.*/ arp_response( ip_me, parms->adapter_mac, px, length, parms->packet_buffers, parms->transmit_queue); break; case 2: /* response */ /* This is for "arp scan" mode, where we are ARPing targets rather * than port scanning them */ /* If we aren't doing an ARP scan, then ignore ARP responses */ if (!masscan->is_arp) break; /* If this response isn't in our range, then ignore it */ if (!rangelist_is_contains(&masscan->targets, ip_them)) break; /* Ignore duplicates */ if (dedup_is_duplicate(dedup, ip_them, 0)) continue; /* ...everything good, so now report this response */ handle_arp(out, px, length, &parsed); break; } continue; case FOUND_UDP: case FOUND_DNS: if (!is_nic_port(masscan, port_me)) continue; if (parms->masscan->nmap.packet_trace) packet_trace(stdout, px, length, 0); handle_udp(out, px, length, &parsed); continue; case FOUND_ICMP: handle_icmp(out, px, length, &parsed); continue; case FOUND_TCP: /* fall down to below */ break; default: continue; } /* verify: my port number */ if (!is_my_port(&parms->src, port_me)) continue; if (parms->masscan->nmap.packet_trace) packet_trace(stdout, px, length, 0); /* Save raw packet in --pcap file */ if (pcapfile) { pcapfile_writeframe( pcapfile, px, length, length, secs, usecs); } { char buf[64]; LOGip(5, ip_them, port_them, "-> TCP ackno=0x%08x flags=0x%02x(%s)\n", seqno_me, TCP_FLAGS(px, parsed.transport_offset), reason_string(TCP_FLAGS(px, parsed.transport_offset), buf, sizeof(buf))); } /* If recording --banners, create a new "TCP Control Block (TCB)" */ if (tcpcon) { struct TCP_Control_Block *tcb; /* does a TCB already exist for this connection? */ tcb = tcpcon_lookup_tcb(tcpcon, ip_me, ip_them, port_me, port_them); if (TCP_IS_SYNACK(px, parsed.transport_offset)) { if (cookie != seqno_me - 1) { LOG(2, "%u.%u.%u.%u - bad cookie: ackno=0x%08x expected=0x%08x\n", (ip_them>>24)&0xff, (ip_them>>16)&0xff, (ip_them>>8)&0xff, (ip_them>>0)&0xff, seqno_me-1, cookie); continue; } if (tcb == NULL) { tcb = tcpcon_create_tcb(tcpcon, ip_me, ip_them, port_me, port_them, seqno_me, seqno_them+1); } tcpcon_handle(tcpcon, tcb, TCP_WHAT_SYNACK, 0, 0, secs, usecs, seqno_them+1); } else if (tcb) { /* If this is an ACK, then handle that first */ if (TCP_IS_ACK(px, parsed.transport_offset)) { tcpcon_handle(tcpcon, tcb, TCP_WHAT_ACK, 0, seqno_me, secs, usecs, seqno_them); } /* If this contains payload, handle that */ if (parsed.app_length) { tcpcon_handle(tcpcon, tcb, TCP_WHAT_DATA, px + parsed.app_offset, parsed.app_length, secs, usecs, seqno_them); } /* If this is a FIN, handle that. Note that ACK + * payload + FIN can come together */ if (TCP_IS_FIN(px, parsed.transport_offset) && !TCP_IS_RST(px, parsed.transport_offset)) { tcpcon_handle(tcpcon, tcb, TCP_WHAT_FIN, 0, 0, secs, usecs, seqno_them); } /* If this is a RST, then we'll be closing the connection */ if (TCP_IS_RST(px, parsed.transport_offset)) { tcpcon_handle(tcpcon, tcb, TCP_WHAT_RST, 0, 0, secs, usecs, seqno_them); } } else if (TCP_IS_FIN(px, parsed.transport_offset)) { /* * NO TCB! * This happens when we've sent a FIN, deleted our connection, * but the other side didn't get the packet. */ if (!TCP_IS_RST(px, parsed.transport_offset)) tcpcon_send_FIN( tcpcon, ip_me, ip_them, port_me, port_them, seqno_them, seqno_me); } }
static void* CTCI_ReadThread( PCTCBLK pCTCBLK ) { DEVBLK* pDEVBLK = pCTCBLK->pDEVBLK[0]; int iLength; BYTE szBuff[2048]; // ZZ FIXME: Try to avoid race condition at startup with hercifc SLEEP(10); pCTCBLK->pid = getpid(); while( pCTCBLK->fd != -1 && !pCTCBLK->fCloseInProgress ) { // Read frame from the TUN/TAP interface iLength = TUNTAP_Read( pCTCBLK->fd, szBuff, sizeof(szBuff) ); // Check for error condition if( iLength < 0 ) { logmsg( _("HHCCT048E %4.4X: Error reading from %s: %s\n"), pDEVBLK->devnum, pCTCBLK->szTUNDevName, strerror( errno ) ); SLEEP(1); // (purposeful long delay) continue; } if( iLength == 0 ) // (probably EINTR; ignore) continue; if( pCTCBLK->fDebug ) { logmsg( _("HHCCT049I %4.4X: Received packet from %s (%d bytes):\n"), pDEVBLK->devnum, pCTCBLK->szTUNDevName, iLength ); packet_trace( szBuff, iLength ); } // Enqueue frame on buffer, if buffer is full, keep trying while( CTCI_EnqueueIPFrame( pDEVBLK, szBuff, iLength ) < 0 && pCTCBLK->fd != -1 && !pCTCBLK->fCloseInProgress ) { if( EMSGSIZE == errno ) // (if too large for buffer) { if( pCTCBLK->fDebug ) logmsg( _("HHCCT072W %4.4X: Packet too big; dropped.\n"), pDEVBLK->devnum ); break; // (discard it...) } ASSERT( ENOBUFS == errno ); // Don't use sched_yield() here; use an actual non-dispatchable // delay instead so as to allow another [possibly lower priority] // thread to 'read' (remove) some packet(s) from our frame buffer. usleep( CTC_DELAY_USECS ); // (wait a bit before retrying...) } } // We must do the close since we were the one doing the i/o... VERIFY( pCTCBLK->fd == -1 || TUNTAP_Close( pCTCBLK->fd ) == 0 ); pCTCBLK->fd = -1; return NULL; }
static void CTCT_Read( DEVBLK* pDEVBLK, U32 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U32* pResidual, BYTE* pMore ) { PCTCIHDR pFrame = NULL; // -> Frame header PCTCISEG pSegment = NULL; // -> Segment in buffer fd_set rfds; // Read FD_SET int iRetVal; // Return code from 'select' int iLength = 0; static struct timeval tv; // Timeout time for 'select' // Limit how long we should wait for data to come in FD_ZERO( &rfds ); FD_SET( pDEVBLK->fd, &rfds ); tv.tv_sec = CTC_READ_TIMEOUT_SECS; tv.tv_usec = 0; iRetVal = select( pDEVBLK->fd + 1, &rfds, NULL, NULL, &tv ); switch( iRetVal ) { case 0: *pUnitStat = CSW_CE | CSW_DE | CSW_UC | CSW_SM; pDEVBLK->sense[0] = 0; return; case -1: if( HSO_errno == HSO_EINTR ) return; WRMSG(HHC00973, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->filename, strerror( HSO_errno ) ); pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; default: break; } // Read an IP packet from the TUN device iLength = read_socket( pDEVBLK->fd, pDEVBLK->buf, pDEVBLK->bufsize ); // Check for other error condition if( iLength < 0 ) { WRMSG(HHC00973, "E", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, pDEVBLK->filename, strerror( HSO_errno ) ); pDEVBLK->sense[0] = SENSE_EC; *pUnitStat = CSW_CE | CSW_DE | CSW_UC; return; } // Trace the packet received from the TUN device if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) { WRMSG(HHC00913, "I", SSID_TO_LCSS(pDEVBLK->ssid), pDEVBLK->devnum, iLength, "TUN" ); packet_trace( pDEVBLK->buf, iLength, '<' ); } // Fix-up Frame pointer pFrame = (PCTCIHDR)pIOBuf; // Fix-up Segment pointer pSegment = (PCTCISEG)( pIOBuf + sizeof( CTCIHDR ) ); // Initialize segment memset( pSegment, 0, iLength + sizeof( CTCISEG ) ); // Update next frame offset STORE_HW( pFrame->hwOffset, (U16)(iLength + sizeof( CTCIHDR ) + sizeof( CTCISEG )) ); // Store segment length STORE_HW( pSegment->hwLength, (U16)(iLength + sizeof( CTCISEG )) ); // Store Frame type STORE_HW( pSegment->hwType, ETH_TYPE_IP ); // Copy data memcpy( pSegment->bData, pDEVBLK->buf, iLength ); // Fix-up frame pointer and terminate block pFrame = (PCTCIHDR)( pIOBuf + sizeof( CTCIHDR ) + sizeof( CTCISEG ) + iLength ); STORE_HW( pFrame->hwOffset, 0x0000 ); // Calculate #of bytes returned including two slack bytes iLength += sizeof( CTCIHDR ) + sizeof( CTCISEG ) + 2; if( sCount < (U32)iLength ) { *pMore = 1; *pResidual = 0; iLength = sCount; } else { *pMore = 0; *pResidual -= iLength; } // Set unit status *pUnitStat = CSW_CE | CSW_DE; }
void packet_buf_flush(struct strbuf *buf) { packet_trace("0000", 4, 1); strbuf_add(buf, "0000", 4); }
void CTCI_Read( DEVBLK* pDEVBLK, U16 sCount, BYTE* pIOBuf, BYTE* pUnitStat, U16* pResidual, BYTE* pMore ) { PCTCBLK pCTCBLK = (PCTCBLK)pDEVBLK->dev_data; PCTCIHDR pFrame = NULL; size_t iLength = 0; int rc = 0; for ( ; ; ) { obtain_lock( &pCTCBLK->Lock ); if( !pCTCBLK->fDataPending ) { struct timespec waittime; struct timeval now; release_lock( &pCTCBLK->Lock ); gettimeofday( &now, NULL ); waittime.tv_sec = now.tv_sec + CTC_READ_TIMEOUT_SECS; waittime.tv_nsec = now.tv_usec * 1000; obtain_lock( &pCTCBLK->EventLock ); rc = timed_wait_condition( &pCTCBLK->Event, &pCTCBLK->EventLock, &waittime ); release_lock( &pCTCBLK->EventLock ); if( rc == ETIMEDOUT || rc == EINTR ) { // check for halt condition if( pDEVBLK->scsw.flag2 & SCSW2_FC_HALT || pDEVBLK->scsw.flag2 & SCSW2_FC_CLEAR ) { if( pDEVBLK->ccwtrace || pDEVBLK->ccwstep ) logmsg( _("HHCCT040I %4.4X: Halt or Clear Recognized\n"), pDEVBLK->devnum ); *pUnitStat = CSW_CE | CSW_DE; *pResidual = sCount; return; } continue; } obtain_lock( &pCTCBLK->Lock ); } // Sanity check if( pCTCBLK->iFrameOffset == 0 ) { release_lock( &pCTCBLK->Lock ); continue; } // Fix-up frame pointer and terminate block pFrame = (PCTCIHDR)( pCTCBLK->bFrameBuffer + sizeof( CTCIHDR ) + pCTCBLK->iFrameOffset ); STORE_HW( pFrame->hwOffset, 0x0000 ); // (fix for day-1 bug offered by Vince Weaver [[email protected]]) // iLength = pCTCBLK->iFrameOffset + sizeof( CTCIHDR ) + 2; iLength = pCTCBLK->iFrameOffset + sizeof( CTCIHDR ); if( sCount < iLength ) { *pMore = 1; *pResidual = 0; iLength = sCount; } else { *pMore = 0; *pResidual -= iLength; } *pUnitStat = CSW_CE | CSW_DE; memcpy( pIOBuf, pCTCBLK->bFrameBuffer, iLength ); if( pCTCBLK->fDebug ) { logmsg( _("HHCCT041I %4.4X: CTC Received Frame (%d bytes):\n"), pDEVBLK->devnum, iLength ); packet_trace( pCTCBLK->bFrameBuffer, iLength ); } // Reset frame buffer pCTCBLK->iFrameOffset = 0; pCTCBLK->fDataPending = 0; release_lock( &pCTCBLK->Lock ); return; } }