/* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Gregory McGarry.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* For some reason the proms won't pass arp responses back to us. I
* have checked if the first parameter to bootread/bootwrite do anything
* but it doesn't appear so. Therefore, we stop the upper layers from
* sending arp requests in the first place, by monitoring packets which
* come in and filling the arp cache ourselves. - gmcgarry
*/
#ifdef FILL_ARPCACHE
struct arp_list {
struct in_addr addr;
u_char ea[6];
};
extern struct arp_list arp_list[8];
extern int arp_num;
void fill_arpcache(void *, int);
#endif
if (sc_fd < 0)
printf("problem initialising device\n");
}
int
prom_put(struct iodesc *desc, void *pkt, size_t len)
{
int s;
DPRINTF(("prom_put: called\n"));
#ifdef NET_DEBUG
if (debug)
dump_packet_info(pkt,len);
#endif
if (callv == &callvec)
s = prom_write(sc_fd, pkt, len);
else {
s = (*callv->_bootwrite)(0, pkt, len);
(*callv->_wbflush)(); /* didn't really make a difference */
}
if (s < 0)
return EIO;
return s;
}
int
prom_get(struct iodesc *desc, void *pkt, size_t len, saseconds_t timeout)
{
int s;
satime_t t;
DPRINTF(("prom_get: called\n"));
t = getsecs();
s = 0;
while (((getsecs() - t) < timeout) && !s) {
if (callv == &callvec)
s = prom_read(sc_fd, pkt, len);
else
s = (*callv->_bootread)(0, pkt, len);
}
#ifdef FILL_ARPCACHE
if (s > 0)
fill_arpcache(pkt,s);
#endif
return s;
}
void
prom_end(struct netif *nif)
{
DPRINTF(("prom_end: called\n"));
if (callv == &callvec)
prom_close(sc_fd);
}
#ifdef FILL_ARPCACHE
void
fill_arpcache(void *pkt, int len)
{
int i;
struct arp_list *al;
struct ether_header *eh = (struct ether_header *)pkt;
struct ip *ih = (struct ip *)(eh + 1);
#ifdef NET_DEBUG
if (debug)
dump_packet_info(pkt, len);
#endif
if (ntohs(eh->ether_type) == 0x0800) {
/* check arp cache */
for (i=0, al=arp_list; i<arp_num; ++i, ++al) {
if (al->addr.s_addr == ih->ip_src.s_addr) {
/* already in cache */
return;
}
}
if (arp_num > 7)
arp_num = 1; /* recycle */
al->addr.s_addr = ih->ip_src.s_addr;
for (i = 0; i < 6; i++)
al->ea[i] = eh->ether_shost[i];
++arp_num;
}
}
#endif
#ifdef NET_DEBUG
void
dump_packet_info(void *pkt, int len)
{
struct ether_header *eh = (struct ether_header *)pkt;
struct ip *ih = (struct ip *)(eh + 1);