/** * _eth_format_packet() places the next packet to be transmitted into * the above link-layer output packet. * \return address of higher-level protocol (IP/RARP/RARP) header. */ void *_eth_formatpacket (const void *mac_dest, WORD eth_type) { SIO_TRACE (("_eth_formatpacket, type %04X", eth_type)); nw_pkt = (*mac_tx_format) (TX_BUF(), mac_dest, eth_type); return (nw_pkt); }
/** * Format the MAC-header for Token-Ring. */ static void *tok_mac_format (void *mac_buf, const void *mac_dest, WORD type) { union link_Packet *buf = (union link_Packet*) mac_buf; SIO_TRACE (("tok_mac_format")); /* No need to clear data behind header. */ if (mac_dest) memcpy (&buf->tok.head.destination, mac_dest, sizeof(mac_address)); memcpy (&buf->tok.head.source, &_eth_addr, sizeof(mac_address)); #if 0 /* !!fix me: need to expand the RIF */ if (_pktdevclass == PDCLASSS_TOKEN_RIF) ((void)0); #endif buf->tok.head.accessCtrl = TR_AC; buf->tok.head.frameCtrl = TR_FC; buf->tok.head.DSAP = TR_DSAP; buf->tok.head.SSAP = TR_SSAP; buf->tok.head.ctrl = TR_CTRL; buf->tok.head.org[0] = TR_ORG; buf->tok.head.org[1] = TR_ORG; buf->tok.head.org[2] = TR_ORG; buf->tok.head.type = type; proto = type; return (&buf->tok.data); }
static void fix_tok_head (tok_Header **trp) { tok_Header *tr = *trp; #if defined(USE_DEBUG) const BYTE *raw = (const BYTE*)tr; int i; for (i = 0; i < 50; i++) dbug_printf ("%02X ", raw[i]); dbug_write ("\n"); #endif SIO_TRACE (("fix_tok_head")); if (TR_IS_SROUTED(tr)) /* Source routed */ { int rlen = TR_RIF_LENGTH (tr); tr->source[0] &= 0x7F; /* clear RII bit */ /* Set our notion of link-layer broadcast */ if (TR_IS_BROADCAST(tr)) tr->destination[0] |= 1; /* Copy MAC-header rlen bytes upwards */ memmove ((BYTE*)tr + rlen, tr, TR_MAC_SIZE); *trp = (tok_Header*) ((BYTE*)tr + rlen); } }
/** * Return value of protocol-type given an IP packet. */ WORD _eth_mac_typ (const in_Header *ip) { const union link_Packet *pkt; SIO_TRACE (("_eth_mac_typ")); pkt = (const union link_Packet*) ((BYTE*)ip - _pkt_ip_ofs); if (_pktdevclass == PDCLASS_ETHER) return (pkt->eth.head.type); if (_pktdevclass == PDCLASS_TOKEN || _pktdevclass == PDCLASS_TOKEN_RIF) return (pkt->tok.head.type); if (_pktdevclass == PDCLASS_FDDI) return (pkt->fddi.head.type); if (_pktdevclass == PDCLASS_ARCNET) return (pkt->arc.head.type); (*_printf) ("Illegal use of `_eth_mac_typ()' for class %d\n", _pktdevclass); exit (-1); /*@-unreachable@*/ return (0); }
/** * Format the MAC-header for Ethernet. */ static void *eth_mac_format (void *mac_buf, const void *mac_dest, WORD type) { union link_Packet *buf = (union link_Packet*) mac_buf; SIO_TRACE (("eth_mac_format")); proto = type; /* remember protocol for _eth_send() */ /* Clear any remains of an old small packet */ memset (&buf->eth.data[0], 0, ETH_MIN-sizeof(eth_Header)); #if defined(USE_PPPOE) if (type == IP4_TYPE && pppoe_is_up(mac_dest)) { proto = PPPOE_SESS_TYPE; return pppoe_mac_format (buf); } #endif if (mac_dest) memcpy (&buf->eth.head.destination, mac_dest, sizeof(mac_address)); memcpy (&buf->eth.head.source, &_eth_addr, sizeof(mac_address)); buf->eth.head.type = type; return (&buf->eth.data); }
/* * trace2com_init() - Public initialisation */ int trace2com_init (WORD portAddress, DWORD baudRate) { BYTE Lsb, Msb; WORD base; DWORD div; /* Check/get UART address */ if (portAddress < 1 || portAddress > 4) return (0); base = trace2com_stdPorts [portAddress-1]; /* See if the chip is actually there and ready */ if (_inportb (base+IER_REG) == 0xFF) /* Nothing here */ return (0); if ((_inportb (base+IER_REG) & 0x0F) != 0x00) return (0); /* UART is already in use by another program */ _outportb (base+IER_REG, 0); /* disable all interrupts */ if (_inportb (base+IER_REG) != 0) return (0); /* Whatever is here is not an UART */ /* Set up UARTs registers */ div = 115200UL / baudRate; Msb = div >> 8; Lsb = (div << 8) >> 8; _outportb (base+LCR_REG, 0x80); /* Turn address latch on */ _outportb (base+BAUD_LSB_REG, Lsb); _outportb (base+BAUD_MSB_REG, Msb); _outportb (base+LCR_REG, 0x00); /* Turn address latch off (again) */ _outportb (base+IER_REG, 0x00); /* No interrupts, we use polling */ _outportb (base+FIFO_REG, 0x01|0x08); /* Activate FIFO @ MODE 2 */ _outportb (base+LCR_REG , 0x03); /* 8, N, 1 */ _outportb (base+MCR_REG, 0x03); /* DTR + DTS on */ /* Check chip type, gives us the FIFO size */ _outportb (base + FIFO_REG, 0x11); Lsb = _inportb (base + FIFO_REG); /* If we have a 16750 or 16550 the FIFO size is 16, otherwise we assume 1 */ trace2com_fifoSize_1 = ((Lsb & 0x20) != 0x20 || (Lsb & 0xC0) == 0xC0) ? 15 : 0; /* We are now officially open for business */ trace2com_speed = baudRate; trace2com_base = base; SIO_TRACE ((_LANG("Watt-32 COM%d trace started"), portAddress)); return (1); }
static int tok_mac_xmit (const void *buf, WORD len) { SIO_TRACE (("tok_mac_xmit, len %d", len)); if (len > TOK_MAX) /* Token-Ring has no min. length */ len = TOK_MAX; return pkt_send (buf, len); }
/** * Leaves a multicast group (at the physical layer) * * \retval 1 The group was left successfully. * \retval 0 Attempt failed. */ BOOL _eth_leave_mcast_group (const struct MultiCast *mc) { eth_address list[IPMULTI_SIZE]; int i, len, idx; SIO_TRACE (("_eth_leave_mcast_group")); /* \note This should be expanded to include switching back to * RXMODE_MULTCAST1 if the list of multicast addresses has * shrunk sufficiently. * * First check to see if we're in RXMODE_MULTICAST2. if so return */ #if defined(WIN32) if (_pkt_rxmode & RXMODE_MULTICAST2) return (TRUE); #else if (_pkt_rxmode >= RXMODE_MULTICAST2) return (TRUE); #endif /* get the list of current multicast addresses */ len = sizeof(list); if (!pkt_get_multicast_list (list, &len)) return (FALSE); /* find the apropriate entry */ for (i = 0, idx = -1; i < len/SIZEOF(list[0]); i++) if (!memcmp(list[i],&mc->ethaddr,sizeof(list[0]))) idx = i; /* if it's not in the list, just return */ if (idx == -1) return (TRUE); /* ahh, but it _is_ in the list. So shorten the list * and send it back to the PKTDRVR */ if (idx+1 < len/SIZEOF(list[0])) memmove (&list[idx], &list[idx+1], len-(idx+1)*sizeof(list[0])); len -= sizeof(list[0]); if (!pkt_set_multicast_list((const eth_address*)&list, len)) { /* If no space or no MC support, switch mode */ if (_pkt_errno == PDERR_NO_SPACE || _pkt_errno == PDERR_NO_MULTICAST) return pkt_set_rcv_mode (RXMODE_MULTICAST2); return (FALSE); } return (TRUE); }
/** * Add a gateway to the routing table. * * The format of 'config_string' is: * IP-address [, subnet] , mask]] * * If 'config_string' is NULL, simply add 'ip' with zero * mask and subnet. */ BOOL _arp_add_gateway (const char *config_string, DWORD ip) { struct gate_entry *gw; DWORD subnet = 0UL; DWORD mask = 0UL; int i; SIO_TRACE (("_arp_add_gateway")); if (config_string) { const char* subnetp, *maskp; /* Get gateways IP address from string */ ip = aton (config_string); if (ip == 0) return (FALSE); /* invalid */ /* Check if optional subnet was supplied */ subnetp = strchr (config_string, ','); if (subnetp) { /* NB: atoi (used in aton) stops conversion when the first non-number * is hit, so there is no need to manually null-terminate the string. * i.e. aton ("123.123.123.123,blabla") = 123.123.123.123 */ subnet = aton (++subnetp); /* Check if optional mask was supplied */ maskp = strchr (subnetp, ','); if (maskp) mask = aton (++maskp); else /* No mask was supplied, we derive it from the supplied subnet */ { switch (subnet >> 30) { case 0: case 1: mask = 0xFF000000UL; break; case 2: mask = 0xFFFFFE00UL; /* minimal class B */ break; case 3: default: mask = 0xFFFFFF00UL; break; } } } } else /* (config_string == NULL) */ { if (ip == 0UL)
/** * Functions called via function pointer `mac_transmit' to * actually send the data. */ static int eth_mac_xmit (const void *buf, WORD len) { SIO_TRACE (("eth_mac_xmit, len %d", len)); if (len < ETH_MIN) len = ETH_MIN; /* zero padding already done in eth_mac_format() */ else if (len > ETH_MAX) len = ETH_MAX; return pkt_send (buf, len); }
/** * Free an input buffer once it is no longer needed. */ void _eth_free (const void *pkt) { SIO_TRACE (("_eth_free")); if (_eth_recv_hook) /* hook-function should free it's own packet */ return; if (!pkt) pkt_buf_wipe(); /* restart the queue */ else pkt_free_pkt (pkt); }
static int arcnet_mac_xmit (const void *buf, WORD len) { SIO_TRACE (("arcnet_mac_xmit, len %d", len)); if (len < ARCNET_MIN) len = ARCNET_MIN; else if (len > ARCNET_MAX) len = ARCNET_MAX; return pkt_send (buf, len); }
static int fddi_mac_xmit (const void *buf, WORD len) { SIO_TRACE (("fddi_mac_xmit, len %d", len)); if (len < FDDI_MIN) len = FDDI_MIN; else if (len > FDDI_MAX) len = FDDI_MAX; return pkt_send (buf, len); }
/* * Fix the LLC header to look like ordinary Ethernet II * !! not yet. */ static void fix_llc_head (void **mac) { SIO_TRACE (("fix_llc_head")); #if 1 DEBUG_RX (NULL, *mac); _eth_free (*mac); *mac = NULL; #else /** \todo handle IEEE 802.3 encapsulation also. */ #endif }
/** * Format MAC-header for protocols without MAC-headers. * Nothing done here. */ static void *null_mac_format (void *mac_buf, const void *mac_dest, WORD type) { union link_Packet *buf = (union link_Packet*) mac_buf; SIO_TRACE (("null_mac_format")); memset (&buf->ip.head, 0, sizeof(buf->ip.head)); ARGSUSED (mac_dest); ARGSUSED (type); proto = IP4_TYPE; return (void*) (&buf->ip.head); }
/** * Return pointer to MAC header start address of an IP packet. */ void *_eth_mac_hdr (const in_Header *ip) { SIO_TRACE (("_eth_mac_hdr")); if (!_pktserial) return (void*) ((BYTE*)ip - _pkt_ip_ofs); (*_printf) ("Illegal use of `_eth_mac_hdr()' for class %d\n", _pktdevclass); exit (-1); /*@-unreachable@*/ return (NULL); }
/** * Sets a new MAC address for our interface. */ int _eth_set_addr (const void *addr) { SIO_TRACE (("_eth_set_addr")); if (_pktserial || _pktdevclass == PDCLASS_ARCNET) return (1); if (pkt_set_addr(addr)) { memcpy (_eth_addr, addr, sizeof(_eth_addr)); return (1); } return (0); }
/** * Handle incoming RARP packets. */ BOOL _rarp_handler (const rarp_Header *rh, BOOL brdcast) { SIO_TRACE (("_rarp_handler")); DEBUG_RX (NULL, rh); if (!brdcast && rh->opcode == RARP_REPLY && rh->protType == IP4_TYPE && !memcmp(rh->dstEthAddr,_eth_addr,sizeof(mac_address))) { my_ip_addr = intel (rh->dstIPAddr); return (TRUE); } return (FALSE); }
/** * Format the MAC-header for FDDI. */ static void *fddi_mac_format (void *mac_buf, const void *mac_dest, WORD type) { union link_Packet *buf = (union link_Packet*) mac_buf; SIO_TRACE (("fddi_mac_format")); memset (&buf->fddi.data[0], 0, FDDI_MIN-sizeof(fddi_Header)); if (mac_dest) memcpy (&buf->fddi.head.destination, mac_dest, sizeof(mac_address)); memcpy (&buf->fddi.head.source, &_eth_addr, sizeof(mac_address)); buf->fddi.head.frameCtrl = FDDI_FC; buf->fddi.head.DSAP = FDDI_DSAP; buf->fddi.head.SSAP = FDDI_SSAP; buf->fddi.head.ctrl = FDDI_CTRL; buf->fddi.head.org[0] = FDDI_ORG; buf->fddi.head.org[1] = FDDI_ORG; buf->fddi.head.org[2] = FDDI_ORG; buf->fddi.head.type = type; proto = type; return (&buf->fddi.data); }
/** * Fill in hardware address type/length for BOOTP/DHCP packets. * Also used for ARP/RARP packets. Should never be called for PPP/SLIP. */ BYTE _eth_get_hwtype (BYTE *hwtype, BYTE *hwlen) { SIO_TRACE (("_eth_get_hwtype")); if (_pktdevclass == PDCLASS_ETHER) { if (hwlen) *hwlen = sizeof (eth_address); if (hwtype) *hwtype = HW_TYPE_ETHER; return (HW_TYPE_ETHER); } if (_pktdevclass == PDCLASS_FDDI) { if (hwlen) *hwlen = sizeof (fddi_address); if (hwtype) *hwtype = HW_TYPE_FDDI; return (HW_TYPE_FDDI); } if (_pktdevclass == PDCLASS_TOKEN || _pktdevclass == PDCLASS_TOKEN_RIF) { if (hwlen) *hwlen = sizeof (tok_address); if (hwtype) *hwtype = HW_TYPE_TOKEN; return (HW_TYPE_TOKEN); } if (_pktdevclass == PDCLASS_AX25) { if (hwlen) *hwlen = sizeof (ax25_address); if (hwtype) *hwtype = HW_TYPE_AX25; return (HW_TYPE_AX25); } if (_pktdevclass == PDCLASS_ARCNET) { if (hwlen) *hwlen = sizeof (arcnet_address); /* 1 byte */ if (hwtype) *hwtype = HW_TYPE_ARCNET; return (HW_TYPE_ARCNET); } return (0); }
/** * Poll the packet queue. Return first packet in queue. * Optionally do receiver profiling. * * \retval pointer to start of MAC-header. * \retval NULL no packets are queued. * * \note Not used when e.g. libpcap has set the `_eth_recv_hook' to * do it's own packet-polling. * \note 'type' is always set. */ static union link_Packet *poll_recv_queue (WORD *type) { #if defined(USE_FAST_PKT) || defined(WIN32) struct pkt_rx_element *buf; #endif struct pkt_ringbuf *q = &_pkt_inf->pkt_queue; union link_Packet *pkt; struct in_Header *ip; SIO_TRACE (("poll_recv_queue")); ASSERT_PKT_INF (NULL); #if defined(USE_DEBUG) #if defined(USE_FAST_PKT) if (!pktq_far_check(q)) #else if (!pktq_check(q)) #endif { fprintf (stderr, "%s: pkt-queue destroyed!\n", __FILE__); exit (-1); } #endif #if defined(WIN32) buf = pkt_poll_recv(); if (!buf) return (NULL); PROFILE_RECV ((uint64*)&buf->tstamp_put, (uint64*)&buf->tstamp_get); _eth_last.rx.size = buf->rx_length; _eth_last.rx.tstamp.lo = 0UL; /* no need yet */ _eth_last.rx.tstamp.hi = 0UL; pkt = (link_Packet*) &buf->rx_buf[0]; #elif defined(USE_FAST_PKT) buf = pkt_poll_recv(); if (!buf) return (NULL); PROFILE_RECV ((uint64*)buf->tstamp_put, (uint64*)buf->tstamp_get); pkt = (link_Packet*) buf->rx_buf; _eth_last.rx.size = buf->rx_length_1; /* length on 1st upcall */ _eth_last.rx.tstamp.lo = buf->tstamp_put[0]; /* TSC set in asmpkt */ _eth_last.rx.tstamp.hi = buf->tstamp_put[1]; #else if (!pktq_queued(q)) return (NULL); pkt = (link_Packet*) pktq_out_buf (q); _eth_last.rx.size = ETH_MAX; /* !! wrong, but doesn't matter for pcap */ _eth_last.rx.tstamp.lo = 0UL; /* pcdbug.c writes rx-time == dbg-time */ _eth_last.rx.tstamp.hi = 0UL; #endif if (_pktserial) { ip = &pkt->ip.head; /* SLIP/PPP/AX25 */ *type = (ip->ver == 4) ? IP4_TYPE : IP6_TYPE; return (pkt); } if (_pktdevclass == PDCLASS_TOKEN || _pktdevclass == PDCLASS_TOKEN_RIF) { tok_Header *tr = &pkt->tok.head; fix_tok_head (&tr); *type = tr->type; return (union link_Packet*) tr; } if (_pktdevclass == PDCLASS_ARCNET) { arcnet_Packet *arc = &pkt->arc; if (!fix_arc_head(&arc->head, type)) { DEBUG_RX (NULL, &arc->data); pkt_free_pkt (pkt); pkt = NULL; } return (pkt); } if (_pktdevclass == PDCLASS_FDDI) { fddi_Packet *fddi = &pkt->fddi; *type = fddi->head.type; return (pkt); } /* must be PDCLASS_ETHER */ *type = pkt->eth.head.type; ARGSUSED (q); return (pkt); }
/** * Joins a multicast group (at the physical layer). * * \retval 1 The group was joined successfully. * \retval 0 Attempt failed. */ BOOL _eth_join_mcast_group (const struct MultiCast *mc) { eth_address list [IPMULTI_SIZE]; int i, len, nextentry; BOOL is_mcast1, is_mcast2, is_promis; SIO_TRACE (("_eth_join_mcast_group")); /* Return if we're already receiving all multicasts or is in * promiscous mode. */ #if defined(WIN32) is_mcast1 = (_pkt_rxmode & RXMODE_MULTICAST1); is_mcast2 = (_pkt_rxmode & RXMODE_MULTICAST2); is_promis = (_pkt_rxmode & RXMODE_PROMISCOUS); #else is_mcast1 = (_pkt_rxmode >= RXMODE_MULTICAST1); is_mcast2 = (_pkt_rxmode >= RXMODE_MULTICAST2); is_promis = (_pkt_rxmode >= RXMODE_PROMISCOUS); #endif if (is_mcast2 || is_promis) return (TRUE); if (!is_mcast1) { is_mcast1 = pkt_set_rcv_mode(RXMODE_MULTICAST1); if (!is_mcast1) is_promis = pkt_set_rcv_mode(RXMODE_PROMISCOUS); if (is_promis) return (TRUE); if (!is_mcast1 && !is_promis) return (FALSE); /* hopeless, give up */ } len = sizeof(list); if (!pkt_get_multicast_list (list, &len)) { /* If no MC support, switch to MC2 mode */ if (_pkt_errno == PDERR_NO_MULTICAST) return pkt_set_rcv_mode (RXMODE_MULTICAST2); return (FALSE); } /* check to see if the address is already in the list */ for (i = 0; i < len / SIZEOF(list[0]); i++) if (!memcmp(list[i], &mc->ethaddr, sizeof(list[0]))) return (TRUE); if (len > 0) nextentry = len / sizeof(list[0]); /* append entry */ else nextentry = 0; memcpy (&list[nextentry], &mc->ethaddr, sizeof(eth_address)); len += sizeof (list[0]); if (!pkt_set_multicast_list((const eth_address*)&list,len)) { /* If no space or no MC support, switch to MC2 mode */ if (_pkt_errno == PDERR_NO_SPACE || _pkt_errno == PDERR_NO_MULTICAST) return pkt_set_rcv_mode (RXMODE_MULTICAST2); return (FALSE); } return (TRUE); }
static int null_mac_xmit (const void *buf, WORD len) { SIO_TRACE (("null_mac_xmit, len %d", len)); return pkt_send (buf, len); }
/** * Enqueue a link-layer frame (IPv4/v6 only) to the internal loopback device. * * \note This function uses call-by-value. Thus `pkt' buffer can * be modified by loopback_device() and loopback handler may * send using _eth_send(). * * \note Loopback device cannot send to itself (potential recursion). */ static int send_loopback (link_Packet pkt, BOOL is_ip6, unsigned *err_line) { struct pkt_ringbuf *q; const in_Header *ip; int ip_len; SIO_TRACE (("send_loopback")); if (!_pkt_inf) { *err_line = __LINE__; goto drop_it; } /* Call loopback handler with IP-packet */ ip = (in_Header*) ((BYTE*)&pkt + _pkt_ip_ofs); ip_len = loopback_device ((in_Header*)ip); q = &_pkt_inf->pkt_queue; if (!q || ip_len > (int)_mtu) { *err_line = __LINE__; goto drop_it; } if (ip_len > 0) { #if defined(USE_FAST_PKT) /* * Don't let pkt_receiver() modify the queue while testing/copying. */ if (pkt_buffers_used() >= _pkt_inf->pkt_queue.num_buf - 1) { *err_line = __LINE__; goto drop_it; } { char tx_buf [ETH_MAX]; unsigned len = ip_len; /* Enqueue packet to head of input IP-queue. */ if (!_pktserial) { void *data = (*mac_tx_format) (tx_buf, _eth_addr, is_ip6 ? IP6_TYPE : IP4_TYPE); memcpy (MAC_SRC(data), &_eth_loop_addr, sizeof(mac_address)); memcpy (data, ip, ip_len); len += _pkt_ip_ofs; } else memcpy (tx_buf, ip, ip_len); if (!pkt_append_recv(tx_buf, len)) { *err_line = __LINE__; goto drop_it; } } #elif defined(WIN32) struct pkt_rx_element *head; ENTER_CRIT(); if (pktq_in_index(q) == q->out_index) /* queue is full, drop it */ { q->num_drop++; LEAVE_CRIT(); *err_line = __LINE__; goto drop_it; } head = (struct pkt_rx_element*) pktq_in_buf (q); head->rx_length = _pkt_ip_ofs + ip_len; gettimeofday (&head->tstamp_put, NULL); /* Enqueue packet to head of input IP-queue. */ if (!_pktserial) { void *data = (*mac_tx_format) (&head->rx_buf, _eth_addr, is_ip6 ? IP6_TYPE : IP4_TYPE); memcpy (MAC_SRC(data), &_eth_loop_addr, sizeof(mac_address)); memcpy (data, ip, ip_len); } else memcpy (head, ip, ip_len); /* Update queue head index */ q->in_index = pktq_in_index (q); LEAVE_CRIT(); #else union link_Packet *head; DISABLE(); if (pktq_in_index(q) == q->out_index) /* queue is full, drop it */ { q->num_drop++; ENABLE(); *err_line = __LINE__; goto drop_it; } head = (union link_Packet*) pktq_in_buf (q); /* Enqueue packet to head of input IP-queue. */ if (!_pktserial) { void *data = (*mac_tx_format) (head, _eth_addr, is_ip6 ? IP6_TYPE : IP4_TYPE); memcpy (MAC_SRC(data), &_eth_loop_addr, sizeof(mac_address)); memcpy (data, ip, ip_len); } else memcpy (head, ip, ip_len); /* Update queue head index */ q->in_index = pktq_in_index (q); ENABLE(); #endif } *err_line = 0; return (ip_len + _pkt_ip_ofs); drop_it: /* * Maybe this should be an input counter */ if (is_ip6) STAT (ip6stats.ip6s_odropped++); else STAT (ip4stats.ips_odropped++); return (0); }
/** * Poll for arrival of new packets (IP/ARP/RARP/PPPoE protocol). * Sets protocol-type of packet received in 'type'. * * For Ethernet/TokenRing-type drivers: \n * \retval Pointer past the MAC-header to the IP/ARP/RARP * protocol header. Also check for link-layer broadcast. * * For PPP/SLIP-type drivers (no MAC-headers): \n * \retval Pointer to the IP-packet itself. * IP-protocol is assumed. Can never be link-layer broadcast. */ void *_eth_arrived (WORD *type_ptr, BOOL *broadcast) { union link_Packet *pkt; mac_address *dst; void *ret = NULL; BOOL is_bcast = FALSE; WORD type = 0; SIO_TRACE (("_eth_arrived")); if (!_eth_is_init) /* GvB 2002-09, Lets us run without a working driver */ return (NULL); if (_eth_recv_hook) pkt = (union link_Packet*) (*_eth_recv_hook) (&type); else pkt = poll_recv_queue (&type); if (!pkt) return (NULL); if (_eth_recv_peek && !(*_eth_recv_peek)(pkt)) { _eth_free (pkt); return (NULL); } /* Hack: If _ip?_handler() can't be reentered, only accept * non-IP packets. Assume PPPoE session packets carry only IP. */ if (_ip_recursion && (type == IP4_TYPE || type == IP6_TYPE || type == PPPOE_SESS_TYPE)) { /**< \todo push back packet, else it's lost */ STAT (macstats.num_ip_recurse++); _eth_free (pkt); return (NULL); } if (_pktserial) { dst = NULL; ret = (void*) &pkt->ip; } else if (_pktdevclass == PDCLASS_TOKEN || _pktdevclass == PDCLASS_TOKEN_RIF) { dst = &pkt->tok.head.destination; ret = (void*) &pkt->tok.data; } else if (_pktdevclass == PDCLASS_FDDI) { dst = &pkt->fddi.head.destination; ret = (void*) &pkt->fddi.data; } else if (_pktdevclass == PDCLASS_ARCNET) { dst = (mac_address*) &pkt->arc.head.destination; ret = (void*) ((BYTE*)pkt + ARC_HDRLEN); } else /* must be ether */ { dst = &pkt->eth.head.destination; ret = (void*) &pkt->eth.data; } #if defined(NEED_PKT_SPLIT) pkt_split_mac_in (pkt); #endif #if defined(USE_STATISTICS) update_in_stat(); #endif #if defined(NEED_PKT_SPLIT) && defined(USE_DEBUG) && 0 /* test */ pkt_print_split_in(); #endif /* ARCnet should never have LLC fields. So don't test for it */ if (_pktdevclass != PDCLASS_ARCNET) { if (dst && !memcmp(dst, &_eth_brdcast, sizeof(_eth_brdcast))) is_bcast = TRUE; if (intel16(type) < 0x600) /* LLC length field */ fix_llc_head (&ret); } else if (dst && *(BYTE*)dst == 0) /* ARCnet broadcast */ { is_bcast = TRUE; } if (type_ptr) *type_ptr = type; if (broadcast) *broadcast = is_bcast; return (ret); }
/** * Initialize the network driver interface. * \return 0 okay. * \return error-code otherwise. */ int _eth_init (void) { int rc; SIO_TRACE (("_eth_init")); if (_eth_is_init) return (0); rc = pkt_eth_init (&_eth_addr); if (rc) return (rc); /* error message already printed */ /* Save our MAC-address incase we change it. Change back at exit. */ memcpy (_eth_real_addr, _eth_addr, sizeof(_eth_real_addr)); switch (_pktdevclass) { case PDCLASS_ETHER: mac_tx_format = eth_mac_format; mac_transmit = eth_mac_xmit; break; case PDCLASS_TOKEN: case PDCLASS_TOKEN_RIF: mac_tx_format = tok_mac_format; mac_transmit = tok_mac_xmit; break; case PDCLASS_FDDI: mac_tx_format = fddi_mac_format; mac_transmit = fddi_mac_xmit; break; case PDCLASS_ARCNET: mac_tx_format = arcnet_mac_format; mac_transmit = arcnet_mac_xmit; break; case PDCLASS_SLIP: case PDCLASS_PPP: case PDCLASS_AX25: /* !! for now */ mac_tx_format = null_mac_format; mac_transmit = null_mac_xmit; break; default: outsnl (_LANG("No supported driver class found")); return (WERR_NO_DRIVER); } memset (TX_BUF(), 0, sizeof(union link_Packet)); memset (&_eth_brdcast, 0xFF, sizeof(_eth_brdcast)); _eth_loop_addr[0] = 0xCF; pkt_buf_wipe(); if (!_eth_get_hwtype(NULL, &_eth_mac_len)) _eth_mac_len = sizeof(eth_address); if (!strcmp(_pktdrvrname,"NDIS3PKT")) _eth_ndis3pkt = TRUE; else if (!strcmp(_pktdrvrname,"SwsVpkt")) _eth_SwsVpkt = TRUE; _eth_is_init = TRUE; RUNDOWN_ADD (_eth_release, 10); return (0); /* everything okay */ }
/** * _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); }