if_nic.c
上传用户:luoyougen
上传日期:2008-05-12
资源大小:23136k
文件大小:40k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* if_nic.c - National Semiconductor SNIC Chip (for HKV30) network interface driver */
  2. /* Copyright 1984-1997 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02b,15jul97,spm  added ARP request to SIOCSIFADDR ioctl handler
  8. 02a,07apr97,spm  code cleanup, corrected statistics, and upgraded to BSD 4.4
  9. 01z,11aug93,jmm  Changed ioctl.h and socket.h to sys/ioctl.h and sys/socket.h
  10. 01y,19feb93,jdi  documentation cleanup.
  11. 01x,15oct92,rfs  Added documentation.
  12. 01w,02oct92,rfs  Made multiple attach calls per unit return OK.
  13. 01v,09sep92,gae  documentation tweaks.
  14. 01u,02sep92,ajm  added conditional compilation for __STDC__ (DEC)
  15. 01t,18aug92,rfs  Revised to follow style of other drivers.
  16.                  Added cache support.  Reworked OVW error recovery.
  17. 01s,23jun92,ajm  fixed ansi warnings for pktBufRead calls
  18.                  went back and fixed all 68k ansi warnings
  19. 01r,26may92,rrr  the tree shuffle
  20.                  -changed includes to have absolute path from h/
  21. 01q,26may92,ajm  got rid of HOST_DEC def's (new compiler)
  22.                  updated copyright
  23. 01p,10oct91,rfs  modified pktBufRead() & pktBufWrite() to return if len is zero
  24. 01o,04oct91,rrr  passed through the ansification filter
  25.                  -changed functions to ansi style
  26.                  -changed includes to have absolute path from h/
  27.                  -changed VOID to void
  28.                  -changed copyright notice
  29. 01n,28sep91,ajm  ifdef'd HOST_DEC for compiler problem
  30. 01m,02Aug91,rfs  cleanup of transmit design, int handler, NIC command register
  31.                  was being handled incorrectly, DMA operations required
  32.                  semaphoring and error checking, changed names, deleted
  33.                  nicdelay(), deleted excessive include files. Provided correct
  34.                  OVW recovery.  Your basic rewrite.
  35. 01l,01may91,elh  fixed transmit buffering problems, added changes from
  36.                  heurikon, removed DMAState, XmtByteCount.
  37. 01k,20sep90,dab  made nicInit() return int.
  38. 01j,10aug90,dnw  added forward declarations of void routines.
  39.                  added include of if_subr.h.
  40. 01i,11jul90,hjb  removed code that uses gotIp.  made nicRead() a void function.
  41.                  changed references to do_protocol() to use
  42.                  do_protocol_with_type().
  43. 01h,19apr90,hjb  deleted param.h, de-linted.
  44. 01g,18mar90,hjb  reduction of redundant code and addition of cluster support.
  45.                  added error recording (TXE, RXE), removed unnecessary
  46.                  error handler which didn't do anything.  delinted.
  47. 01f,18sep89,cwp  added multiple transmit buffer support
  48. 01e,14sep89,dab  changed iv68k.h to iv.h.
  49. 01d,15jun89,cwp  fixed ring buffer overflow and transmit errors.
  50. 01c,04apr89,cwp  first working version.
  51. 01b,25feb89,cwp  added changes from unix driver.
  52. 01a,12jan89,cwp  written.
  53. */
  54. /*
  55. This module implements the National Semiconductor 83901 SNIC Ethernet network 
  56. interface driver.
  57. This driver is non-generic and is for use on the Heurikon HKV30 board.  
  58. Only unit number zero is supported.  The driver must be given several 
  59. target-specific parameters.  These parameters, and the mechanisms 
  60. used to communicate them to the driver, are detailed below.
  61. BOARD LAYOUT
  62. This device is on-board.  No jumpering diagram is necessary.
  63. EXTERNAL INTERFACE
  64. This driver provides the standard external interface with the following
  65. exceptions.  All initialization is performed within the attach routine; there
  66. is no separate initialization routine.  Therefore, in the global interface
  67. structure, the function pointer to the initialization routine is NULL.
  68. The only user-callable routine is nicattach(), which publishes the `nic'
  69. interface and initializes the driver and device.
  70. TARGET-SPECIFIC PARAMETERS
  71. .iP "device I/O address"
  72. This parameter is passed to the driver by nicattach().
  73. It specifies the base address of the device's I/O register
  74. set.
  75. .iP "interrupt vector"
  76. This parameter is passed to the driver by nicattach().
  77. It specifies the interrupt vector to be used by the driver
  78. to service an interrupt from the SNIC device.  The driver will connect
  79. the interrupt handler to this vector by calling intConnect().
  80. .LP
  81. SYSTEM RESOURCE USAGE
  82. When implemented, this driver requires the following system resources:
  83.     - one mutual exclusion semaphore
  84.     - one interrupt vector
  85.     - 0 bytes in the initialized data section (data)
  86.     - 1702 bytes in the uninitialized data section (BSS)
  87. The above data and BSS requirements are for the MC68020 architecture 
  88. and may vary for other architectures.  Code size (text) varies greatly between
  89. architectures and is therefore not quoted here.
  90. The HKV30 provides a private buffer for all packets transmitted and received.
  91. Thus, the driver does not require any system memory to share with the
  92. device.  This also eliminates all data cache coherency issues.
  93. SEE ALSO: ifLib
  94. */
  95. #include "vxWorks.h"
  96. #include "iv.h"
  97. #include "stdlib.h"
  98. #include "intLib.h"
  99. #include "netLib.h"
  100. #include "net/mbuf.h"
  101. #include "sys/ioctl.h"
  102. #include "errno.h"
  103. #include "net/if.h"
  104. #include "net/unixLib.h"
  105. #include "net/if_subr.h"
  106. #include "netinet/in_var.h"
  107. #include "netinet/if_ether.h"
  108. #include "etherLib.h"
  109. #include "semLib.h"
  110. #include "cacheLib.h"
  111. #include "drv/netif/if_nic.h"
  112. #include "drv/dma/we32104.h"
  113. /***** LOCAL DEFINITIONS *****/
  114. #define MAX_UNITS      1                     /* max number of units supported */
  115. #define NIC_DCR_CS      DCR_CS_2                /* device #2 on DMAC PBUS */
  116. #define NIC_DCR_PA      0x60                    /* device addr on DMAC PBUS */
  117. /* Typedefs for external structures that are not typedef'd in their .h files */
  118. typedef struct mbuf MBUF;
  119. typedef struct arpcom IDR;                  /* Interface Data Record wrapper */
  120. typedef struct ifnet IFNET;                 /* real Interface Data Record */
  121. typedef struct sockaddr SOCK;
  122. typedef struct ether_header ETH_HDR;
  123. #ifdef BSD43_DRIVER
  124. #define ENET_HDR_REAL_SIZ   14
  125. #endif
  126. typedef struct rx_hdr
  127.     {
  128.     u_char status;                              /* status of packet */
  129.     u_char nextRxPage;                          /* page next pkt starts at */
  130.     u_char cntL;                                /* low byte of frame length */
  131.     u_char cntH;                                /* high byte of frame length */
  132.     } RX_HDR;
  133. #define RX_HDR_SIZ      sizeof(RX_HDR)
  134. typedef struct rx_frame
  135.     {
  136.     RX_HDR rxHdr;                               /* the receive status header */
  137.     ETH_HDR enetHdr;                            /* the Ethernet header */
  138.     u_char data [ETHERMTU];                     /* the data */
  139.     u_long fcs;
  140.     } RX_FRAME;
  141. #define RX_FRAME_SIZ        sizeof(RX_FRAME)
  142. typedef struct tx_desc
  143.     {
  144.     volatile BOOL ready;                        /* ready for transmission */
  145.     unsigned short addr;                        /* addr in NIC buffer */
  146.     unsigned short len;                         /* length of packet */
  147.     struct tx_desc *next;                       /* link to next descriptor */
  148.     } TX_DESC;
  149. #define TX_DESC_SIZ     sizeof(TX_DESC)
  150. /* The driver control structure. */
  151. typedef struct drv_ctrl
  152.     {
  153.     IDR                 idr;                /* interface data record */
  154.     BOOL                attached;           /* indicates unit is attached */
  155.     int                 nicIntVec;          /* interrupt vector */
  156.     SEM_ID              dmaSem;             /* exclusive use of DMA units */
  157.     u_char              NextPkt;            /* NIC buf page for next pkt */
  158.     volatile BOOL       dmaWait;            /* waiting for DMA completion */
  159.     volatile BOOL       taskRcvActive;      /* indicates netTask in use */
  160.     NIC_DEVICE          *nicAddr;           /* address of NIC chip */
  161.     volatile TX_DESC    *pTxActive;         /* ptr to Tx desc in use */
  162.     TX_DESC             *pTxNext;           /* ptr to next Tx desc to use */
  163.     TX_DESC             txDesc [MAXXMT];    /* array of Tx descriptors */
  164.     RX_FRAME            rxFrame;            /* storage for one Rx frame */
  165.     } DRV_CTRL;
  166. #define DRV_CTRL_SIZ       sizeof(DRV_CTRL)
  167. /* array of driver control structs, one per unit supported */
  168. LOCAL DRV_CTRL drvCtrl [MAX_UNITS];
  169. /* forward static functions */
  170. static void nicReset (int unit);
  171. static void nicIntr (int unit);
  172. static void nicRestart (int unit);
  173. static void nicHandleInt (DRV_CTRL *pDrvCtrl);
  174. static BOOL nicRead (DRV_CTRL *pDrvCtrl);
  175. #ifdef BSD43_DRIVER
  176. static int nicOutput (IDR *pIDR, MBUF *pMbuf, SOCK *pDest);
  177. #else
  178. static int nicTxStartup (DRV_CTRL *pDrvCtrl);
  179. #endif
  180. static int nicIoctl (IDR *pIDR, int cmd, caddr_t data);
  181. static void nicEnetAddrGet (int unit);
  182. static void nicConfig (int unit);
  183. static STATUS pktBufWrite (DRV_CTRL *pDrvCtrl, u_long nicBufAddr,
  184.                            u_long len, char *pData);
  185. static STATUS pktBufRead (DRV_CTRL *pDrvCtrl, u_long nicBufAddr,
  186.                           u_long len, char *pData);
  187. #ifdef BSD43_DRIVER
  188. static BOOL convertDestAddr (IDR *pIDR, SOCK *pDestSktAddr,
  189.                              char *pDestEnetAddr, u_short *pPacketType,
  190.                              MBUF *pMbuf);
  191. #endif
  192. /*******************************************************************************
  193. *
  194. * nicattach - publish the `nic' network interface and initialize the driver and device
  195. *
  196. * This routine publishes the `nic' interface by filling in a network interface
  197. * record and adding this record to the system list.  It also
  198. * initializes the driver and the device to the operational state.
  199. *
  200. * RETURNS: OK or ERROR.
  201. */
  202. STATUS nicattach
  203.     (
  204.     int unit,                                 /* unit number */
  205.     NIC_DEVICE *pNic,                         /* address of NIC chip */
  206.     int ivec                                  /* interrupt vector to use */
  207.     )
  208.     {
  209.     int         temp;
  210.     int         loopy;
  211.     WE32104     *pDmac;
  212.     DRV_CTRL    *pDrvCtrl;
  213.     /* Sanity check the unit number */
  214.     if (unit < 0 || unit >= MAX_UNITS)
  215.         return (ERROR);
  216.     /* Ensure single invocation per system life */
  217.     pDrvCtrl = & drvCtrl [unit];
  218.     if (pDrvCtrl->attached)
  219.         return (OK);
  220.     pDrvCtrl->dmaSem = semBCreate(SEM_Q_FIFO, SEM_FULL);
  221.     pDrvCtrl->nicAddr = pNic;
  222.     pDrvCtrl->nicIntVec = ivec;
  223.     /* Publish the interface data record */
  224. #ifdef BSD43_DRIVER
  225.     ether_attach    (
  226.                     &pDrvCtrl->idr.ac_if,
  227.                     unit,
  228.                     "nic",
  229.                     (FUNCPTR) NULL,
  230.                     (FUNCPTR) nicIoctl,
  231.                     (FUNCPTR) nicOutput,
  232.                     (FUNCPTR) nicReset
  233.                     );
  234. #else
  235.     ether_attach (
  236.                  &pDrvCtrl->idr.ac_if,
  237.                  unit,
  238.                  "nic",
  239.                  (FUNCPTR) NULL,
  240.                  (FUNCPTR) nicIoctl,
  241.                  (FUNCPTR) ether_output, 
  242.                  (FUNCPTR) nicReset
  243.                  );
  244.     pDrvCtrl->idr.ac_if.if_start = (FUNCPTR)nicTxStartup;
  245. #endif
  246.     /*
  247.      * Fill in the Tx descriptors.
  248.      * Note that the address in the NIC buffer must be on a 256 byte boundary,
  249.      * since only the upper 8 bits are fed to the device when telling it
  250.      * to transmit.
  251.      */
  252.     for (loopy = 0; loopy < MAXXMT; loopy++)
  253.         {
  254.         /* addr in NIC buf */
  255.         pDrvCtrl->txDesc[loopy].addr = XMTBUF + (loopy * 0x600);
  256.         /* point to next */
  257.         pDrvCtrl->txDesc[loopy].next = & pDrvCtrl->txDesc [loopy+1];
  258.         pDrvCtrl->txDesc[loopy].ready = FALSE;
  259.         }
  260.     pDrvCtrl->txDesc[MAXXMT-1].next = pDrvCtrl->txDesc;    /* point to first */
  261.     /* Connect the interrupt handler */
  262.     (void) intConnect (INUM_TO_IVEC (ivec), nicIntr, 0);
  263.     pDrvCtrl->pTxNext = pDrvCtrl->txDesc;          /* reset "next Tx" ptr */
  264.     pDrvCtrl->pTxActive = NULL;                    /* no active Tx desc */
  265.     pDrvCtrl->taskRcvActive = FALSE;               /* reset flag */
  266.     pDrvCtrl->NextPkt = CURR;                      /* reset to initial value */
  267.     /* The WE32104 controls all access to the peripheral buss. It allows the
  268.      * CPU "transparent" access to the devices on that buss. Before this
  269.      * access is allowed, the WE32104 must be told device control info. The
  270.      * following line sets up the channel 2 device control register to
  271.      * correctly access the NIC. These values are obtained from the HKV30
  272.      * manual.
  273.      */
  274.     pDmac = (WE32104 *) DMA_BASE;
  275.     pDmac->Ch2.DevControl = NIC_DCR_CS | NIC_DCR_PA;
  276.     pDmac->Mask = pDmac->Mask & ~MASK_CH2;      /* allow channel 2 requests */
  277.     temp = RESET_ON;                            /* Issue a hardware reset */
  278.     temp = RESET_OFF;                           /* release the reset */
  279.     temp = LED_OFF;                             /* the 'U' LED on XE module */
  280.     while (!(pNic->Isr & RST))                  /* wait for reset done */
  281.         ;
  282.     nicConfig (unit);                              /* configure the device */
  283.     /* Raise the interface flags */
  284.     pDrvCtrl->idr.ac_if.if_flags |= IFF_UP | IFF_RUNNING | IFF_NOTRAILERS;
  285.     /* Set our flag */
  286.     pDrvCtrl->attached = TRUE;
  287.     temp = LED_ON;                      /* turn XE module LED on */
  288.     return (OK);
  289.     }
  290. /*******************************************************************************
  291. *
  292. * nicReset - reset of interface
  293. */
  294. LOCAL void nicReset
  295.     (
  296.     int unit
  297.     )
  298.     {
  299.     int         temp;
  300.     DRV_CTRL    *pDrvCtrl;
  301.     pDrvCtrl = & drvCtrl [unit];
  302.     pDrvCtrl->idr.ac_if.if_flags = 0;
  303.     temp = RESET_ON;                            /* Issue a hardware reset */
  304.     temp = LED_OFF;                             /* the 'U' LED on XE module */
  305.     }
  306. /*******************************************************************************
  307. *
  308. * nicIntr - The driver's interrupt handler
  309. *
  310. * This function clears the cause of the device interrupt(s) and then acts
  311. * on the individual possible causes.  The primary goal of this routine is to
  312. * minimize the time spent in it.  This is accomplished by deferring processing
  313. * to the netTask via the netJobAdd() function.
  314. *
  315. * A secondary goal is to keep the transmitter working, if there are more
  316. * frames ready to be sent.  This is done examining flags set by the task level
  317. * code that indicates ready frames.  The transmitter is flagged as "idle" if
  318. * it appears that there are no frames ready to send.
  319. *
  320. * Note that in case the receiver overruns, we promptly mark the interface as
  321. * "down" and then leave only the RDC interrupt enabled.  This is in case netTask
  322. * is in the midst of DMA activity, we must allow it to complete.  The receive
  323. * handler will give up when it discovers the interface is down, which will
  324. * then allow netTask to run our OVW handler.  This provides a nice orderly
  325. * error recovery, even though the crummy NIC requires complete re-init.
  326. */
  327. LOCAL void nicIntr
  328.     (
  329.     int unit
  330.     )
  331.     {
  332.     DRV_CTRL *pDrvCtrl;
  333.     NIC_DEVICE *pNic;
  334.     TX_DESC *pTxDesc;
  335.     unsigned char isr;                            /* copy of ISR */
  336.     unsigned char tsr;                            /* copy of TSR */
  337.     pDrvCtrl = & drvCtrl [unit];
  338.     pNic = pDrvCtrl->nicAddr;
  339.     isr = pNic->Isr;                              /* copy the ISR */
  340.     pNic->Isr = isr;                              /* ACK all the ints */
  341.     /* handle receiver overrun */
  342.     if  (
  343.         (isr & OVW) &&
  344.         (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING))
  345.         )
  346.         {
  347.         pNic->Imr = RDCE;                       /* disable all but RDC intrs */
  348.         pDrvCtrl->idr.ac_if.if_flags &=                 /* flag as down */
  349.             ~(IFF_UP | IFF_RUNNING | IFF_PROMISC);
  350.         /* Place our restart routine on the netTask queue */
  351.         netJobAdd ((FUNCPTR) nicRestart, unit, 0, 0, 0, 0);
  352.         return;                     /* no sense continuing */
  353.         }
  354.     /* handle packet Tx error */
  355.     if (isr & TXE)
  356.         {
  357.         pDrvCtrl->idr.ac_if.if_opackets--;
  358.         pDrvCtrl->idr.ac_if.if_oerrors++;
  359.         }
  360.     /* handle packet received */
  361.     if  ((isr & PRX) &&
  362.         (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) &&
  363.         (!pDrvCtrl->taskRcvActive))
  364.         {
  365.         pDrvCtrl->taskRcvActive = TRUE;                 /* set flag */
  366.         /* defer to netTask */
  367.         netJobAdd ((FUNCPTR) nicHandleInt, (int) pDrvCtrl, 0, 0, 0, 0);
  368.         }
  369.     /* handle packet transmitted */
  370.     if  ((isr & PTX) &&
  371.         (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) &&
  372.                                                 /* copy ptr, safety check it */
  373.         ((pTxDesc = (TX_DESC *) pDrvCtrl->pTxActive) != NULL))
  374.         {
  375.         tsr = pNic->Tsr;                          /* read Tx status reg */
  376.         pTxDesc->ready = FALSE;                   /* active pkt completed */
  377.         if (pTxDesc->next->ready)                 /* if next pkt ready to go */
  378.             {
  379.             pTxDesc = pTxDesc->next;              /* use next desc */
  380.             pDrvCtrl->pTxActive = pTxDesc;        /* update active ptr */
  381.             pNic->Tpsr = pTxDesc->addr >> 8;
  382.             pNic->Tbcr0 = pTxDesc->len & 0xff;
  383.             pNic->Tbcr1 = pTxDesc->len >> 8;
  384.             /* Start NIC transmitting. Note that since we could be doing
  385.              * a NIC remote DMA transfer at this time, we must maintain the
  386.              * state of these bits.
  387.              */
  388.             pNic->Cr = TXP | (pNic->Cr & (RREAD | RWRITE));
  389.             }
  390.         else
  391.             pDrvCtrl->pTxActive = NULL;             /* transmitter idle */
  392.         if (tsr & COL)                              /* collision */
  393.             pDrvCtrl->idr.ac_if.if_collisions++;
  394.         }
  395.     /* handle DMA complete */
  396.     if (isr & RDC)
  397.         pDrvCtrl->dmaWait = FALSE;                  /* clr the waiting flag */
  398.     }
  399. /*******************************************************************************
  400. *
  401. * nicRestart - restart the device after fatal error
  402. */
  403. LOCAL void nicRestart
  404.     (
  405.     int unit
  406.     )
  407.     {
  408.     int         temp;
  409.     int         loopy;
  410.     DRV_CTRL    *pDrvCtrl;
  411.     NIC_DEVICE  *pNic;                         /* address of device */
  412.     pDrvCtrl = & drvCtrl [unit];
  413.     pNic = pDrvCtrl->nicAddr;
  414.     /* The device has all interrupts disabled and the interface flags are down.
  415.      * Our job is to reset the device and our dynamic driver variables,
  416.      * bring the device back to life, and put the interface online.
  417.      */
  418.     temp = RESET_ON;                            /* Issue a hardware reset */
  419.     temp = RESET_OFF;                           /* release the reset */
  420.     /* Wait for device reset indication */
  421.     while ( ! (pNic->Isr & RST) )
  422.         ;
  423.     pNic->Cr = RPAGE0 | STP;                    /* select page 0 and stop */
  424.     pNic->Dcr = NOTLS | FIFO8;
  425.     pNic->Rbcr0 = 0;                /* clear remote DMA byte count registers */
  426.     pNic->Rbcr1 = 0;
  427.     for (loopy = 0; loopy < MAXXMT; loopy++)
  428.         pDrvCtrl->txDesc[loopy].ready = FALSE;
  429.     pDrvCtrl->pTxNext = pDrvCtrl->txDesc;          /* reset "next Tx" ptr */
  430.     pDrvCtrl->pTxActive = NULL;                    /* no active Tx desc */
  431.     pDrvCtrl->taskRcvActive = FALSE;               /* reset flag */
  432.     pDrvCtrl->NextPkt = CURR;                      /* reset to initial value */
  433.     pNic->Rcr = AB;         /* accept broadcast, but not runt or multicast */
  434.     pNic->Tcr = MODE1;                          /* internal loopback mode */
  435.     pNic->Pstart = PSTART;
  436.     pNic->Pstop  = PSTOP;
  437.     pNic->Bnry   = BNRY;
  438.     pNic->Cr   = RPAGE1;                        /* map in page 1 */
  439.     pNic->Par0 = pDrvCtrl->idr.ac_enaddr [0];
  440.     pNic->Par1 = pDrvCtrl->idr.ac_enaddr [1];
  441.     pNic->Par2 = pDrvCtrl->idr.ac_enaddr [2];
  442.     pNic->Par3 = pDrvCtrl->idr.ac_enaddr [3];
  443.     pNic->Par4 = pDrvCtrl->idr.ac_enaddr [4];
  444.     pNic->Par5 = pDrvCtrl->idr.ac_enaddr [5];
  445.     pNic->nic_pg1.mar0 = 0xff;
  446.     pNic->nic_pg1.mar1 = 0xff;
  447.     pNic->nic_pg1.mar2 = 0xff;
  448.     pNic->nic_pg1.mar3 = 0xff;
  449.     pNic->nic_pg1.mar4 = 0xff;
  450.     pNic->nic_pg1.mar5 = 0xff;
  451.     pNic->nic_pg1.mar6 = 0xff;
  452.     pNic->nic_pg1.mar7 = 0xff;
  453.     pNic->Curr = CURR;
  454.     pNic->Cr = RPAGE0;                          /* back to page 0 */
  455.     pNic->Tcr = MODE0;                          /* put Tx into normal mode */
  456.     pNic->Cr = STA;                             /* start the beast running */
  457.     pNic->Isr = 0xff;                           /* clr any pending ints */
  458.     pNic->Imr = PRXE|PTXE|TXEE|OVWE|RDCE;       /* enable these ints */
  459.     /* Raise the interface flags */
  460.     pDrvCtrl->idr.ac_if.if_flags |= IFF_UP | IFF_RUNNING | IFF_NOTRAILERS;
  461.     }
  462. /*******************************************************************************
  463. *
  464. * nicHandleInt - defered recv interrupt handler
  465. *
  466. * This function handles the received frames from the device.  It runs in the
  467. * context of the netTask, which was triggered by a received packet interrupt.
  468. */
  469. LOCAL void nicHandleInt
  470.     (
  471.     DRV_CTRL *pDrvCtrl
  472.     )
  473.     {
  474.     do
  475.         {
  476.         pDrvCtrl->taskRcvActive = TRUE;
  477.         while (nicRead (pDrvCtrl))            /* process a received frame */
  478.             ;
  479.         pDrvCtrl->taskRcvActive = FALSE;
  480.         } while (nicRead (pDrvCtrl));
  481.     }
  482. /*******************************************************************************
  483. *
  484. * nicRead - read a packet off the interface
  485. *
  486. * nicRead copies packets from local memory into an mbuf and hands it to
  487. * the next higher layer.
  488. */
  489. LOCAL BOOL nicRead
  490.     (
  491.     DRV_CTRL *pDrvCtrl
  492.     )
  493.     {
  494.     MBUF *m;
  495.     NIC_DEVICE *pNic;                      /* ptr to the NIC registers */
  496.     RX_FRAME *pRxFrame;                    /* ptr to our frame storage */
  497.     ETH_HDR *eh;                                /* ptr to enet hdr */
  498.     u_int len;                                  /* length of the enet pkt */
  499.     u_short curr;                               /* current page NIC using */
  500.     int oldLevel;
  501.     if (!(pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)))
  502.         return (FALSE);
  503.     pNic = pDrvCtrl->nicAddr;
  504.     pRxFrame = &pDrvCtrl->rxFrame;
  505.     eh = &pRxFrame->enetHdr;
  506.     /*
  507.      * See if any unprocessed frames in NIC buffer. Unfortunately, there
  508.      * is no reliable way of doing this other than reading the CURR register.
  509.      * The NIC designers, in their infinite wisdom, put this register in
  510.      * page 1. To access page 1, we need to temporarily disable our interrupt
  511.      * handler.
  512.      */
  513.     oldLevel = intLock ();
  514.     pNic->Cr = RPAGE1;                              /* select page 1 */
  515.     curr = pNic->Curr;                              /* get current page */
  516.     pNic->Cr = RPAGE0;                              /* restore page 0 */
  517.     intUnlock (oldLevel);
  518.     if (pDrvCtrl->NextPkt == curr)             /* if NIC has not moved ahead */
  519.         return (FALSE);
  520.     pDrvCtrl->idr.ac_if.if_ipackets++;
  521.     /*
  522.      * OK, there is work to be done.
  523.      * First we copy the NIC receive status header from the NIC buffer
  524.      * into our local area. This is done so that we can obtain the length
  525.      * of the packet before copying out the rest of it. Note that the length
  526.      * field in the NIC header includes the Ethernet header, the data, and
  527.      * the 4 byte FCS field.
  528.      */
  529.     while   (
  530.             pktBufRead  (
  531.                         pDrvCtrl,
  532.                         pDrvCtrl->NextPkt << 8,
  533.                         RX_HDR_SIZ,
  534.                         (char *) pRxFrame
  535.                         )
  536.             == ERROR
  537.             )
  538.         ;
  539.     len = pRxFrame->rxHdr.cntL + (pRxFrame->rxHdr.cntH << 8) - 4 /* FCS */;
  540. #if 0   /* valid frame checks, for paranoia */
  541.     if  (
  542.         ((pRxFrame->rxHdr.status & ~PHY) != PRX) ||
  543.         (pRxFrame->rxHdr.nextRxPage < PSTART) ||
  544.         (pRxFrame->rxHdr.nextRxPage >= PSTOP) ||
  545.         (len < 60) || (len > 1514)
  546.         )
  547.         return (FALSE);
  548. #endif
  549.     /* copy Ethernet packet section of the frame */
  550.     while   (
  551.             pktBufRead  (
  552.                         pDrvCtrl,
  553.                         (pDrvCtrl->NextPkt << 8) + RX_HDR_SIZ,
  554.                         len,
  555.                         (char *) eh
  556.                         )
  557.             == ERROR
  558.             )
  559.         ;
  560.     /* done with frame in NIC buf, so update vars */
  561.     pDrvCtrl->NextPkt = pRxFrame->rxHdr.nextRxPage;/* where dev will use next */
  562.     pNic->Bnry = (pDrvCtrl->NextPkt == PSTART) ?   /* if dev is at beginning */
  563.                 (PSTOP - 1) :                     /* boundary is 1 before end */
  564.                 (pDrvCtrl->NextPkt - 1);           /* else it's 1 before next */
  565.     /* call input hook if any */
  566.     if (etherInputHookRtn != NULL)
  567.         if  ( (* etherInputHookRtn) (&pDrvCtrl->idr.ac_if, (char *)eh, len))
  568.             return (TRUE);
  569.     len -= sizeof (ETH_HDR);            /* now equals length of data only */
  570.     m = copy_to_mbufs   (
  571.                         pRxFrame->data,
  572.                         len,
  573.                         0,
  574.                         (IFNET *) & pDrvCtrl->idr.ac_if
  575.                         );
  576.     if (m != NULL)
  577. #ifdef BSD43_DRIVER
  578.         do_protocol_with_type (eh->ether_type, m, &pDrvCtrl->idr, len);
  579. #else
  580.         do_protocol (eh, m, &pDrvCtrl->idr, len);
  581. #endif
  582.     else
  583.         pDrvCtrl->idr.ac_if.if_ierrors++;
  584.     return (TRUE);
  585.     }
  586. #ifdef BSD43_DRIVER
  587. /*******************************************************************************
  588. *
  589. * nicOutput - the driver's output routine
  590. *
  591. * This function attempts to copy the data from the mbuf chain to the buffer
  592. * that NIC transmits from.  If successfull, and the NIC is not currently busy
  593. * transmitting, it then attempts to start the NIC transmitting.
  594. */
  595. LOCAL int nicOutput
  596.     (
  597.     IDR  *pIDR,
  598.     MBUF *pMbuf,
  599.     SOCK *pDest
  600.     )
  601.     {
  602.     int         unit;
  603.     int         oldLevel;
  604.     u_long      nicBufAddr;
  605.     MBUF        *pTempMbuf;
  606.     DRV_CTRL    *pDrvCtrl;
  607.     NIC_DEVICE  *pNic;
  608.     TX_DESC     *pTxNext;                   /* ptr to next desc to use */
  609.     ETH_HDR     enetHdr;                    /* space for the packet header */
  610.     /* init ptrs */
  611.     unit = pIDR->ac_if.if_unit;
  612.     pDrvCtrl = & drvCtrl [unit];
  613.     pNic = pDrvCtrl->nicAddr;          /* copy it, due to frequent use */
  614.     /* Check ifnet flags. Return error if incorrect. */
  615.     if  (
  616.         (pIDR->ac_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
  617.         (IFF_UP | IFF_RUNNING)
  618.         )
  619.         {
  620.         m_freem (pMbuf);                /* release MBUFs */
  621.         return (ENETDOWN);
  622.         }
  623.     /* Attempt to convert socket addr into enet addr and packet type.
  624.      * Note that if ARP resolution of the address is required, the ARP
  625.      * module will call our routine again to transmit the ARP request
  626.      * packet.  This means we may actually call ourselves recursively!
  627.      */
  628.     if  (
  629.         convertDestAddr (
  630.                         pIDR,
  631.                         pDest,
  632.                         &enetHdr.ether_dhost,     /* fill our local header */
  633.                         &enetHdr.ether_type, /* fill our local header */
  634.                         pMbuf
  635.                         )
  636.         == FALSE
  637.         )
  638.         return (OK);
  639.     /* Get next transmit resource */
  640.     pTxNext = pDrvCtrl->pTxNext;        /* copy it, due to frequent use */
  641.     if (pTxNext->ready)                 /* if still in use */
  642.         {
  643.         m_freem (pMbuf);                /* release MBUFs */
  644.         return (ENETDOWN);
  645.         }
  646.     /* Fill in the source address of the Ethernet header */
  647.     bcopy ( (char *) pIDR->ac_enaddr, &enetHdr.ether_shost, 6 );
  648.     /* copy Ethernet header to NIC buffer */
  649.     nicBufAddr = pTxNext->addr;
  650.     while   (
  651.             pktBufWrite (
  652.                         pDrvCtrl,
  653.                         nicBufAddr,
  654.                         ENET_HDR_REAL_SIZ,
  655.                         (char *) & enetHdr
  656.                         )
  657.             == ERROR
  658.             )
  659.             ;
  660.     /* copy mbufs to NIC buffer */
  661.     pTempMbuf = pMbuf;                      /* copy head of MBUF chain */
  662.     for (
  663.         nicBufAddr += (u_long) ENET_HDR_REAL_SIZ;
  664.         pTempMbuf != NULL;
  665.         nicBufAddr += (u_long) pTempMbuf->m_len, pTempMbuf = pTempMbuf->m_next)
  666.         {
  667.         while
  668.             (
  669.             pktBufWrite (
  670.                         pDrvCtrl,
  671.                         nicBufAddr,
  672.                         pTempMbuf->m_len,
  673.                         mtod (pTempMbuf, caddr_t)
  674.                         )
  675.             == ERROR
  676.             )
  677.             ;
  678.         }
  679.     pTxNext->len = max (MINPKTSIZE, (nicBufAddr - pTxNext->addr));
  680.     m_freem (pMbuf);                       /* free the mbufs */
  681.     oldLevel = intLock ();                 /* keep our int handler out */
  682.     pTxNext->ready = TRUE;                 /* mark packet as "ready" */
  683.     if (pDrvCtrl->pTxActive == NULL)       /* if transmitter not active */
  684.         {
  685.         pDrvCtrl->pTxActive = pTxNext;           /* set active ptr */
  686.         pNic->Tpsr = pTxNext->addr >> 8;
  687.         pNic->Tbcr0 = pTxNext->len & 0xff;
  688.         pNic->Tbcr1 = pTxNext->len >> 8;
  689.         pNic->Cr = TXP;                    /* start NIC transmitting */
  690.         }
  691.     pDrvCtrl->pTxNext = pTxNext->next;     /* move ptr to next desc */
  692.     intUnlock (oldLevel);                  /* allow interrupts again */
  693.     /* Bump packet counter */
  694.     pIDR->ac_if.if_opackets++;
  695.     return (0);
  696.     }
  697. #else
  698. /*******************************************************************************
  699. *
  700. * nicTxStartup - the driver's output routine
  701. *
  702. * This function attempts to copy the data from the mbuf chain to the buffer
  703. * that NIC transmits from.  If successful, and the NIC is not currently busy
  704. * transmitting, it then attempts to start the NIC transmitting.
  705. */
  706. LOCAL int nicTxStartup
  707.     (
  708.     DRV_CTRL *  pDrvCtrl  /* pointer to driver control structure */
  709.     )
  710.     {
  711.     MBUF *  pMbuf;
  712.     int         oldLevel;
  713.     u_long      nicBufAddr;
  714.     MBUF        *pTempMbuf;
  715.     NIC_DEVICE  *pNic;
  716.     TX_DESC     *pTxNext;                   /* ptr to next desc to use */
  717.     pNic = pDrvCtrl->nicAddr;          /* copy it, due to frequent use */
  718.     /* Get next transmit resource */
  719.     while (pDrvCtrl->idr.ac_if.if_snd.ifq_head)
  720.         {
  721.         /* Dequeue a packet from the transmit queue. */
  722.  
  723.         IF_DEQUEUE (&pDrvCtrl->idr.ac_if.if_snd, pMbuf);
  724.         pTxNext = pDrvCtrl->pTxNext;        /* copy it, due to frequent use */
  725.         if (pTxNext->ready)                 /* if still in use */
  726.             {
  727.             m_freem (pMbuf);                /* release MBUFs */
  728.             pDrvCtrl->idr.ac_if.if_oerrors++;
  729.             break;
  730.             }
  731.         /* copy mbufs to NIC buffer */
  732.         pTempMbuf = pMbuf;                      /* copy head of MBUF chain */
  733.         nicBufAddr = pTxNext->addr;
  734.         while (pTempMbuf != NULL)
  735.             {
  736.             while (pktBufWrite (pDrvCtrl, nicBufAddr, pTempMbuf->m_len,
  737.                                 mtod (pTempMbuf, caddr_t))
  738.                    == ERROR)
  739.                 ;
  740.             nicBufAddr += (u_long) pTempMbuf->m_len;
  741.             pTempMbuf = pTempMbuf->m_next;
  742.             }
  743.         pTxNext->len = max (MINPKTSIZE, (nicBufAddr - pTxNext->addr));
  744.         m_freem (pMbuf);                       /* free the mbufs */
  745.         oldLevel = intLock ();                 /* keep our int handler out */
  746.         pTxNext->ready = TRUE;                 /* mark packet as "ready" */
  747.         if (pDrvCtrl->pTxActive == NULL)       /* if transmitter not active */
  748.             {
  749.             pDrvCtrl->pTxActive = pTxNext;           /* set active ptr */
  750.             pNic->Tpsr = pTxNext->addr >> 8;
  751.             pNic->Tbcr0 = pTxNext->len & 0xff;
  752.             pNic->Tbcr1 = pTxNext->len >> 8;
  753.             pNic->Cr = TXP;                    /* start NIC transmitting */
  754.             }
  755.         pDrvCtrl->pTxNext = pTxNext->next;     /* move ptr to next desc */
  756.         intUnlock (oldLevel);                  /* allow interrupts again */
  757.         /* Bump packet counter */
  758.         pDrvCtrl->idr.ac_if.if_opackets++;
  759.         }
  760.     return (0);
  761.     }
  762. #endif
  763. /*******************************************************************************
  764. *
  765. * nicIoctl - the driver's I/O control routine
  766. *
  767. */
  768. LOCAL int nicIoctl
  769.     (
  770.     IDR *pIDR,
  771.     int cmd,
  772.     caddr_t data
  773.     )
  774.     {
  775.     int error;
  776.     error = 0;
  777.     switch (cmd)
  778.         {
  779.         case SIOCSIFADDR:
  780.             ((struct arpcom *)pIDR)->ac_ipaddr = IA_SIN (data)->sin_addr;
  781.             arpwhohas (pIDR, &IA_SIN (data)->sin_addr);
  782.             break;
  783.         case SIOCSIFFLAGS:
  784.             /* Flags are set outside this module. No additional work to do. */
  785.             break;
  786.         default:
  787.             error = EINVAL;
  788.         }
  789.     return (error);
  790.     }
  791. /*******************************************************************************
  792. *
  793. * nicEnetAddrGet - get hardwired Ethernet address.
  794. *
  795. * Read the Ethernet address out of the ROM
  796. */
  797. LOCAL void nicEnetAddrGet
  798.     (
  799.     int unit
  800.     )
  801.     {
  802.     DRV_CTRL *pDrvCtrl = & drvCtrl [unit];
  803.     NIC_DEVICE *pNic = pDrvCtrl->nicAddr;
  804.     int i;
  805.     pNic->Rsar0 = 0;                            /* ID ROM starts at 0 */
  806.     pNic->Rsar1 = 0;
  807.     pNic->Rbcr0 = 6;                            /* length of enet addr */
  808.     pNic->Rbcr1 = 0;
  809.     pNic->Cr = RREAD;                           /* Start NIC Remote DMA */
  810.     for (i = 0; i < 6; i++)
  811.         {
  812.         while (pNic->Rsar0 == i)            /* wait for byte available */
  813.             ;
  814.         pDrvCtrl->idr.ac_enaddr [i] = *NIC_BUF_PORT;  /* read byte from port */
  815.         }
  816.     }
  817. /*******************************************************************************
  818. *
  819. * nicConfig - configure the NIC chip for Ethernet and program address
  820. */
  821. LOCAL void nicConfig
  822.     (
  823.     int unit
  824.     )
  825.     {
  826.     DRV_CTRL *pDrvCtrl = & drvCtrl [unit];
  827.     NIC_DEVICE *pNic = pDrvCtrl->nicAddr;
  828.     pNic->Cr = RPAGE0 | STP;                    /* select page 0 and stop */
  829.     pNic->Dcr = NOTLS | FIFO8;
  830.     pNic->Rbcr0 = 0;                /* clear remote DMA byte count registers */
  831.     pNic->Rbcr1 = 0;
  832.     pNic->Rcr = AB;         /* accept broadcast, but not runt or multicast */
  833.     pNic->Tcr = MODE1;                          /* internal loopback mode */
  834.     pNic->Pstart = PSTART;
  835.     pNic->Pstop  = PSTOP;
  836.     pNic->Bnry   = BNRY;
  837.     nicEnetAddrGet (unit);                      /* Get Ethernet address */
  838.     /* set up page 1 registers */
  839.     pNic->Cr   = RPAGE1;
  840.     pNic->Par0 = pDrvCtrl->idr.ac_enaddr [0];
  841.     pNic->Par1 = pDrvCtrl->idr.ac_enaddr [1];
  842.     pNic->Par2 = pDrvCtrl->idr.ac_enaddr [2];
  843.     pNic->Par3 = pDrvCtrl->idr.ac_enaddr [3];
  844.     pNic->Par4 = pDrvCtrl->idr.ac_enaddr [4];
  845.     pNic->Par5 = pDrvCtrl->idr.ac_enaddr [5];
  846.     pNic->nic_pg1.mar0 = 0xff;
  847.     pNic->nic_pg1.mar1 = 0xff;
  848.     pNic->nic_pg1.mar2 = 0xff;
  849.     pNic->nic_pg1.mar3 = 0xff;
  850.     pNic->nic_pg1.mar4 = 0xff;
  851.     pNic->nic_pg1.mar5 = 0xff;
  852.     pNic->nic_pg1.mar6 = 0xff;
  853.     pNic->nic_pg1.mar7 = 0xff;
  854.     pNic->Curr = CURR;
  855.     pNic->Cr = RPAGE0;                          /* back to page 0 */
  856.     pNic->Tcr = MODE0;                          /* put Tx into normal mode */
  857.     pNic->Cr = STA;                             /* start the beast running */
  858.     pNic->Isr = 0xff;                           /* clr any pending ints */
  859.     pNic->Imr = PRXE|PTXE|TXEE|OVWE|RDCE;       /* enable these ints */
  860.     }
  861. /*******************************************************************************
  862. *
  863. * pktBufWrite - write data to NIC buffer
  864. */
  865. LOCAL STATUS pktBufWrite
  866.     (
  867.     DRV_CTRL *pDrvCtrl,
  868.     unsigned long nicBufAddr,
  869.     unsigned long len,
  870.     char *pData
  871.     )
  872.     {
  873.     NIC_DEVICE *pNic;
  874.     WE32104 *pDmac;
  875.     STATUS status;
  876.     if (len == 0)                                       /* nothing to do */
  877.         return (OK);
  878.     pNic = pDrvCtrl->nicAddr;
  879.     pDmac = (WE32104 *) DMA_BASE;
  880.     semTake(pDrvCtrl->dmaSem, WAIT_FOREVER);           /* obtain semaphore */
  881.     pDrvCtrl->dmaWait = TRUE;                          /* set our flag */
  882.     /* set up NIC remote DMA transfer */
  883.     pNic->Rsar0 = nicBufAddr;
  884.     pNic->Rsar1 = nicBufAddr >> 8;
  885.     pNic->Rbcr0 = len;
  886.     pNic->Rbcr1 = len >> 8;
  887.     /* set up main DMAC transfer */
  888.     cacheFlush (DATA_CACHE, pData, len);            /* ensure coherency */
  889.     pDmac->Ch2.SourceAdd = (unsigned long) pData;
  890.     pDmac->Ch2.TranCount = len;
  891.     pDmac->Ch2.Mode = MODE_TT_MP | MODE_DS_LONG | MODE_BR;
  892.     /* start both devices doing the transfer */
  893.     pDmac->Ch2.StatCont = SCR_STR;
  894.     pNic->Cr = RWRITE;
  895.     /* wait for interrupt handler to clear our flag */
  896.     while (pDrvCtrl->dmaWait)
  897.         {
  898.         if  (
  899.             (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
  900.             (IFF_UP | IFF_RUNNING)
  901.             )
  902.             {
  903.             pDrvCtrl->dmaWait = FALSE;
  904.             pDmac->Ch2.StatCont = SCR_SA;               /* abort */
  905.             semGive(pDrvCtrl->dmaSem);                  /* release the sem */
  906.             return (OK);                                /* this is correct */
  907.             }
  908.         }
  909.     /* check for DMAC error */
  910.     if(pDmac->Ch2.StatCont & SCR_ACT)
  911.         {
  912.         pDmac->Ch2.StatCont = SCR_SA;               /* abort */
  913.         status = ERROR;
  914.         }
  915.     else
  916.         status = OK;
  917.     semGive(pDrvCtrl->dmaSem);
  918.     return (status);
  919.     }
  920. /*******************************************************************************
  921. *
  922. * pktBufRead - read data from NIC buffer
  923. */
  924. LOCAL STATUS pktBufRead
  925.     (
  926.     DRV_CTRL *pDrvCtrl,
  927.     unsigned long nicBufAddr,
  928.     unsigned long len,
  929.     char *pData
  930.     )
  931.     {
  932.     NIC_DEVICE *pNic;
  933.     WE32104 *pDmac;
  934.     STATUS status;
  935.     if (len == 0)                                       /* nothing to do */
  936.         return (OK);
  937.     /* Avoid starting DMA if device is down to to fatal error */
  938.     if  (
  939.         (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
  940.         (IFF_UP | IFF_RUNNING)
  941.         )
  942.         return (OK);
  943.     pNic = pDrvCtrl->nicAddr;
  944.     pDmac = (WE32104 *) DMA_BASE;
  945.     semTake(pDrvCtrl->dmaSem, WAIT_FOREVER);            /* obtain semaphore */
  946.     pDrvCtrl->dmaWait = TRUE;                           /* set our flag */
  947.     /* set up NIC remote DMA transfer */
  948.     pNic->Rsar0 = nicBufAddr;
  949.     pNic->Rsar1 = nicBufAddr >> 8;
  950.     pNic->Rbcr0 = len;
  951.     pNic->Rbcr1 = len >> 8;
  952.     /* set up main DMAC transfer */
  953.     pDmac->Ch2.DestAdd = (unsigned long) pData;
  954.     pDmac->Ch2.TranCount = len;
  955.     pDmac->Ch2.Mode = MODE_TT_PM | MODE_DS_LONG | MODE_BR;
  956.     /* start both devices doing the transfer */
  957.     pDmac->Ch2.StatCont = SCR_STR;
  958.     pNic->Cr = RREAD;
  959.     /* wait for interrupt handler to clear our flag */
  960.     while (pDrvCtrl->dmaWait)
  961.         {
  962.         if  (
  963.             (pDrvCtrl->idr.ac_if.if_flags & (IFF_UP | IFF_RUNNING)) !=
  964.             (IFF_UP | IFF_RUNNING)
  965.             )
  966.             {
  967.             pDrvCtrl->dmaWait = FALSE;
  968.             pDmac->Ch2.StatCont = SCR_SA;               /* abort */
  969.             semGive(pDrvCtrl->dmaSem);                  /* release the sem */
  970.             return (OK);                                /* this is correct */
  971.             }
  972.         }
  973.     /* check for DMAC error */
  974.     if(pDmac->Ch2.StatCont & SCR_ACT)
  975.         {
  976.         pDmac->Ch2.StatCont = SCR_SA;               /* abort */
  977.         status = ERROR;
  978.         }
  979.     else
  980.         {
  981.         cacheInvalidate (DATA_CACHE, pData, len);   /* ensure coherency */
  982.         status = OK;
  983.         }
  984.     semGive(pDrvCtrl->dmaSem);
  985.     return (status);
  986.     }
  987. #ifdef BSD43_DRIVER
  988. #include "sys/socket.h"
  989. /*******************************************************************************
  990. *
  991. * convertDestAddr - converts socket addr into enet addr and packet type
  992. *
  993. */
  994. static BOOL convertDestAddr
  995.     (
  996.     IDR *pIDR,                          /* ptr to i/f data record */
  997.     SOCK *pDestSktAddr,                 /* ptr to a generic sock addr */
  998.     char *pDestEnetAddr,                /* where to write enet addr */
  999.     u_short *pPacketType,               /* where to write packet type */
  1000.     MBUF *pMbuf                         /* ptr to mbuf data */
  1001.     )
  1002.     {
  1003. #ifdef __STDC__
  1004.     extern arpresolve   (               /* we call this */
  1005.                         IDR *,
  1006.                         MBUF *,
  1007.                         struct in_addr *,
  1008.                         char *,
  1009.                         int *
  1010.                         );
  1011. #else /* __STDC__ */
  1012.     extern arpresolve   ();
  1013. #endif /* __STDC__ */
  1014.     /***** Internet family *****/
  1015.     {
  1016.     struct in_addr destIPAddr;              /* not used */
  1017.     int trailers;                           /* not supported */
  1018.      if (pDestSktAddr->sa_family == AF_INET)
  1019.         {
  1020.         *pPacketType = ETHERTYPE_IP;            /* stuff packet type */
  1021.         destIPAddr = ((struct sockaddr_in *) pDestSktAddr)->sin_addr;
  1022.         if (!arpresolve (pIDR, pMbuf, &destIPAddr, pDestEnetAddr, &trailers))
  1023.             return (FALSE);     /* if not yet resolved */
  1024.         return (TRUE);
  1025.         }
  1026.     }
  1027.     /***** Generic family *****/
  1028.     {
  1029.     ETH_HDR *pEnetHdr;
  1030.     if (pDestSktAddr->sa_family == AF_UNSPEC)
  1031.         {
  1032.         pEnetHdr = (ETH_HDR *) pDestSktAddr->sa_data;      /* ptr to hdr */
  1033.         bcopy (pEnetHdr->dst, pDestEnetAddr, 6);            /* copy dst addr */
  1034.         *pPacketType = pEnetHdr->ether_type;                /* copy type */
  1035.         return (TRUE);
  1036.         }
  1037.     }
  1038.     /* Unsupported family */
  1039.     return (FALSE);
  1040.     }
  1041. #endif