int pkt_release (void) { ADAPTER *adapter; DWORD status = 1; if (!_pkt_inf || _watt_fatal_error) return (0); adapter = (ADAPTER*) _pkt_inf->adapter; TCP_CONSOLE_MSG (2, ("pkt_release(): adapter %08lX\n", (DWORD)adapter)); if (adapter && adapter != INVALID_HANDLE_VALUE) { /* Don't close the adapter before telling the thread about it. */ if (_pkt_inf->recv_thread) { FILETIME ctime, etime, ktime, utime; DWORD err = 0; _pkt_inf->stop_thread = TRUE; SetEvent (adapter->ReadEvent); Sleep (50); GetExitCodeThread (_pkt_inf->recv_thread, &status); if (status == STILL_ACTIVE) TCP_CONSOLE_MSG (2, ("pkt_release(): killing thread.\n")); else TCP_CONSOLE_MSG (2, ("pkt_release(): thread exit code %lu.\n", status)); if (!GetThreadTimes (_pkt_inf->recv_thread, &ctime, &etime, &ktime, &utime)) err = GetLastError(); TerminateThread (_pkt_inf->recv_thread, 1); CloseHandle (_pkt_inf->recv_thread); if (err) TCP_CONSOLE_MSG (2, (" GetThreadTime() %s, ", win_strerror(err))); TCP_CONSOLE_MSG (2, (" kernel time %.6fs, user time %.6fs\n", filetime_sec(&ktime), filetime_sec(&utime))); } PacketCloseAdapter (adapter); _pkt_inf->adapter = NULL; } DO_FREE (_pkt_inf->npf_buf); DO_FREE (_pkt_inf); PacketInitModule (FALSE, dump_file); if (dump_file) fclose (dump_file); dump_file = NULL; return (int) status; }
/* * Sets the receive mode of the interface. */ int pkt_set_rcv_mode (int mode) { struct { PACKET_OID_DATA oidData; DWORD filter; } oid; BOOL rc; const ADAPTER *adapter; if (!_pkt_inf) return (0); adapter = (const ADAPTER*) _pkt_inf->adapter; memset (&oid, 0, sizeof(oid)); oid.oidData.Oid = OID_GEN_CURRENT_PACKET_FILTER; oid.oidData.Length = sizeof(oid.filter); *(DWORD*)oid.oidData.Data = mode; rc = PacketRequest (adapter, TRUE, &oid.oidData); if (rc) _pkt_rxmode = mode; else _pkt_errno = GetLastError(); TCP_CONSOLE_MSG (2, ("pkt_set_rcv_mode(); mode 0x%02X, rc %d; %s\n", mode, rc, !rc ? win_strerror(GetLastError()) : "okay")); return (rc); }
/* * NDIS has the annoying feature (?) of looping packets we send in * NDIS_PACKET_TYPE_ALL_LOCAL mode (the default?). Disable it, but * doesn't seem to have any effect yet. Maybe need to use a BPF filter? * * No need when using RXMODE_DEFAULT (9). */ static BOOL ndis_set_loopback (BOOL enable) { struct { PACKET_OID_DATA oidData; DWORD options; } oid; const ADAPTER *adapter; BOOL rc; DWORD options; DWORD gen_oid = OID_GEN_MAC_OPTIONS; DWORD opt_bit = NDIS_MAC_OPTION_NO_LOOPBACK; if (!_pkt_inf) return (FALSE); adapter = (const ADAPTER*) _pkt_inf->adapter; memset (&oid, 0, sizeof(oid)); oid.oidData.Oid = gen_oid; oid.oidData.Length = sizeof(oid.options); /* Get current MAC/protocol options */ rc = PacketRequest (adapter, FALSE, &oid.oidData); options = *(DWORD*) &oid.oidData.Data; TCP_CONSOLE_MSG (2, ("ndis_set_loopback(); rc %d, options 0x%02lX; %s\n", rc, options, !rc ? win_strerror(GetLastError()) : "okay")); if (enable) options &= ~opt_bit; else options |= opt_bit; /* Set it back */ memset (&oid, 0, sizeof(oid)); oid.oidData.Oid = gen_oid; oid.oidData.Length = sizeof(oid.options); *(DWORD*) &oid.oidData.Data = options; rc = PacketRequest (adapter, TRUE, &oid.oidData); TCP_CONSOLE_MSG (2, ("ndis_set_loopback(); rc %d; %s\n", rc, !rc ? win_strerror(GetLastError()) : "okay")); return (rc); }
/* * Return the MAC address. */ int pkt_get_addr (mac_address *eth) { mac_address mac; if (get_perm_mac_address(&mac)) { memcpy (eth, &mac, sizeof(*eth)); return (1); } TCP_CONSOLE_MSG (2, ("Failed to get our MAC address; %s\n", win_strerror(GetLastError()))); return (0); }
struct pkt_rx_element *pkt_poll_recv (void) { struct pkt_rx_element *rc; WORD out_idx = PEEKW (0, QUE_OFS(out_index)); WORD in_idx = PEEKW (0, QUE_OFS(in_index)); if (out_idx != in_idx) { static struct pkt_rx_element rx_buf; struct pkt_ringbuf *q = &_pkt_inf->pkt_queue; DWORD addr = ASMPKT_INF + offsetof(PKT_INFO,rx_buf[out_idx]); /* It might be faster to copy whole thing (head and rx-buffer) * in one operation ?? */ pullup_rx_element (&rx_buf, addr, RX_ELEMENT_HEAD_SIZE); if (check_rx_element(&rx_buf)) { BYTE *pad; int pad_len, size; get_tstamp (rx_buf.tstamp_get); size = min (rx_buf.rx_length_1, q->buf_size - 4 - RX_ELEMENT_HEAD_SIZE); pad_len = q->buf_size - 4 - RX_ELEMENT_HEAD_SIZE - size; addr += RX_ELEMENT_HEAD_SIZE; pullup_rx_element (&rx_buf.rx_buf, addr, ROUND_UP32(size)); if (pad_len > 0) { pad = &rx_buf.rx_buf[0] + size; memset (pad, 0, pad_len); } rc = &rx_buf; } else { TCP_CONSOLE_MSG (1, ("pkt-error %s\n", pkt_error)); rc = NULL; } if (++out_idx >= q->num_buf) out_idx = 0; POKEW (0, QUE_OFS(out_index), out_idx); return (rc); } return (NULL); }
/* * Get hostname excluding domain-name */ int _get_machine_name (char *buf, int size) { int rc; DWORD sz = size; HMODULE mod = GetModuleHandle ("KERNEL32.DLL"); BOOL (WINAPI *_GetComputerNameExA) (int, char*, DWORD*) = NULL; typedef BOOL (WINAPI *gcn_ex) (int, char*, DWORD*); if (mod) _GetComputerNameExA = (gcn_ex) GetProcAddress (mod, "GetComputerNameExA"); if (!_GetComputerNameExA) rc = GetComputerNameA (buf, &sz); else rc = (*_GetComputerNameExA) (ComputerNameDnsHostname, buf, &sz); rc = rc ? 0 : -1; TCP_CONSOLE_MSG (2, ("_get_machine_name(): \"%s\", rc %d\n", buf, rc)); return (rc); }
/* * This functiom is called once each second. */ static void check_dead_gw (void) { char buf[20]; static int i = 0; if (i >= gate_top) i = 0; for ( ; i < gate_top; i++) { struct gate_entry *gw = &gate_list [i]; eth_address eth; if (!is_on_LAN(gw->gate_ip)) continue; if (!LAN_lookup(gw->gate_ip,ð)) continue; if (gw->chk_timer == 0UL || !chk_timeout(gw->chk_timer)) { gw->chk_timer = set_timeout (DEAD_GW_TIMEOUT); continue; } if (gw->echo_pending && _chk_ping(gw->gate_ip,NULL) == (DWORD)-1) { gw->is_dead = TRUE; gw->echo_pending = FALSE; TCP_CONSOLE_MSG (1, ("Dead default GW %s (%d) detected\n", _inet_ntoa(NULL,gw->gate_ip), i)); } if (ping_gateway (gw->gate_ip, eth)) gw->echo_pending = TRUE; gw->chk_timer = set_timeout (DEAD_GW_TIMEOUT); return; /* only one ping per interval */ } }
void pkt_free_pkt (const void *pkt) { struct pkt_ringbuf *q; const char *q_tail; int delta; if (!_pkt_inf || !pkt) return; q = &_pkt_inf->pkt_queue; pkt_drop_cnt = q->num_drop; q_tail = (const char*)pkt - _pkt_ip_ofs - RX_ELEMENT_HEAD_SIZE; delta = q_tail - pktq_out_buf (q); if (delta) { TCP_CONSOLE_MSG (0, ("%s: freeing illegal packet 0x%p, delta %d.\n", __FILE__, pkt, delta)); pktq_clear (q); } else pktq_inc_out (q); }
/* * Called from setup_pkt_inf() in pcpkt.c */ static DWORD setup_pkt_inf_fast (void) { /* Allocate space for asmpkt_inf, temp area, pkt-stub and Tx buffer. */ DWORD rdata_size = PKT_TMP(); size_t stub_size = sizeof(real_stub_array); #if (DOSX) rdata_size += PKT_TMP_SIZE + ETH_MAX + 10; #endif if (rdata_size >= 64*1024UL) { TCP_CONSOLE_MSG (0, ("%s (%u): Development error:\nsize %u too large\n", __FILE__, __LINE__, (unsigned int)rdata_size)); return (0); } if (stub_size < 0xC0) { TCP_CONSOLE_MSG (0, ("%s (%u): Development error:\n\"pkt_stub.h\"" " seems truncated (%d bytes)\n", __FILE__, __LINE__, SIZEOF(real_stub_array))); return (0); } #if (DOSX & DJGPP) { int i, seg, sel; seg = __dpmi_allocate_dos_memory ((rdata_size+15)/16, &sel); if (seg < 0) return (0); _pkt_inf->rm_seg = seg; _pkt_inf->rm_sel = sel; rm_base = (_pkt_inf->rm_seg << 4); for (i = 0; i < (int)rdata_size; i += 4) /* clear area */ POKEL (_pkt_inf->rm_seg, i, 0); } #elif (DOSX & DOS4GW) { WORD seg, sel; seg = dpmi_real_malloc (rdata_size, &sel); if (!seg) return (0); _pkt_inf->rm_seg = seg; _pkt_inf->rm_sel = sel; rm_base = (_pkt_inf->rm_seg) << 4; memset ((void*)rm_base, 0, rdata_size); } #elif (DOSX & PHARLAP) { WORD largest, seg; int i; if (_dx_real_alloc ((rdata_size+15)/16, &seg, &largest) != 0) return (0); _pkt_inf->rm_seg = seg; _pkt_inf->rm_sel = 0; RP_SET (rm_base, 0, _pkt_inf->rm_seg); for (i = 0; i < (int)rdata_size; i += 4) POKEL (_pkt_inf->rm_seg, i, 0); } #elif (DOSX & X32VM) { int i; rm_base = _x32_real_alloc (rdata_size); if (!rm_base) return (0); _pkt_inf->rm_seg = _x32_real_segment (rm_base); _pkt_inf->rm_sel = 0; for (i = 0; i < (int)rdata_size; i += 4) POKEL (_pkt_inf->rm_seg, i, 0); } #elif (DOSX & POWERPAK) { WORD seg, sel; int i; seg = dpmi_real_malloc ((rdata_size+15)/16, &sel); if (!seg) return (0); _pkt_inf->rm_seg = seg; _pkt_inf->rm_sel = sel; RP_SET (rm_base, 0, _pkt_inf->rm_seg); for (i = 0; i < (int)rdata_size; i += 4) POKEL (_pkt_inf->rm_seg, i, 0); } #elif (DOSX == 0) { char _far *buf = _fcalloc (rdata_size, 0); if (!buf) return (0); _pkt_inf->rm_seg = FP_SEG (buf); rm_base = (DWORD) buf; } #else #error Help! #endif pktq_far_init (sizeof(struct pkt_rx_element), RX_BUFS, ASMPKT_INF); _pkt_inf->pkt_queue.num_buf = RX_BUFS; return (rm_base); }
static int setup_rmode_receiver (void) { WORD rx_seg, rx_ofs; WORD asmpkt_size_chk; int head_size = RX_ELEMENT_HEAD_SIZE; WATT_ASSERT (rm_base); WATT_ASSERT ((head_size % 4) == 0); rx_seg = _pkt_inf->rm_seg; rx_ofs = PktReceiver; #if 0 /* test */ printf ("PktReceiver @ %04X:%04X, ", rx_seg, PktReceiver); printf ("_asmpkt_inf @ %04X:%04X\n", rx_seg, (int)sizeof(real_stub_array)); #endif *(WORD*)&real_stub_array[asmpkt_inf+0] = sizeof(real_stub_array); *(WORD*)&real_stub_array[asmpkt_inf+2] = rx_seg; asmpkt_size_chk = *(WORD*) (real_stub_array + size_chk); if (asmpkt_size_chk != sizeof(PKT_INFO)) { TCP_CONSOLE_MSG (0, ("%s (%u): Development error:\n" " sizeof(pkt_info) = %ld in pcpkt.h\n" " sizeof(pkt_info) = %u in asmpkt.nas, (diff %ld)\n", __FILE__, __LINE__, (long)sizeof(PKT_INFO), asmpkt_size_chk, (long)(sizeof(PKT_INFO) - asmpkt_size_chk))); return (-1); } if (*(WORD*)&real_stub_array[PktReceiver] != 0xA80F || /* push gs */ *(WORD*)&real_stub_array[PktReceiver+2] != 0xA00F) /* push fs */ { TCP_CONSOLE_MSG (0, ("%s (%u): Development error:\n" " PktReceiver misaligned\n", __FILE__, __LINE__)); return (-1); } if (!has_rdtsc || !use_rdtsc) { DWORD patch_it = (*(WORD*) &real_stub_array[patch_nop]) + (DWORD) &real_stub_array; TCP_CONSOLE_MSG (4, ("patch_it (%04X): %02X,%02X,%02X\n", *(WORD*)&real_stub_array[patch_nop], ((BYTE*)patch_it)[0], ((BYTE*)patch_it)[1], ((BYTE*)patch_it)[2])); ((BYTE*)patch_it) [0] = 0x90; /* NOP */ ((BYTE*)patch_it) [1] = 0x90; ((BYTE*)patch_it) [2] = 0x90; } #if (DOSX & (PHARLAP|POWERPAK|X32VM)) WriteRealMem (rm_base, &real_stub_array, sizeof(real_stub_array)); #elif (DOSX & DJGPP) dosmemput (&real_stub_array, sizeof(real_stub_array), rm_base); #elif (DOSX & DOS4GW) || (DOSX == 0) memcpy ((void*)rm_base, &real_stub_array, sizeof(real_stub_array)); #else #error Help me! #endif return (0); }
/** * Our low-level capture thread. * * Loop waiting for packet(s) in PacketReceivePacket(). In * _pkt_release() the receive event-handle (adapter->Readvent) is * set. This causes WaitForSingleObject() in PacketReceivePacket() * to return. It is vital that the ADAPTER object isn't deallocated * before PacketReceivePacket() returns. * * The return-value is > 0 if thread exited on it's own. Otherwise * it is 0 (from GetExitCodeThread). */ DWORD __stdcall pkt_recv_thread (void *arg) { int rc = 0; while (1) { const ADAPTER *adapter; const BYTE *pkt, *pkt_end; size_t cap_len, hdr_len; int total_len, chunk; PACKET npf_pkt; if (!_pkt_inf || _pkt_inf->stop_thread) /* signals closure */ { rc = 1; break; } adapter = (const ADAPTER*) _pkt_inf->adapter; npf_pkt.Length = _pkt_inf->npf_buf_size; npf_pkt.Buffer = _pkt_inf->npf_buf; if (!PacketReceivePacket(adapter, &npf_pkt, TRUE)) { rc = 2; break; } total_len = npf_pkt.ulBytesReceived; ENTER_CRIT(); for (pkt = npf_pkt.Buffer, pkt_end = (BYTE*)npf_pkt.Buffer + total_len, chunk = 1; pkt < pkt_end; pkt += Packet_WORDALIGN(cap_len+hdr_len), chunk++) { struct pkt_ringbuf *q; struct pkt_rx_element *head; struct bpf_hdr *bp; q = &_pkt_inf->pkt_queue; bp = (struct bpf_hdr*) pkt; cap_len = bp->bh_caplen; hdr_len = bp->bh_hdrlen; num_rx_bytes += bp->bh_datalen; TCP_CONSOLE_MSG (2, ("pkt_recv_thread(): total_len %d, " "chunk %d, cap_len %d, in-idx %d\n", total_len, chunk, cap_len, q->in_index)); if (cap_len > ETH_MAX) { _pkt_inf->error = "Large size"; STAT (macstats.num_too_large++); } else if (pktq_in_index(q) == q->out_index) /* queue is full, drop it */ q->num_drop++; else { int pad_len, buf_max; head = (struct pkt_rx_element*) pktq_in_buf (q); memcpy (head->rx_buf, pkt + hdr_len, cap_len); head->tstamp_put = bp->bh_tstamp; head->rx_length = cap_len; /* zero-pad up to ETH_MAX (don't destroy marker at end) */ buf_max = q->buf_size - RX_ELEMENT_HEAD_SIZE - 4; pad_len = min (ETH_MAX, buf_max - cap_len); if (pad_len > 0) memset (&head->rx_buf[cap_len], 0, pad_len); pktq_inc_in (q); } } LEAVE_CRIT(); } TCP_CONSOLE_MSG (2, ("pkt_recv_thread(): rc %d\n", rc)); fflush (stdout); ARGSUSED (arg); thr_stopped = TRUE; return (rc); }
/** * Initialise WinPcap and return our MAC address. */ int pkt_eth_init (mac_address *mac_addr) { struct { PACKET_OID_DATA oidData; char descr[512]; } oid; const ADAPTER *adapter = NULL; DWORD thread_id; BOOL is_up; if (_watt_is_win9x) /**< \todo Support Win-9x too */ { (*_printf) (_LANG("Win-NT or later reqired.\n")); _pkt_errno = PDERR_GEN_FAIL; return (WERR_ILL_DOSX); } if (!_watt_no_config || _watt_user_config_fn) parse_config_pass_1(); _pkt_inf = calloc (sizeof(*_pkt_inf), 1); if (!_pkt_inf) { (*_printf) (_LANG("Failed to allocate WinPcap DRIVER data.\n")); _pkt_errno = PDERR_GEN_FAIL; return (WERR_NO_MEM); } if (debug_on >= 2 && dump_fname[0]) dump_file = fopen_excl (ExpandVarStr(dump_fname), "w+t"); if (!PacketInitModule(TRUE, dump_file)) { (*_printf) (_LANG("Failed to initialise WinPcap.\n")); pkt_release(); _pkt_errno = PDERR_NO_DRIVER; return (WERR_PKT_ERROR); } if (!_pktdrvrname[0] && !find_adapter(_pktdrvrname,sizeof(_pktdrvrname))) { (*_printf) (_LANG("No WinPcap driver found.\n")); _pkt_errno = PDERR_NO_DRIVER; return (WERR_NO_DRIVER); } TCP_CONSOLE_MSG (2, ("device %s\n", _pktdrvrname)); adapter = PacketOpenAdapter (_pktdrvrname); if (!adapter) { if (debug_on > 0) (*_printf) (_LANG("PacketOpenAdapter (\"%s\") failed; %s\n"), _pktdrvrname, win_strerror(GetLastError())); pkt_release(); return (WERR_NO_DRIVER); } _pkt_inf->adapter = adapter; #if defined(USE_DYN_PACKET) _pkt_inf->adapter_info = NULL; #else _pkt_inf->adapter_info = PacketFindAdInfo (_pktdrvrname); #endif /* Query the NIC driver for the adapter description */ memset (&oid, 0, sizeof(oid)); oid.oidData.Oid = OID_GEN_VENDOR_DESCRIPTION; oid.oidData.Length = sizeof(oid.descr); if (PacketRequest (adapter, FALSE, &oid.oidData)) StrLcpy (_pktdrvr_descr, (char*)oid.oidData.Data, sizeof(_pktdrvr_descr)); else { (*_printf) (_LANG("PacketRequest() failed; %s\n"), win_strerror(GetLastError())); pkt_release(); return (WERR_PKT_ERROR); } if (!get_interface_type(&_pktdevclass)) { pkt_release(); return (WERR_PKT_ERROR); } if (get_connected_status(&is_up) && !is_up) (*_printf) (_LANG("Warning: the adapter %s is down\n"), _pktdrvrname); switch (_pktdevclass) { case PDCLASS_TOKEN: _pkt_ip_ofs = sizeof(tok_Header); break; case PDCLASS_ETHER: _pkt_ip_ofs = sizeof(eth_Header); break; case PDCLASS_FDDI: _pkt_ip_ofs = sizeof(fddi_Header); break; case PDCLASS_ARCNET: _pkt_ip_ofs = ARC_HDRLEN; break; default: pkt_release(); (*_printf) (_LANG("WinPcap-ERROR: Unsupported driver class %dh\n"), _pktdevclass); _pkt_errno = PDERR_NO_CLASS; return (WERR_PKT_ERROR); } if (!pkt_get_addr(mac_addr)) /* get our MAC address */ { pkt_release(); return (WERR_PKT_ERROR); } pktq_init (&_pkt_inf->pkt_queue, sizeof(_pkt_inf->rx_buf[0]), /* RX_SIZE */ DIM(_pkt_inf->rx_buf), /* RX_BUFS */ (char*)&_pkt_inf->rx_buf); _pkt_inf->npf_buf_size = RX_SIZE * pkt_num_rx_bufs; _pkt_inf->npf_buf = malloc (_pkt_inf->npf_buf_size); if (!_pkt_inf->npf_buf) { (*_printf) (_LANG("Failed to allocate %d byte Rx buffer.\n"), _pkt_inf->npf_buf_size); pkt_release(); _pkt_errno = PDERR_GEN_FAIL; return (WERR_NO_MEM); } PacketSetMode (adapter, PACKET_MODE_CAPT); PacketSetBuff (adapter, _pkt_inf->npf_buf_size); PacketSetMinToCopy (adapter, ETH_MIN); /* PacketReceivePacket() blocks until something is received */ PacketSetReadTimeout ((ADAPTER*)adapter, 0); /* Set Rx-mode forced via config. */ if (_pkt_forced_rxmode != -1) { _pkt_forced_rxmode &= 0xFFFF; /* clear bits not set via ARG_ATOX_W */ if (_pkt_forced_rxmode == 0 || /* check illegal bit-values */ (_pkt_forced_rxmode & 0x10) || (_pkt_forced_rxmode & 0x40) || (_pkt_forced_rxmode > 0x80)) { TCP_CONSOLE_MSG (0, ("Illegal Rx-mode (0x%02X) specified\n", _pkt_forced_rxmode)); _pkt_forced_rxmode = -1; } } if (pkt_get_rcv_mode()) _pkt_rxmode0 = _pkt_rxmode; if (_pkt_forced_rxmode != -1) pkt_set_rcv_mode (_pkt_forced_rxmode); else pkt_set_rcv_mode (RXMODE_DEFAULT); #if 1 _pkt_inf->recv_thread = CreateThread (NULL, 2048, pkt_recv_thread, NULL, 0, &thread_id); #else _pkt_inf->recv_thread = _beginthreadex (NULL, 2048, pkt_recv_thread, NULL, 0, &thread_id); #endif if (!_pkt_inf->recv_thread) { (*_printf) (_LANG("Failed to create receiver thread; %s\n"), win_strerror(GetLastError())); pkt_release(); _pkt_errno = PDERR_GEN_FAIL; return (WERR_PKT_ERROR); } if (thr_realtime) SetThreadPriority (_pkt_inf->recv_thread, THREAD_PRIORITY_TIME_CRITICAL); TCP_CONSOLE_MSG (2, ("capture thread-id %lu\n", thread_id)); #if defined(USE_DEBUG) if (debug_on >= 2) { (*_printf) ("link-details:\n"); show_link_details(); } #endif return (0); }
/** * _eth_send() does the actual transmission once we are complete with * filling the buffer. Do any last minute patches here, like fix the * size. Send to "loopback" device if it's IP and destination matches * loopback network (127.x.x.x.). * * Return length of network-layer packet (not length of link-layer * packet). */ int _eth_send (WORD len, const void *sock, const char *file, unsigned line) { #if defined(USE_DEBUG) || defined(USE_LOOPBACK) unsigned errline = 0; #endif BOOL send_loopback_to_driver = FALSE; SIO_TRACE (("_eth_send, len %d", len)); if (!_eth_is_init) /* GvB 2002-09, Lets us run without a working eth */ { SOCK_ERRNO (ENETDOWN); return (0); } #if defined(WIN32) /* * Just a test for now; send it to the driver and look what happens.... * They go on the wire and not to the Winsock loopback provider. * No surprise here yet. */ if (loopback_mode & LBACK_MODE_WINSOCK) send_loopback_to_driver = TRUE; #endif if (proto == IP4_TYPE) { /* Sending to loopback device if IPv4. */ const in_Header *ip = (const in_Header*) nw_pkt; if (!send_loopback_to_driver && _ip4_is_loopback_addr(intel(ip->destination))) { #if defined(USE_LOOPBACK) len = send_loopback (*TX_BUF(), FALSE, &errline); #else STAT (ip4stats.ips_odropped++); /* packet dropped (null-device) */ #endif goto debug_tx; } } #if defined(USE_IPV6) else if (proto == IP6_TYPE) { const in6_Header *ip = (const in6_Header*) nw_pkt; if (!send_loopback_to_driver && IN6_IS_ADDR_LOOPBACK(&ip->destination)) { #if defined(USE_LOOPBACK) len = send_loopback (*TX_BUF(), TRUE, &errline); #else STAT (ip6stats.ip6s_odropped++); #endif goto debug_tx; } } #endif /* USE_IPV6 */ #if defined(USE_PPPOE) else if (proto == PPPOE_SESS_TYPE) { pppoe_Packet *pppoe = (pppoe_Packet*) TX_BUF()->eth.data; pppoe->length = intel16 (len+2); len += PPPOE_HDR_SIZE + 2; /* add 2 for protocol */ } #endif /* Store the last Tx CPU timestamp (for debugging). */ #if (DOSX) && !(DOSX & WINWATT) if (_dbugxmit && has_rdtsc) get_rdtsc2 (&_eth_last.tx.tstamp); #endif /* Do the MAC-dependant transmit. `len' on return is total length * of link-layer packet sent. `len' is 0 on failure. The xmit-hook * is used by e.g. libpcap/libnet. */ if (_eth_xmit_hook) len = (*_eth_xmit_hook) (TX_BUF(), len + _pkt_ip_ofs); else len = (*mac_transmit) (TX_BUF(), len + _pkt_ip_ofs); if (len > _pkt_ip_ofs) { _eth_last.tx.size = len; len -= _pkt_ip_ofs; } else { if (debug_on) outs ("Tx failed. "); len = 0; _eth_last.tx.size = 0; } debug_tx: #if defined(NEED_PKT_SPLIT) pkt_split_mac_out (TX_BUF()); #endif #if defined(USE_STATISTICS) if (len > 0) update_out_stat(); #endif #if defined(USE_DEBUG) if (_dbugxmit) (*_dbugxmit) (sock, (const in_Header*)nw_pkt, file, line); if (len == 0) { if (errline && !send_loopback_to_driver) dbug_printf ("** Error in loopback handler, line %u\n", errline); else { const char err[] = "** Transmit fault **\n"; TCP_CONSOLE_MSG (0, ("%s", err)); dbug_printf (err); } } #else ARGSUSED (sock); ARGSUSED (file); ARGSUSED (line); #endif /* Undo hack done in pppoe_mac_format() */ if (proto == PPPOE_SESS_TYPE || _pktdevclass == PDCLASS_ETHER) _pkt_ip_ofs = sizeof(eth_Header); return (len); }