📄 pcpkt.c
字号:
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(®s))
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(ð_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(®s) && !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(®s) && !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(®s) && !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(®s) && !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(®s) && !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 + -