📄 pcsed.c
字号:
/*
* Ethernet Driver Routines
*
* The TCP code uses Ethernet constants for protocol numbers and 48 bits
* for address. Also, 0xFFFFFFFFFFFF is assumed to be a broadcast.
*
* If you need to write a new driver, implement it at this level and use
* the above mentioned constants as this program's constants, not device
* dependant constants.
*
* The packet driver code lies below this module.
*
* _eth_addr - MAC address of this host.
* _eth_brdcast - MAC broadcast address.
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#ifdef __HIGHC__
#include <init.h> /* _mwenv, PL_ENV */
#endif
#include "copyrigh.h"
#include "wattcp.h"
#include "wdpmi.h"
#include "strings.h"
#include "language.h"
#include "sock_ini.h"
#include "loopback.h"
#include "misc.h"
#include "fragment.h"
#include "pcmulti.h"
#include "pcqueue.h"
#include "pcconfig.h"
#include "pcstat.h"
#include "pcdbug.h"
#include "pctcp.h"
#include "pcsed.h"
#include "pcpkt.h"
#include "pppoe.h"
mac_address _eth_addr; /* Local link-layer source address */
mac_address _eth_brdcast; /* Link-layer broadcast address */
mac_address _eth_loop_addr; /* Link-layer loopback address */
BOOL _eth_is_init = 0; /* we are initialised */
BOOL _ip_recursion = 0; /* avoid recursion in arp_resolve() */
/*
* Pointer to functions that when set bypasses the normal poll/send
* functions _eth_arrived() and _eth_send()
*/
void *(*_eth_recv_hook) (WORD *type);
int (*_eth_xmit_hook) (void *buf, unsigned len);
/*
* Pointer to functions that does the filling of correct MAC-header
* and sends the link-layer packet. We store 'proto' between calls.
*/
static BYTE *(*mac_format) (void *mac_buf, const void *mac_dest, WORD type);
static int (*mac_transmit) (void *mac_buf, WORD len);
static WORD proto; /* protocol set in _eth_formatpacket() */
static BYTE *nw_pkt; /* where network protocol packet starts */
/*
* _eth_format_packet() places the next packet to be transmitted into
* this link-layer output packet. We return address of higher-level
* protocol (IP/RARP/RARP) header.
*
* Note, I only maintain a single output buffer, and it gets used quickly
* then released. The benefits of non-blocking systems are immense.
*/
static union link_Packet outbuf;
BYTE *_eth_formatpacket (const void *mac_dest, WORD eth_type)
{
nw_pkt = (*mac_format) (&outbuf, mac_dest, eth_type);
memset (nw_pkt, 0, sizeof(in_Header)); /* clear only IP-header */
return (nw_pkt);
}
/*
* _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)
{
void *tx_buf = &outbuf;
update_out_stat (nw_pkt, proto);
if (proto == IP_TYPE)
{
/* Sending to loopback device (only ip accepted)
*/
if (is_local_addr(intel(((in_Header*)nw_pkt)->destination)))
{
#if defined(USE_LOOPBACK)
return _eth_send_loopback (outbuf);
#else
/* packet dropped (null-device)
*/
STAT (ipstats.ips_odropped++);
return (len);
#endif
}
#if defined(USE_PPPOE)
if (pppoe_is_up())
/* tx_buf = ppp_output (&outbuf, len) */ ;
#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)
return (len - _pkt_ip_ofs);
if (debug_on)
outs ("Tx failed.");
return (0);
}
/*
* Functions for formatting MAC-headers for Ethernet, Token-Ring
* and FDDI. null_mac_format() is for protocols without MAC-headers.
*/
static BYTE *eth_mac_format (void *mac_buf, const void *mac_dest, WORD type)
{
union link_Packet *buf = (union link_Packet*) mac_buf;
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;
proto = type; /* remember protocol for _eth_send() */
return (&buf->eth.data[0]);
}
static BYTE *tok_mac_format (void *mac_buf, const void *mac_dest, WORD type)
{
union link_Packet *buf = (union link_Packet*) mac_buf;
memcpy (&buf->tok.head.destination, mac_dest, sizeof(mac_address));
memcpy (&buf->tok.head.source, &_eth_addr, sizeof(mac_address));
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[0]);
}
static BYTE *fddi_mac_format (void *mac_buf, const void *mac_dest, WORD type)
{
union link_Packet *buf = (union link_Packet*) mac_buf;
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[0]);
}
static BYTE *null_mac_format (void *mac_buf, const void *mac_dest, WORD type)
{
union link_Packet *buf = (union link_Packet*) mac_buf;
ARGSUSED (mac_dest);
ARGSUSED (type);
proto = IP_TYPE;
return (BYTE*) (&buf->ip.head);
}
/*
* Function called via 'mac_transmit' to actually send the data.
*/
static int eth_mac_xmit (void *buf, WORD len)
{
if (len < ETH_MIN)
{
memset ((void*)((BYTE*)buf + len), 0, ETH_MIN - len);
len = ETH_MIN;
}
else if (len > ETH_MAX)
len = ETH_MAX;
return pkt_send (buf, len);
}
static int tok_mac_xmit (void *buf, WORD len)
{
if (len > TOK_MAX) /* Token-Ring has no min. length */
len = TOK_MAX;
return pkt_send (buf, len);
}
static int fddi_mac_xmit (void *buf, WORD len)
{
if (len < FDDI_MIN)
{
memset ((void*)((BYTE*)buf + len), 0, FDDI_MIN - len);
len = FDDI_MIN;
}
else if (len > FDDI_MAX)
len = FDDI_MAX;
return pkt_send (buf, len);
}
static int null_mac_xmit (void *buf, WORD len)
{
return pkt_send (buf, len);
}
/*
* Initialize the (DOS-extender API and) network driver interface.
* Return error-code or 0 if okay.
*/
int _eth_init (void)
{
if (_eth_is_init)
return (0);
#if defined(__HIGHC__)
if (_mwenv != PL_ENV)
{
outsnl (_LANG("Only Pharlap DOS extender supported"));
return (WERR_ILL_DOSX);
}
#elif defined(__WATCOM386__) /* Watcom386 + DOS4GW style or Pharlap */
if (dpmi_init() < 0)
return (WERR_ILL_DOSX);
#elif (DOSX & WDOSX) /* 32-bit Borland/MSVC + WDOSX extender */
if (dpmi_init() < 0)
return (WERR_ILL_DOSX);
#endif
if (!pkt_eth_init(&_eth_addr))
return (WERR_NO_DRIVER); /* error message already printed */
switch (_pktdevclass)
{
case PD_ETHER:
mac_format = eth_mac_format;
mac_transmit = eth_mac_xmit;
break;
case PD_TOKEN:
mac_format = tok_mac_format;
mac_transmit = tok_mac_xmit;
break;
case PD_FDDI:
mac_format = fddi_mac_format;
mac_transmit = fddi_mac_xmit;
break;
case PD_SLIP:
case PD_PPP:
mac_format = null_mac_format;
mac_transmit = null_mac_xmit;
break;
default: /* already handled in pkt_drvr_info() */
break;
}
memset (&outbuf, 0, sizeof(outbuf));
memset (&_eth_brdcast, 0xFF, sizeof(_eth_brdcast));
_eth_loop_addr[0] = 0xCF;
pkt_buf_wipe();
_eth_is_init = 1;
return (0); /* everything okay */
}
/*
* _eth_release() - release the hardware driver
*/
void _eth_release (void)
{
if (_eth_is_init)
{
_eth_is_init = 0;
pkt_release();
}
}
/*
* Sets a new MAC address for our interface
*/
int _eth_set_addr (mac_address *addr)
{
if (_pktserial || pkt_set_addr(addr))
{
memcpy (&_eth_addr, addr, sizeof(_eth_addr));
return (1);
}
return (0);
}
/*
* Fill in hardware address type/length for BOOTP/DHCP packets.
* Also used for ARP/RARP packets. Results must be converted to
* proper byte-order by caller.
*/
BYTE _eth_get_hwtype (BYTE *hwtype, BYTE *hwlen)
{
if (_pktdevclass == PD_ETHER ||
_pktdevclass == PD_FDDI) /* according to RFC-1390 */
{
if (hwlen)
*hwlen = sizeof (mac_address);
if (hwtype)
*hwtype = HW_TYPE_ETHER;
return (HW_TYPE_ETHER);
}
if (_pktdevclass == PD_TOKEN)
{
if (hwlen)
*hwlen = sizeof (mac_address);
if (hwtype)
*hwtype = HW_TYPE_TOKEN;
return (HW_TYPE_TOKEN);
}
return (0);
}
/*
* _eth_free() - free an input buffer once it is no longer needed.
* If it's a IP fragment free the fragment buffers, but don't update
* the '_pkt_inf->ip_queue' queue. If 'pkt' is NULL, restart the queues.
*/
void _eth_free (const void *pkt, WORD type)
{
if (_eth_recv_hook) /* hook-function should free it's own packet */
return;
if (!pkt)
{
pkt_buf_wipe(); /* restart the queues */
return;
}
if (type == IP_TYPE)
{
#if defined(USE_FRAGMENTS)
if (!free_fragment((const in_Header*)pkt))
#endif
pkt_free_pkt (pkt, TRUE);
}
else if (type == ARP_TYPE || type == RARP_TYPE)
pkt_free_pkt (pkt, FALSE);
else
{
#if defined(USE_DEBUG)
(*_printf) ("%s: freeing illegal buffer, type %04Xh.\r\n",
__FILE__, type);
#endif
pkt_buf_wipe(); /* restart the queues */
}
}
/*
* Check a Token-Ring raw packet for RIF/RCF. Remove RCF if
* found. '*trp' on output is corrected for dropped RCF.
* These macros are taken from `tcpdump'.
*/
#define RCF DSAP /* Routing Control where DSAP is when no routing */
#define TR_IS_SROUTED(th) ((th)->source[0] & 0x80)
#define TR_IS_BROADCAST(th) (((intel16((th)->RCF) & 0xE000) >> 13) >= 4)
#define TR_RIF_LENGTH(th) ((intel16((th)->RCF) & 0x1F00) >> 8)
#define TR_MAC_SIZE (2+2+2*sizeof(mac_address)) /* AC,FC,src/dst */
static void fix_tok_head (tok_Header **trp)
{
tok_Header *tr = *trp;
#if defined(USE_DEBUG)
if (dbug_handle() > 0)
{
BYTE *raw = (BYTE*)tr;
char buf[202], *p = buf;
int i;
for (i = 0; i < 50; i++)
p += sprintf (p, "%02X ", raw[i]);
*p++ = '\r';
*p = '\n';
dbug_write_raw (buf);
}
#endif
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
*/
movmem (tr, (BYTE*)tr + rlen, TR_MAC_SIZE);
*trp = (tok_Header*) ((BYTE*)tr + rlen);
}
}
#ifdef NOT_YET
static void fix_llc_head (void **mac)
{
}
#endif
/*
* Poll the IP-queue. If fragmented, give to fragment handler.
*/
static union link_Packet *poll_ip_queue (WORD *type)
{
struct pkt_ringbuf *q = &_pkt_inf->ip_queue;
while (pktq_queued(q))
{
WORD ip_flg;
DWORD ip_ofs;
in_Header *ip;
link_Packet *pkt = (link_Packet*) pktq_out_buf (q);
if (_pktserial)
{
ip = &pkt->ip.head; /* PD_SLIP / PD_PPP */
*type = IP_TYPE;
}
else if (_pktdevclass == PD_TOKEN)
{
tok_Header *tr = &pkt->tok.head;
fix_tok_head (&tr);
*type = tr->type;
/* A non-IP packet in the IP-queue?
* I guess this could happen with a buggy driver.
*/
if (*type != IP_TYPE)
return (union link_Packet*) tr;
ip = (in_Header*) (tr+1);
}
else if (_pktdevclass == PD_FDDI)
{
fddi_Packet *fddi = &pkt->fddi;
*type = fddi->head.type;
if (*type != IP_TYPE)
return (union link_Packet*) fddi;
ip = (in_Header*) &fddi->data[0];
}
else /* must be PD_ETHER */
{
*type = pkt->eth.head.type;
if (*type != IP_TYPE)
return (union link_Packet*) pkt;
ip = (in_Header*) &pkt->eth.data[0];
}
/* We have determined it's an IP-packet.
*/
ip_ofs = intel16 (ip->frag_ofs);
ip_flg = (WORD) (ip_ofs & ~IP_OFFMASK);
ip_ofs = (ip_ofs & IP_OFFMASK) << 3; /* 0 <= ip_ofs <= 65536-8 */
/* It's a non-fragmented IP-packet.
*
* fix-me!!: This packet might be a last fragment (ofs 0, MF=0)
* This would be normal for Linux.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -