* Copyright IBM Corporation 1987,1990
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation, and that the name of IBM not be
* used in advertising or publicity pertaining to distribution of the
* software without specific, written prior permission.
* IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
* ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR USE.
* IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
* @(#)if_un.eg 7.1 (Berkeley) %G%
* Ungermann-Bass PC-NIC (Ethernet) Adapter (4.3 driver)
#include "../machine/pte.h"
#include "../net/netisr.h"
#include "../net/route.h"
#include "../netinet/in.h"
#include "../netinet/in_systm.h"
#include "../netinet/in_var.h"
#include "../netinet/ip.h"
#include "../netinet/if_ether.h"
#include "../netns/ns_if.h"
#include "../netargo/if_clnp.h"
#include "../netargo/iso.h"
#include "../netargo/iso_var.h"
#include "../netargo/argo_debug.h"
#include "../machine/io.h"
#include "../machineio/ioccvar.h"
#include "../machine/debug.h"
int unprobe(), unattach();
caddr_t unstd[] = { (caddr_t) 0xa0000, (caddr_t) 0xa8000,
(caddr_t) 0xb0000, (caddr_t) 0xb8000, 0 };
caddr_t unstd[] = { (caddr_t) 0xf4080000, (caddr_t) 0xf4088000,
(caddr_t) 0xf4090000, (caddr_t) 0xf4098000, 0 };
struct iocc_device *uninfo[NUN];
int unint(), uninit(), unioctl(), unoutput(), unreset();
struct iocc_driver undriver =
{ unprobe, 0, unattach, 0, unstd, "un", uninfo,
0, 0, unint, UN_EADDROFF };
* Ethernet software status per adapter.
struct arpcom us_ac; /* generic network interface stuff */
#define us_if us_ac.ac_if /* ifnet struct */
#define us_addr us_ac.ac_enaddr /* hardware (i.e. ethernet) address */
short us_oactive; /* 1 => output active */
short us_nextpage; /* next receive buffer page */
short us_xbuf; /* in-use xmt buf (if output active) */
short us_xfull[2]; /* 1 => a full xmt buf */
short us_xstart[2]; /* start address used in unstart */
#define move_window(window, addr) {\
window = get_128_window();\
real_addr = 0xfffff & (int) addr;\
new_window = real_addr & 0xe0000;\
set_128_window(new_window);\
addr = (struct undevice *) (real_addr - new_window);\
#define restore_window(window) set_128_window(window)
#define bcopyin(from,to,len) bcopy((from)+pcif_128_fw,to,len)
#define bcopyout(from,to,len) bcopy(from,(to)+pcif_128_fw,len)
* unprobe - try to generate an interrupt (to see if the board is there)
register struct undevice *addr = (struct undevice *) p;
move_window(old_window, addr);
UN_GLOBIENB(0); /* global interrrupt enable */
MM_OUT(&addr->un_csr, UN_GSFTINT); /* generate software interrupt */
MM_OUT(&addr->un_csr, 0);
restore_window(old_window);
* unattach - make the interface available to the network software
* (if the auto-configuration software determines that the interface
* exists). The system will initialize the interface when it is
* ready to accept packets.
register struct iocc_device *iod;
register struct un_softc *us = &un_softc[iod->iod_unit];
register struct ifnet *ifp = &us->us_if;
register struct undevice *addr = (struct undevice *) iod->iod_addr;
move_window(old_window, addr);
ifp->if_unit = iod->iod_unit;
ifp->if_mtu = ETHERMTU - 3; /* 3 bytes for UI LLC frame */
* Read the ethernet address off the board.
* Save it and also write it to the edlc chip.
for (i = 0; i < ETH_ADDR_SIZE; i++){
us->us_addr[i] = MM_IN(&addr->un_eprom[UN_EADDROFF+i]);
MM_OUT(&addr->un_edlc.nodeID[i], us->us_addr[i]);
printf("un%d: ethernet address ", ifp->if_unit);
unprintethaddr(us->us_addr);
ifp->if_output = unoutput;
ifp->if_flags = IFF_BROADCAST;
ifp->if_flags |= IFF_EAVESDROP;
DEBUGF(undebug, printf("un%d: attached\n", iod->iod_unit);)
restore_window(old_window);
* unreset - reset interface
register unsigned int unit;
register struct iocc_device *iod;
if (unit < NUN && (iod = uninfo[unit]) != 0 && iod->iod_alive != 0){
un_softc[unit].us_if.if_flags &= ~IFF_RUNNING;
DEBUGF(undebug, printf("un%d: reset\n", unit);)
* uninit - initialize interface, enable packet reception, start any
register struct un_softc *us = &un_softc[unit];
register struct ifnet *ifp = &us->us_if;
register struct undevice *addr;
if (ifp->if_addrlist == (struct ifaddr *) 0){
if ((ifp->if_flags & IFF_RUNNING) == 0){
addr = (struct undevice *) (uninfo[unit]->iod_addr);
move_window(old_window, addr);
us->us_nextpage = unzap(addr); /* initialize hardware */
/* unzap returns next receive page to be used */
for (i = 0; i < ETH_ADDR_SIZE; i++){
MM_OUT(&addr->un_edlc.nodeID[i], us->us_addr[i]);
us->us_oactive = 0; /* output not active */
ifp->if_flags |= IFF_RUNNING;
MM_OUT(&addr->un_csr, UN_PAVIENB);
/* Allow packet available interrupts */
UN_GLOBIENB(us->us_nextpage); /* global interrrupt enable */
if (ifp->if_snd.ifq_head){ /* anything on send queue */
IF_DEQUEUE(&ifp->if_snd, m);
if (ifp->if_snd.ifq_head){
IF_DEQUEUE(&ifp->if_snd, m);
restore_window(old_window);
DEBUGF(undebug, printf("un%d: init'ed\n", unit);)
* unstart - start output from one of the adapter's 2 transmit buffers
register struct un_softc *us;
register struct undevice *addr;
UN_XMIT(addr, us->us_xstart[xbuf]);
MM_OUT(&addr->un_csr, UN_IENABLE); /* enable transmit done interrupt */
* unint - interrupt handler. find the cause of the interrupt and
* dispatch an appropriate handler routine.
register struct un_softc *us = &un_softc[unit];
register struct undevice *addr =
(struct undevice *) uninfo[unit]->iod_addr;
move_window(old_window, addr);
UN_DISABLE(us->us_nextpage);
while ((status = ~MM_IN(&addr->un_csr)) & UN_PAVINT){
DEBUGF(undebug & 0x2, printf("unint: unit = %d, csr = %b",
unit, status & 0xff, UN_CSRBITS);)
DEBUGF(undebug & 0x2, printf("unint: unit = %d, csr = %b",
unit, status & 0xff, UN_CSRBITS);)
UN_ENABLE(us->us_nextpage);
restore_window(old_window);
* unrint - interrupt handler for packet reception.
* log error if error bits are latched, examine packet to determine
* type, if can't determine packet length from type, drop packet.
* otherwise decapsulate packet based on type and pass to an appropriate
* higher-level input routine.
register struct un_softc *us;
register struct undevice *addr;
register struct ether_header *eh;
char status = MM_IN(&addr->un_edlc.rstat);
u_short ungetushortatoff();
struct ether_header ehbuf;
MM_OUT(&addr->un_edlc.rstat, status); /* clear status */
/* (the hardware xor's in the value of status setting rstat to 0) */
DEBUGF(undebug & 0x2, printf(" rstat = %b", status, RS_BITS);)
* Latch errors. (Errors found correspond to packets
* that were received prior to the current packet
* since packet available interrupts are generated
* for good packets only.)
DEBUGF(undebug, printf("unrint: input error\n");)
* determine the length of the received packet.
#define BUMP(page) if (++(page) == UN_NUMRBUFS) page = 0
while ((MM_IN(&addr->un_pram[us->us_nextpage]) & UN_LAST_PAGE) == 0){
len += (MM_IN(&addr->un_pram[us->us_nextpage]) &
UN_PAGE_LENGTH_MASK) + 1;
DEBUGF(undebug & 0x2, printf(" len = %d ", len);)
printf("un%d: huge packet!\n",unit);
eh = (struct ether_header *) &addr->un_rcvbuf[off][0];
bcopyin(eh->ether_shost, cbuf, sizeof(cbuf));
bcopyin(eh->ether_dhost, cbuf, sizeof(cbuf));
len -= sizeof(struct ether_header);
type = ntohs((u_short) MM_INW(&eh->ether_type));
* The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL
* have (type - ETHERTYPE_TRAIL) * 512 bytes of data followed by
* a type field and then a (variable length) header
if (type >= ETHERTYPE_TRAIL &&
type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER){
off = (type - ETHERTYPE_TRAIL) * 512;
type = ungetushortatoff(addr, eh, off);
resid = ungetushortatoff(addr, eh, off + 2);
/* may need ether_header for XID, TEST LLC functions */
* pull packet off interface. if off is non-zero, the
* packet has a trailing "header". unget will move this
* header to the front, but we still have to remove the
* type and length fields from the front of the data.
m = unget(addr, (char *) eh, len, off, &us->us_if);
* update the full page pointer and clear the packet available
* flag if necessary. update the fpp here to free the on-board
* receive pages as soon as possible.
unupdatefpp(addr, us->us_nextpage);
* Move snpa header over by 4 bytes to skip
* the trailer Type and Header length fields.
bcopy(mtod(m, char *), (caddr_t)&sh, sizeof(struct snpa_hdr));
m->m_off += 2 * sizeof(u_short);
m->m_len -= 2 * sizeof(u_short);
bcopy((caddr_t)&sh, mtod(m, char *), sizeof(struct snpa_hdr));
* bcopy is used since word moves must be on 4 byte
* boundaries on the RT PC
bcopy(mtod(m, char *), (char *) &ifp, sizeof(ifp));
m->m_off += 2 * sizeof(u_short);
m->m_len -= 2 * sizeof(u_short);
bcopy((char *) &ifp, mtod(m, char *), sizeof(ifp));
DEBUGF(undebug & 0x2, printf("ip packet\n");)
DEBUGF(undebug & 0x2, printf(" qfull\n");)
DEBUGF(undebug & 0x2, printf(" queued\n");)
DEBUGF(undebug & 0x2, printf("arp packet\n");)
arpinput(&us->us_ac, m); /* arpinput frees m */
DEBUGF(undebug & 0x2, printf("ns packet\n");)
case ETHERTYPE_CLNP: /* should be CLNL */
DEBUGF(undebug & 0x2, printf("clnl packet\n");)
/* IFF_EAVESDROP can not be turned off for Ethernet */
schednetisr(NETISR_CLNP);
DEBUGF(undebug & 0x2, printf(" qfull\n");)
DEBUGF(undebug & 0x2, printf(" queued\n");)
DEBUGF(undebug & 0x2, printf("unknown packet\n");)
#define PREPENDED_SIZE sizeof(struct snpa_hdr)
#define PREPENDED_SIZE sizeof(struct ifnet *)
* This assumes that the snpa header is in the same mbuf
* as the llc header. Currently this is ok, but if
* unget allocates a cluster, this will not be the case
pkt_start = mtod(m, caddr_t);
l = (struct llc *) (pkt_start + PREPENDED_SIZE);
printf("unrint: llc: length %d, control x%x:\n", type,
switch (l->llc_control) {
/* LLC_UI_P forbidden in class 1 service */
if (l->llc_dsap == LLC_ISO_LSAP) {
if ((IS_MULTICAST(ehbuf.ether_dhost)) &&
((us->us_if.if_flags & IFF_EAVESDROP) == 0) &&
(!snpac_ownmulti(ehbuf.ether_dhost, 6))) {
/* move struct snpa_header over the llc header */
clnp_ypocb(pkt_start, pkt_start + 3,
DEBUGF(undebug & 0x2, printf("clnp packet\n");)
schednetisr(NETISR_CLNP);
DEBUGF(undebug & 0x2, printf(" qfull\n");)
DEBUGF(undebug & 0x2, printf(" queued\n");)
printf("unrint: unknown llc sap\n");
/* LLC_XID, LLC_XID_P, LLC_TEST, and LLC_TEST_P are untested */
case LLC_XID_P: /* control field is untouched for resp */
l->llc_fid = LLC_IEEE_basic_format;
l->llc_class = LLC_CLASS1;
l->llc_dsap = l->llc_ssap = 0;
struct ifnet *ifp = &us->us_if;
struct sockaddr_iso siso;
l->llc_dsap = l->llc_ssap;
/* Do not TEST or XID to multicasts */
if (IS_MULTICAST(ehbuf.ether_dhost)) {
siso.siso_family = AF_ISO;
bcopy(ehbuf.ether_shost, siso.siso_addr.sna_idi, 6);
siso.siso_addr.isoa_afi = AFI_SNA;
siso.siso_addr.isoa_len = 7;
/* trim off prepended snpa_hdr or ifp */
m->m_off += PREPENDED_SIZE;
m->m_len -= PREPENDED_SIZE;
DEBUGF(undebug & 0x2, printf("unknown packet\n");)
DEBUGF(undebug, printf("unrint: packet dropped\n");)
unupdatefpp(addr, us->us_nextpage);
* unxint - interrupt handler for transmit ready
register struct un_softc *us;
register struct undevice *addr;
* collect stats on last packet
status = MM_IN(&addr->un_edlc.xstat);
MM_OUT(&addr->un_edlc.xstat, status); /* clear status bits */
DEBUGF(undebug & 0x2, printf(" unxint: xstat = %b\n",
status & 0xff, XS_BITS);)
us->us_if.if_collisions += 16;
printf("un%d: ethernet jammed\n", unit);
else if (status & XS_SHRT){
printf( "un%d: ethernet not responding (is it connected?)\n",
us->us_if.if_collisions += UN_NCOLL(addr);
printf(" ipkt = %d ierr = %d okt = %d oerr = %d coll = %d\n",
us->us_if.if_ipackets, us->us_if.if_ierrors,
us->us_if.if_opackets, us->us_if.if_oerrors,
us->us_if.if_collisions);)
/* mark the current transmit buffer empty */
us->us_xfull[us->us_xbuf] = 0;
/* switch to the other transmit buffer */
next_buf = 1 - us->us_xbuf;
if (us->us_xfull[next_buf]){ /* if it's full */
unstart(us, addr, next_buf); /* start output from it */
if (us->us_if.if_snd.ifq_head){ /* if more on out queue */
IF_DEQUEUE(&us->us_if.if_snd, m); /* fill empty buf */
unput(us, addr, m, 1 - next_buf);
else { /* the other transmit buffer is empty */
MM_OUT(&addr->un_csr, UN_PAVIENB); /* Turn off TxRIENB */
* unoutput - ethernet output routine. encapsulate a packet of type
* family for the local net. use trailer local net encapsulation if
* the number of bytes in the mbufs after the first is a multiple of
register struct ifnet *ifp;
register struct mbuf *m0;
register struct sockaddr *dst;
char edst[ETH_ADDR_SIZE];
register struct un_softc *us = &un_softc[ifp->if_unit];
register struct mbuf *m = m0;
register struct ether_header *eh;
if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)){
idst = ((struct sockaddr_in *)dst)->sin_addr;
if (!arpresolve(&us->us_ac, m, &idst, edst, &usetrailers)){
off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len;
if (usetrailers && off > 0 && (off & 0x1ff) == 0 &&
m->m_off >= MMINOFF + 2 * sizeof(u_short)){
type = ETHERTYPE_TRAIL + (off>>9);
m->m_off -= 2 * sizeof(u_short);
m->m_len += 2 * sizeof(u_short);
*mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP);
*(mtod(m, u_short *) + 1) = htons((u_short)m->m_len);
* Packet to be sent with trailer, move first packet
* (control information) to end of chain.
bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
(caddr_t)edst, sizeof(edst));
struct iso_addr *dst_nsap = &((struct sockaddr_iso *)dst)->siso_addr;
if ((ret = iso_tryloopback(m, dst)) >= 0)
else if (ret = iso_snparesolve(&us->us_ac.ac_if, dst_nsap, edst, &len)){
printf("unoutput: clnp packet dropped\n");
printf("unoutput: snpa len is not 6 (%d)\n", len);
/* check for enough space for LLC header */
if (m->m_off >= MMAXOFF || m->m_off < MMINOFF + 3) {
MGET(llcm, M_DONTWAIT, MT_DATA);
llcm->m_off = MMAXOFF - 3;
cp[0] = cp[1] = LLC_ISO_LSAP; cp[2] = LLC_UI;
printf("unoutput: sending pkt to: ");
printf("%x ", edst[i] & 0xff);
printf(" llc len %d", type);
eh = (struct ether_header *)dst->sa_data;
bcopy((char *)eh->ether_dhost, (caddr_t)edst, sizeof(edst));
printf("un%d: can't handle af%d\n", ifp->if_unit,
* Add local net header. If no space in first mbuf,
if (m->m_off > MMAXOFF ||
MMINOFF + sizeof(struct ether_header) > m->m_off){
m = m_get(M_DONTWAIT, MT_HEADER);
* Note: m_get, m_freem etc. guard against concurrent
* updates to the list of free mbufs.
m->m_len = sizeof(struct ether_header);
m->m_off -= sizeof(struct ether_header);
m->m_len += sizeof(struct ether_header);
eh = mtod(m, struct ether_header *);
bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof(edst));
bcopy((caddr_t)us->us_addr, (caddr_t)eh->ether_shost,
sizeof(eh->ether_shost));
bcopy((caddr_t)&type, (caddr_t)&eh->ether_type, sizeof(u_short));
* queue packet for transmission. if there is an empty
* transmit buffer on the adapter, use it.
if (IF_QFULL(&ifp->if_snd)){
if (us->us_xfull[0] == 0 || us->us_xfull[1] == 0){ /* empty xmt buf */
struct undevice *addr = (struct undevice *)
uninfo[ifp->if_unit]->iod_addr;
move_window(old_window, addr);
if (us->us_xfull[0] == 0){
unput(us, addr, m, next_buf);
if (us->us_oactive == 0){
unstart(us, addr, next_buf);
restore_window(old_window);
IF_ENQUEUE(&ifp->if_snd, m);
* unput - copy packet from an mbuf chain to one of the adapter's
* transmit buffers. the packet is extended to the minimum legal
* size if necessary. the extra bytes could be zeroed out to improve
* security but are not to maximize performance.
register struct mbuf *mp;
* compute starting address in transmit buffer. packets must be
for (off = UN_XBSIZE, mp = m; mp; mp = mp->m_next){
if (UN_XBSIZE - off < ETHERMIN + sizeof(struct ether_header)){
/* packet too short => extend it */
off = UN_XBSIZE - ETHERMIN - sizeof(struct ether_header);
if (xbuf == 1){ /* use the second buffer */
off += UN_XBSIZE; /* the 2 buffers are adjacent */
bp = ((char *)(addr->un_xmtbuf)) + off;
for (mp = m; mp; mp = mp->m_next){
register unsigned len = mp->m_len;
bcopyout(mtod(mp, char *), bp, len);
/* save starting address so interrupt handler can find it */
us->us_xstart[xbuf] = off; /* start address to be passed to adapter */
us->us_xfull[xbuf] = 1; /* mark buffer full */
* unget - copy packet from adapter's receive buffers into a chain of mbufs
unget(addr, unbuf, totlen, off0, ifp)
register struct mbuf **mp = ⊤
cp = unbuf + sizeof(struct ether_header);
MGET(m, M_DONTWAIT, MT_DATA);
if (off){ /* trailer exists */
cp = unbuf + sizeof(struct ether_header) + off;
len += sizeof(struct snpa_hdr);
m->m_len = len = MIN(len, CLBYTES);
m->m_len = len = MIN(MLEN, len);
m->m_len = len = MIN(MLEN, len);
* Prepend snpa_hdr to first mbuf
* The hardcoded 12 below refers to the length of the dhost
* and shost fields. We recklessly assume
* the order of dhost,shost in the snpa_hdr is the same
* as the order in the ether_header.
struct snpa_hdr *sh = (struct snpa_hdr *)mcp;
struct ether_header *eh = (struct ether_header *)unbuf;
bcopy((char *) &ifp, (caddr_t)&sh->snh_ifp, sizeof(ifp));
bcopy((caddr_t)eh, (caddr_t)sh->snh_dhost, 12);
mcp += sizeof(struct snpa_hdr);
len -= sizeof(struct snpa_hdr);
/* prepend ifp to first mbuf */
* bcopy is used since since word moves must
* be on 4 byte boundaries on the RT PC
bcopy((char *) &ifp, mcp, sizeof(ifp));
ifp = (struct ifnet *) 0;
unbcopy(addr, cp, mcp, len);
cp = unbuf + sizeof(struct ether_header);
* ioctl - process an ioctl request.
register struct ifnet *ifp;
register struct ifaddr *ifa = (struct ifaddr *)data;
register int s = splimp();
switch (ifa->ifa_addr.sa_family){
uninit(ifp->if_unit); /* before arpwhohas */
((struct arpcom *) ifp)->ac_ipaddr =
arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr);
struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr);
struct un_softc *us = &un_softc[ifp->if_unit];
ina->x_host = *(union ns_host *)(us->us_addr);
ifp->if_flags &= ~IFF_RUNNING;
bcopy((caddr_t) ina->x_host.c_host,
(caddr_t) us->us_addr, sizeof(us->us_addr));
* the uninit will set the hardware address
* since the IFF_RUNNING flag is off
if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags &
addr = (struct undevice *) uninfo[ifp->if_unit]->
move_window(old_window, addr);
(void) unzap((struct undevice *) addr);
ifp->if_flags &= ~IFF_RUNNING;
restore_window(old_window);
} else if (ifp->if_flags & IFF_UP && (ifp->if_flags &
* unzap - initialize adapter but don't enable it.
* returns page number of next receive page to be used.
register struct undevice *addr;
MM_OUT(&addr->un_csr, 0); /* disable interrupts */
MM_OUT(&addr->un_edlc.reset, RESET_ON);
/* set reset bit while init'ing */
MM_OUT(&addr->un_edlc.rstat, RS_CLEAR);
MM_OUT(&addr->un_edlc.xstat, XS_CLEAR);
MM_OUT(&addr->un_edlc.rmask, 0);
MM_OUT(&addr->un_edlc.xmask, 0);
MM_OUT(&addr->un_edlc.rmode, RM_NORMAL);
* the next line puts the transmitter in loopback mode so
* that a spurious packet is not sent when the reset bit is
MM_OUT(&addr->un_edlc.tmode, TM_NORMAL - TM_LBC);
MM_OUT(&addr->un_edlc.reset, RESET_OFF); /* clear reset bit */
* clear the receive buffers. assign the value in the empty
* page pointer to the full page pointer and clear the packet
next = MM_IN(&addr->un_fppepp) & UN_PAGE_MASK;
/* clears the IKSYDK flag */
MM_OUT(&addr->un_fppepp, next); /* fpp = epp */
UN_CLRPAV(addr); /* clear the PAV flag */
MM_OUT(&addr->un_edlc.tmode, TM_NORMAL);
/* put transmitter in normal mode */
DEBUGF(undebug & 0x2, printf("unzap: zzzzapped!\n");)
* unupdatefpp - update adapter's full page pointer and clear packet available
unupdatefpp(addr, nextpage)
register struct undevice *addr;
if (nextpage == /* EPP */ (MM_IN(&addr->un_fppepp) & UN_PAGE_MASK))
MM_OUT(&addr->un_fppepp, nextpage); /* set FPP */
* unbcopy - similar to bcopy but can deal with packets that wrap
* around from the high end of the adapter's receive buffer to the
unbcopy(addr, from, to, len)
register struct undevice *addr;
register char *high_end = &addr->un_rcvbuf[UN_LASTRBUF][UN_RBUFSIZE];
if (from + len <= high_end){
else if (from >= high_end){
from -= sizeof(addr->un_rcvbuf);
bcopyin((char *)addr->un_rcvbuf, to, len - n);
* ungetushortatoff - return the u_short at offset in the received packet,
* handling wrap-around in the receive buffer and conversion between network
* and host formats as necessary.
u_short ungetushortatoff(addr, eh, off)
register struct undevice *addr;
register struct ether_header *eh;
register char *high_end = &addr->un_rcvbuf[UN_LASTRBUF][UN_RBUFSIZE];
p = (caddr_t)(eh + 1) + off;
p -= sizeof(addr->un_rcvbuf);
return(ntohs((u_short) MM_INW(p)));
* unprintethaddr - print an ethernet address
for (i = 0; i < ETH_ADDR_SIZE; i++){