📄 pcsed.c
字号:
* to-do!!: look in 'fraglist' for a match.
*/
if (ip_ofs == 0 && (ip_flg & IP_MF) == 0)
return (union link_Packet*) pkt;
#if defined(USE_FRAGMENTS)
/* IP-packet is part of a fragment chain. Match with previous
* fragments and return reassembled IP-packet.
*/
ip = ip_defragment (ip, ip_ofs, ip_flg);
pktq_inc_out (q); /* drop the queued fragment */
if (!ip) /* not reassembled yet, or error */
continue; /* loop and check for more */
/*
* Return the reassembled segment (icmp, udp or tcp).
* We assume MAC-header is the same on all fragments.
* We return a packet with the MAC-header of the first
* fragment received.
*/
return (union link_Packet*) ((BYTE*)ip - _pkt_ip_ofs);
#else
pktq_inc_out (q); /* drop the fragment */
continue; /* poll for next */
#endif
}
return (NULL);
}
/*
* Poll the non-IP (ARP/RARP) queue.
* Serial drivers should always return NULL here.
*/
static union link_Packet *poll_arp_queue (WORD *type)
{
struct pkt_ringbuf *q = &_pkt_inf->arp_queue;
union link_Packet *ret = NULL;
while (pktq_queued(q))
{
char *tail = pktq_out_buf (q);
if (_pktserial)
{
pktq_inc_out (q);
#if defined(USE_DEBUG)
outsnl (_LANG("Non-IP from serial-type driver !?"));
#endif
STAT (macstats.num_err_type++);
continue;
}
if (_pktdevclass == PD_TOKEN)
{
tok_Header *tr = (tok_Header*) tail;
fix_tok_head (&tr);
*type = tr->type;
ret = (union link_Packet*) tr;
}
else if (_pktdevclass == PD_FDDI)
{
*type = ((fddi_Header*) tail)->type;
ret = (union link_Packet*) tail;
}
else /* must be PD_ETHER */
{
*type = ((eth_Header*) tail)->type;
ret = (union link_Packet*) tail;
}
if (*type != ARP_TYPE
#if defined(USE_RARP)
&& *type != RARP_TYPE)
#endif
)
{
STAT (macstats.num_err_type++);
pktq_inc_out (q); /* drop the packet */
continue;
}
return (ret);
}
return (NULL);
}
/*
* Poll IP or ARP/RARP queues.
* Alternate between ARP/IP on each poll. Or poll other queue if
* this queue is empty. Serial drivers should only get an IP-packet.
* Return pointer to start of MAC-header or NULL if no packets are
* queued.
*
* Not used when e.g. libpcap has set the `_eth_recv_hook' to
* do it's own packet-polling.
*/
static union link_Packet *poll_recv_queues (WORD *type)
{
static int which = 1; /* start polling IP-queue */
int loop;
ASSERT_PKT_INF (NULL);
#if defined(USE_DEBUG)
if (!pktq_check(&_pkt_inf->ip_queue))
{
fprintf (stderr, "%s: IP-queue destroyed!\n", __FILE__);
exit (-1);
}
if (!pktq_check(&_pkt_inf->arp_queue))
{
fprintf (stderr, "%s: ARP-queue destroyed!\n", __FILE__);
exit (-1);
}
#endif
for (loop = 0; loop < 2; loop++)
{
union link_Packet *pkt = which ? poll_ip_queue (type)
: poll_arp_queue (type);
which ^= 1;
if (pkt)
return (pkt);
}
return (NULL);
}
/*
* _eth_arrived() - poll for new packet (IP/ARP/RARP/PPPoE protocol)
* arrival. Sets protocol-type of packet received.
*
* For Ethernet/TokenRing-type drivers:
* The return value points past the MAC-header to the IP/ARP/RARP
* protocol header. Also check for link-layer broadcast.
*
* For PPP/SLIP-type drivers (MAC-less links):
* The return value points to the IP-packet itself.
* IP-protocol is assumed. Can never be link-layer broadcast.
*/
void *_eth_arrived (WORD *type, BOOL *brdcast)
{
union link_Packet *pkt;
BOOL bcast = FALSE;
void *ret = NULL;
if (_eth_recv_hook)
pkt = (union link_Packet*) (*_eth_recv_hook) (type);
else pkt = poll_recv_queues (type);
if (!pkt)
return (NULL);
/* If ip_handler() can't be reentered, only accept
* non-IP packets
*/
if (_ip_recursion && *type == IP_TYPE)
return (NULL);
if (_pktserial)
{
bcast = FALSE;
ret = (void*) &pkt->ip;
}
else if (_pktdevclass == PD_TOKEN)
{
bcast = (pkt->tok.head.destination[0] & 1);
ret = (void*) &pkt->tok.data;
}
else if (_pktdevclass == PD_FDDI)
{
bcast = (pkt->fddi.head.destination[0] & 1);
ret = (void*) &pkt->fddi.data;
}
else
{
bcast = (pkt->eth.head.destination[0] & 1);
ret = (void*) &pkt->eth.data;
}
if (intel16(*type) < ETH_MAX) /* LLC field */
{
STAT (macstats.num_llc_frames++);
#if 1
_eth_free (ret, *type);
return (NULL);
#else
/* !!to-do: handle IEEE 802.3 encapsulation also
*/
fix_llc_head (&ret);
#endif
}
update_in_stat (ret, *type);
if (brdcast)
*brdcast = bcast;
return (ret);
}
#if defined(USE_DEBUG)
/*
* Return pointer to MAC header start address of an IP packet.
*/
void *_eth_mac_hdr (const in_Header *ip)
{
if (!_pktserial)
return (void*) ((BYTE*)ip - _pkt_ip_ofs);
(*_printf) ("Illegal use of `_eth_mac_hdr()' for class %d\r\n",
_pktdevclass);
exit (-1);
/*@-unreachable@*/
return (NULL);
}
/*
* Return pointer to MAC source address of an IP packet.
*/
void *_eth_mac_src (const in_Header *ip)
{
const union link_Packet *pkt;
pkt = (const union link_Packet*) ((BYTE*)ip - _pkt_ip_ofs);
if (_pktdevclass == PD_ETHER)
return (void*) &pkt->eth.head.source;
if (_pktdevclass == PD_TOKEN)
return (void*) &pkt->tok.head.source;
if (_pktdevclass == PD_FDDI)
return (void*) &pkt->fddi.head.source;
(*_printf) ("Illegal use of `_eth_mac_src()' for class %d\r\n",
_pktdevclass);
exit (-1);
/*@-unreachable@*/
return (NULL);
}
/*
* Return value of protocol-type given an IP packet.
*/
WORD _eth_mac_typ (const in_Header *ip)
{
const union link_Packet *pkt;
pkt = (const union link_Packet*) ((BYTE*)ip - _pkt_ip_ofs);
if (_pktdevclass == PD_ETHER)
return (pkt->eth.head.type);
if (_pktdevclass == PD_TOKEN)
return (pkt->tok.head.type);
if (_pktdevclass == PD_FDDI)
return (pkt->fddi.head.type);
(*_printf) ("Illegal use of `_eth_mac_typ()' for class %d\r\n",
_pktdevclass);
exit (-1);
/*@-unreachable@*/
return (0);
}
#endif /* USE_DEBUG */
#if defined(USE_LOOPBACK)
/*
* _eth_send_loopback() - enqueue a link-layer frame (ip only)
* to the 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)
*/
int _eth_send_loopback (link_Packet pkt)
{
struct pkt_ringbuf *q;
const in_Header *ip;
int ip_len;
if (!_pkt_inf)
{
STAT (ipstats.ips_odropped++); /* maybe this should be an input counter */
return (0);
}
/* Call loopback handler with IP-packet
*/
ip = (in_Header*) ((BYTE*)&pkt + _pkt_ip_ofs);
ip_len = loopback_device ((in_Header*)ip);
q = &_pkt_inf->ip_queue;
if (!q || ip_len > ETH_MAX_DATA) /* !!should be MTU of current driver */
{
STAT (ipstats.ips_odropped++); /* maybe this should be an input counter */
return (0);
}
if (ip_len > 0)
{
union link_Packet *head;
/* Don't let pkt_receiver() modify the queue while testing/copying.
*/
DISABLE();
if (pktq_in_index(q) == q->out_index) /* queue is full, drop it */
{
STAT (ipstats.ips_odropped++);
q->num_drop++;
ENABLE();
return (0);
}
head = (union link_Packet*) pktq_in_buf (q);
/* Enqueue packet to head of input IP-queue.
*/
if (!_pktserial)
{
BYTE *data = (*mac_format) (head, &_eth_addr, IP_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();
}
return (ip_len + _pkt_ip_ofs);
}
#endif /* USE_LOOPBACK */
#if defined(USE_MULTICAST) /* Jim Martin's Multicast extensions */
/*
* _eth_join_mcast_group - joins a multicast group (at the physical layer)
*
* int _eth_join_mcast_group (int entry)
* Where:
* entry the entry # in the _ipmulti table
* Returns:
* 1 if the group was joined successfully
* 0 if attempt failed
*/
int _eth_join_mcast_group (int entry)
{
eth_address list [IPMULTI_SIZE];
int i, len, mode;
BYTE nextentry = 0;
/* initialize a few things
*/
_ipmulti[entry].active = 0;
_ipmulti[entry].replytime = set_timeout (0);
_ipmulti[entry].processes = 1;
/* Fill in the hardware address
*/
multi_to_eth (_ipmulti[entry].ina, (BYTE*)&_ipmulti[entry].ethaddr);
mode = _pkt_get_ip_rcv_mode();
if (mode == -1) /* something seems to be broken */
return (0);
if (mode == RM_MULTICAST2) /* we're already in all mcast mode */
{
_ipmulti[entry].active = 1;
return (1);
}
len = _pkt_get_multicast_list (sizeof(list), list);
if (len == -1)
return (0);
/* check to see if the address is already in the list
*/
for (i = 0; i < len/sizeof(list[0]); i++)
{
if (!memcmp(list[i], _ipmulti[entry].ethaddr, sizeof(list[0])))
{
_ipmulti[entry].active = 1;
return (1);
}
}
if (len)
nextentry = len / sizeof(list[0]);
memcpy (&list[nextentry], &_ipmulti[entry].ethaddr, sizeof(eth_address));
len += sizeof (list[0]);
if (_pkt_set_multicast_list(len,list) == -1)
{
if (_pkterror == NO_SPACE) /* out of space, switch mode */
{
if (_pkt_set_ip_rcv_mode(RM_MULTICAST2) == -1)
return (0);
}
else
return (0);
}
_ipmulti[entry].active = 1;
return (1);
}
/*
* _eth_leave_mcast_group - leaves a multicast group (at the physical layer)
*
* int _eth_leave_mcast_group (int entry)
* Where:
* entry the entry # in the _ipmulti table
* Returns:
* 1 if the group was left successfully
* 0 if attempt failed
*/
int _eth_leave_mcast_group (int entry)
{
eth_address list[IPMULTI_SIZE];
unsigned i;
int len, mode;
int ethindex = -1;
/* NOTE: This should be expanded to include switching back to mode 4
* if the list of multicast addresses has shrunk sufficiently.
*
* First check to see if we're in mode 5. if so, mark
* the entry as inactive and return.
*/
mode = _pkt_get_ip_rcv_mode();
if (mode == -1)
return (0);
if (mode == RM_MULTICAST2)
{
_ipmulti[entry].active = 0;
return (1);
}
/* get the list of current multicast addresses
*/
len = _pkt_get_multicast_list (sizeof(list), list);
if (len < 0)
return (0);
/* find the apropriate entry
*/
for (i = 0; i < len/sizeof(list[0]); i++)
if (!memcmp(list[i],_ipmulti[entry].ethaddr,sizeof(list[0])))
ethindex = i;
/* if it's not in the list, just set the entry inactive and return
*/
if (ethindex == -1)
{
_ipmulti[entry].active = 0;
return (1);
}
/* ahh, but it _is_ in the list. So shorten the list
* and send it back to the PD
*/
if (ethindex+1 < (int)(len/sizeof(list[0])))
movmem (&list[ethindex+1], &list[ethindex],
len-(ethindex+1)*sizeof(list[0]));
len -= sizeof (list[0]);
if (_pkt_set_multicast_list(len,&list[0]) == -1)
{
if (_pkterror == NO_SPACE) /* out of space, switch mode */
{
if (_pkt_set_ip_rcv_mode(RM_MULTICAST2) == -1)
return (0);
}
else
return (0);
}
_ipmulti[entry].active = 0;
return (1);
}
#endif /* USE_MULTICAST */
/*
* Turn off stack-checking because eth_release() might be called from
* exception handler.
*/
#if defined(__HIGHC__) || defined(__WATCOMC__)
#pragma Off(check_stack)
#endif
#if defined(__BORLANDC__)
#pragma option -N-
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -