⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pcpkt.c

📁 开放源码的编译器open watcom 1.6.0版的源代码
💻 C
📖 第 1 页 / 共 4 页
字号:

      case PD_ETHER:
           _pkt_ip_ofs = sizeof(eth_Header);
           break;

      case PD_FDDI:
           _pkt_ip_ofs = sizeof(fddi_Header);
           break;

      case PD_SLIP:
      case PD_PPP:
           _pkt_ip_ofs = 0;
           break;

      default:
           outs (_LANG("ERROR: Unsupported driver class "));
           outhex ((char)_pktdevclass);
           outsnl ("");
           return (0);
    }
  }
  _pktserial = (_pktdevclass == PD_SLIP ||
                _pktdevclass == PD_PPP);
  _pkt_inf->is_serial = _pktserial;
  return (1);
}


/**************************************************************************/

#include <sys/packon.h>

static struct {
       BYTE  major_rev;      /* Revision of Packet Driver spec */
       BYTE  minor_rev;      /*  this driver conforms to. */
       BYTE  length;         /* Length of structure in bytes */
       BYTE  addr_len;       /* Length of a MAC-layer address */
       WORD  mtu;            /* MTU, including MAC headers */
       WORD  multicast_aval; /* Buffer size for multicast addr */
       WORD  rcv_bufs;       /* (# of back-to-back MTU rcvs) - 1 */
       WORD  xmt_bufs;       /* (# of successive xmits) - 1 */
       WORD  int_num;        /* interrupt for post-EOI processing */
     } pkt_params;

#include <sys/packoff.h>

static BOOL got_params = FALSE;

static int pkt_get_params (void)
{
  IREGS regs;

  regs.r_ax = PD_GET_PARAM;  /* get driver parameters */
  if (!PKT_API(&regs))
     return (0);

#if (DOSX & PHARLAP)
  {
    REALPTR rp;
    RP_SET (rp, (WORD)regs.r_di, regs.r_es);
    ReadRealMem (&pkt_params, rp, sizeof(pkt_params));
  }

#elif (DOSX & DJGPP)
  dosmemget (regs.r_di + (regs.r_es << 4), sizeof(pkt_params), &pkt_params);

#elif (DOSX & (DOS4GW|WDOSX))
  memcpy (&pkt_params, SEG_OFS_TO_LIN(regs.r_es,regs.r_di), sizeof(pkt_params));

#elif (DOSX & POWERPAK)
  UNFINISHED();

#else
  _fmemcpy (&pkt_params, MK_FP(regs.r_es,regs.r_di), sizeof(pkt_params));
#endif

  got_params = TRUE;
  return (1);
}

int pkt_get_mtu (void)
{
  if (got_params)
     return (pkt_params.mtu);
  return (-1);
}

int pkt_get_mac_len (void)
{
  if (got_params)
     return (pkt_params.addr_len);
  return (-1);
}

int pkt_get_drvr_ver (void)
{
  if (got_params)
     return ((pkt_params.major_rev << 8) + pkt_params.minor_rev);
  return (-1);
}

/**************************************************************************/


#if (DOSX == 0) && defined(USE_DEBUG)
/*
 *  Some paranoia checks for real-targets; if our IREGS structure
 *  doesn't match REGPACK of the C-lib, intr() will probably cause a
 *  crash. Better safe than sorry..
 */
static int check_reg_struct (void)
{
#define OffsetOf(x) (unsigned)&(x)

#if defined(_MSC_VER)  /* We made our own intr(), hence no need to do this */
  return (1);

#elif defined(__WATCOMC__)
  union  REGPACK *r1 = NULL;
  struct IREGS   *r2 = NULL;

  if ((OffsetOf(r1->w.ax)    != OffsetOf(r2->r_ax)) ||
      (OffsetOf(r1->w.bx)    != OffsetOf(r2->r_bx)) ||
      (OffsetOf(r1->w.cx)    != OffsetOf(r2->r_cx)) ||
      (OffsetOf(r1->w.dx)    != OffsetOf(r2->r_dx)) ||
      (OffsetOf(r1->w.bp)    != OffsetOf(r2->r_bp)) ||
      (OffsetOf(r1->w.si)    != OffsetOf(r2->r_si)) ||
      (OffsetOf(r1->w.di)    != OffsetOf(r2->r_di)) ||
      (OffsetOf(r1->w.ds)    != OffsetOf(r2->r_ds)) ||
      (OffsetOf(r1->w.es)    != OffsetOf(r2->r_es)) ||
      (OffsetOf(r1->x.flags) != OffsetOf(r2->r_flags)))
    return (0);

#else  /* Borland */
  struct REGPACK *r1 = NULL;
  struct IREGS   *r2 = NULL;

  if ((OffsetOf(r1->r_ax)    != OffsetOf(r2->r_ax)) ||
      (OffsetOf(r1->r_bx)    != OffsetOf(r2->r_bx)) ||
      (OffsetOf(r1->r_cx)    != OffsetOf(r2->r_cx)) ||
      (OffsetOf(r1->r_dx)    != OffsetOf(r2->r_dx)) ||
      (OffsetOf(r1->r_bp)    != OffsetOf(r2->r_bp)) ||
      (OffsetOf(r1->r_si)    != OffsetOf(r2->r_si)) ||
      (OffsetOf(r1->r_di)    != OffsetOf(r2->r_di)) ||
      (OffsetOf(r1->r_ds)    != OffsetOf(r2->r_ds)) ||
      (OffsetOf(r1->r_es)    != OffsetOf(r2->r_es)) ||
      (OffsetOf(r1->r_flags) != OffsetOf(r2->r_flags)))
    return (0);
#endif

  return (1);
}
#endif /* (DOSX == 0) && USE_DEBUG */

/*
 * pkt_init - Called from pkt_eth_init() to search for PKT-DRVR.
 *          - Allocates '_pkt_inf' structure.
 */
static int pkt_init (void)
{
#if (DOSX)
  int rc;
#endif

#if (DOSX == 0) && defined(USE_DEBUG)
  if (!check_reg_struct())
  {
    outsnl (__FILE__ ": IREGS/REGPACK size mismatch!");
    return (0);
  }
#endif

  /* If interrupt specified in environment ("WATTCP.VEC=0xNN" or
   * "TCP_PKTINT=0xNN") check a single vector. Else, search for the 1st
   * driver in range 0x60-0x80.
   */
  if (pkt_interrupt)
       pkt_interrupt = find_vector (pkt_interrupt, 1);
  else pkt_interrupt = find_vector (PKT_FIRST_VEC,
                                    PKT_LAST_VEC - PKT_FIRST_VEC + 1);

  if (pkt_interrupt == 0)
  {
    outsnl (_LANG("NO PACKET DRIVER FOUND."));
    return (0);
  }

  if (!setup_pkt_inf())
  {
    outsnl (_LANG("Failed to allocate PACKET DRIVER data."));
    return (0);
  }

#if (DOSX)
  if ((rc = setup_rmode_callback()) < 0)
  {
    if (rc == -1 || rc == -2)
       outsnl (rc == -1 ?
               _LANG("Failed to allocate callback for PACKET DRIVER.") :
               _LANG("Failed to allocate DOS-mem for PACKET DRIVER."));
    return (0);
  }
  if (lock_code_and_data() < 0)
  {
    outsnl (_LANG("Failed to lock code/data for PACKET DRIVER."));
    return (0);
  }
#endif

  if (!pkt_drvr_info())         /* get device class etc. of driver */
     return (0);

  if (!pkt_set_access())        /* get handles for IP, ARP (and RARP, PPPoE) */
  {
    release_handles (TRUE);
    return (0);
  }

  if (!pkt_get_addr(&eth_addr)) /* get our MAC address */
  {
    release_handles (TRUE);
    return (0);
  }

  if (_pktdevlevel >= 2 && _pktdevlevel < 255)
     pkt_get_params();

#if defined(USE_MULTICAST)
  /* set receive mode to limited multicast
   */
  if (_multicast_on)
     _pkt_set_rcv_mode (_pkt_inf->ip_handle, RM_MULTICAST1);
#endif

  return (1);
}

/*
 *  The following functions (ending at '_pkt_end()') are called
 *  at interrupt time (or asynchronously). 'pkt_release()' may be
 *  called from SIGSEGV handler. Therefore don't assume anything
 *  about the state of our stack (except hope it's large enough).
 *  And don't use large local variables here. Hope we will not be
 *  reentered since not all functions below are reentrant.
 */

/* Disable stack-checking here
 */
#if defined(__HIGHC__)
#pragma off(check_stack)
#pragma off(call_trace)
#pragma off(prolog_trace)
#pragma off(epilog_trace)
#endif

#if defined(__WATCOMC__)
#pragma off(check_stack)
#endif

#if defined(__WATCOM386__)
//#pragma option -zu                    /* assume SS != DS (doesn't work) */
//#pragma aux pkt_release __modify[ss]; /* !! fix-me (doesn't work) */
#endif

#if (defined(__TURBOC__) || defined(__BORLANDC__)) && !defined(OLD_TURBOC)
#pragma option -N-
#endif

/*
 * Release all allocated protocol handles
 */
static int release_handles (BOOL quiet)
{
  static IREGS regs;  /* `static' because the stack could be too small */

  ASSERT_PKT_INF (0);

  /* to-do!!: change to local stack just in case (use longjmp?)
   */

  if (!_pktserial)
  {
    regs.r_ax = PD_RELEASE;
    regs.r_bx = _pkt_inf->arp_handle;
    if (!PKT_API(&regs) && !quiet)
       PKT_ERR ("Error releasing ARP handle: ", regs.r_dx);

#if defined(USE_RARP)
    regs.r_ax = PD_RELEASE;
    regs.r_bx = _pkt_inf->rarp_handle;
    if (!PKT_API(&regs) && !quiet)
       PKT_ERR ("Error releasing RARP handle: ", regs.r_dx);
#endif

#if defined(USE_PPPOE)
    regs.r_ax = PD_RELEASE;
    regs.r_bx = _pkt_inf->pppoe_sess_handle;
    if (!PKT_API(&regs) && !quiet)
       PKT_ERR ("Error releasing PPPOE session handle: ", regs.r_dx);

    regs.r_ax = PD_RELEASE;
    regs.r_bx = _pkt_inf->pppoe_disc_handle;
    if (!PKT_API(&regs) && !quiet)
       PKT_ERR ("Error releasing PPPOE discovery handle: ", regs.r_dx);
#endif
  }

  regs.r_ax = PD_RELEASE;
  regs.r_bx = _pkt_inf->ip_handle;

  if (!PKT_API(&regs) && !quiet)
     PKT_ERR ("Error releasing IP handle: ", regs.r_dx);
  return (1);
}

/*
 *  Release the pkt-driver.
 *  Might be called from exception/signal handler.
 */
int pkt_release (void)
{
  release_handles (FALSE);

  pkt_interrupt = 0;
  DISABLE();         /* no upcalls now */

  /*
   * to-do !!: We might be called between 1st and 2nd packet-driver
   *           upcall. Need to wait for 2nd upcall to finish or else
   *           freeing the RMCB too early could cause a crash.
   */

#if (DOSX & PHARLAP)
  _dx_free_rmode_wrapper (rm_base);

#elif (DOSX & DJGPP)
  _go32_dpmi_free_real_mode_callback (&rm_cb);
  __dpmi_error = 0;
  _go32_dpmi_free_dos_memory (&_pkt_inf->rm_mem);
  if (__dpmi_error)                /* !!above free function clears eax */
    fprintf (stderr, "%s (%u): DPMI/DOS error %04Xh\n",
             __FILE__, __LINE__, __dpmi_error);

#elif (DOSX & DOS4GW)
  if (pkt_rcv_sel) dpmi_real_free (pkt_rcv_sel);
  if (pkt_inf_sel) dpmi_real_free (pkt_inf_sel);
  pkt_rcv_sel = 0;
  pkt_inf_sel = 0;
  _pkt_inf = NULL;

#elif (DOSX & WDOSX)
  if (rm_base_sel)
     dpmi_real_free (rm_base_sel);
  rm_base_sel = 0;

#elif (DOSX & POWERPAK)
  UNFINISHED();
#endif

#if (DOSX)
  unlock_code_and_data();

  if (_pkt_inf)
     free (_pkt_inf);
  _pkt_inf = NULL;  /* drop anything still in the queue */
#endif

  ENABLE();
  return (1);
}

#if !(DOSX & DOS4GW) /* Not used for DOS4GW targets;
                      * This is done in asmpkt4.asm
                      */
/*
 *  Enqueue a received packet into '_pkt_inf->ip_queue' or
 *  '_pkt_inf->arp_queue'.
 *
 *  This routine is called from pkt_receiver_rm/_pm().
 *  The packet has been copied to rx_buffer (in DOS memory) by the
 *  packet-driver. We now must copy it to correct queue.
 *  Interrupts are disabled on entry.
 *
 *  Note 1: For real-mode targets SS and SP have been setup to a small
 *          work stack in asmpkt.asm. The stack can only take 64 pushes,
 *          hence use few local variables here.
 *
 *  Note 2: The C-compiler must be told NOT to use register calling
 *          for this routine (MUST use _cdecl) because it's called from
 *          asmpkt.asm via `pkt_enque_ptr' function pointer.
 *
 *  Note 3: Watcom/DOS4GW targets doesn't use real->prot mode upcall (RMCB),
 *          but does the following in asmpkt4.asm instead.
 *
 *  Note 4: For DOSX targets, all code from pkt_enqueue() down to pkt_end()
 *          must be locked in memory.
 *
 *  HACK: For real-mode targets this routine is called via the
 *        `pkt_enque_ptr' function pointer. This was the only way
 *        I could avoid a fixup error for small-model programs.
 */                      

#if (DOSX)
static void pkt_enqueue (unsigned rxBuf, WORD rxLen, WORD handle)
#else
static void _cdecl _far pkt_enqueue (BYTE _far *rxBuf, WORD rxLen, WORD handle)
#endif
{
  struct pkt_ringbuf *q;
  int    index;

  if (handle == _pkt_inf->arp_handle && !_pkt_inf->is_serial)
       q = &_pkt_inf->arp_queue;    /* ARP only packets */
  else q = &_pkt_inf->ip_queue;     /* RARP, IP, PPPOE packets */

  /* don't use pktq_in_index() and pktq_in_buf() because they
   * are not in locked code area.
   */
  index = q->in_index + 1;
  if (index >= q->num_buf)
      index = 0;

  if (index != q->out_index)
  {
    char *head   = q->buf_start + (q->buf_size * q->in_index);
    int   padLen = q->buf_size - 4 - rxLen;

    if (rxLen > q->buf_size - 4)  /* don't overwrite marker */
    {
      rxLen  = q->buf_size - 4;
      padLen = 0;
    }

#if (DOSX & PHARLAP)
    ReadRealMem (head, rm_base + rxBuf, rxLen);

#elif (DOSX & DJGPP)
    dosmemget (rm_base + rxBuf, rxLen, head);

#elif (DOSX & WDOSX)
    memcpy (head, rm_base + rxBuf, rxLen);

#elif (DOSX & POWERPAK)
    UNFINISHED();

#else  /* real-mode targets */
    _fmemcpy (head, rxBuf, rxLen);
#endif

    /* To stay on the safe side we zero-fill remaining old
     * data in this buffer.
     */
    head += rxLen;
    while (padLen--)
       *head++ = 0;
    q->in_index = index;   /* update buffer tail-index */
  }
  else
    q->num_drop++;
}  


/*
 * We have allocated a real-mode callback (RMCB) to gain control
 * here when the packet-driver makes an upcall.
 *
 * Entry AL = 0; driver requests a buffer. We return ES:DI of real-mode buffer
 *       BX = handle (IP, ARP or RARP)
 *       CX = length of packet
 * Entry AL = 1; driver has put the data in buffer, we then enqueues the buffer
 *       BX = handle (IP, ARP or RARP)
 *       CX = length of packet
 *
 * Interrupts are disabled on entry.
 *
 * to-do!!: allocate a real-stub that calls the RMCB only on the 2nd upcall.
 */
#if (DOSX & PHARLAP)
  static void pkt_receiver_pm (SWI_REGS *r)
  { 
    if ((BYTE)r->eax == 0)         /* AL == 0; rx-buffer request */
    {
      if (!_pkt_inf || (WORD)r->ecx > ETH_MAX) /* !!should be for current driver */
      {
        r->es  = 0;
        r->edi = 0;
      }
      else
      {
        r->es  = RP_SEG (rm_base);
        r->edi = RX_BUF();
      }
    }
    else if ((WORD)r->esi && _pkt_inf)   /* AL != 0; rx-buffer filled */
            pkt_enqueue (RX_BUF(), (WORD)r->ecx, (WORD)r->ebx);
  }

#elif (DOSX & DJGPP)
  static void pkt_receiver_pm (void)
  {
    __dpmi_regs *r = &rm_reg;

    if (r->h.al == 0)
    {
      if (!_pkt_inf || r->x.cx > ETH_MAX)
      {
        r->x.es = 0;
        r->x.di = 0;
      }
      else
      {
        r->x.es = RP_SEG();
        r->x.di = RX_BUF();
      }
    }
    else if (r->x.si && _pkt_inf)
            pkt_enqueue (RX_BUF(), (WORD)r->x.cx, (WORD)r->x.bx);
  }

#elif (DOSX & WDOSX)      /* !!fix-me: assumes bcc32 */
  static void pkt_receiver_pm (void)
  {
    static struct DPMI_regs *r; /* static because of "pop ebp" below */

    r = &rm_cb.cb_reg;
    if ((BYTE)r->r_ax == 0)
    {
      if (!_pkt_inf || r->r_cx > ETH_MAX)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -