722 lines
17 KiB
C
722 lines
17 KiB
C
/* @(#)hllcputils.c 1.1 92/07/30 SMI */
|
|
|
|
/*
|
|
* Copyright (c) 1988 by Sun Microsystems, Inc.
|
|
*/
|
|
|
|
/*
|
|
* hllcputils.c - contains routines which should be invarient from application
|
|
* to application. The routines contained in this file are:
|
|
*
|
|
* LLCP_SEND_CMD - macro to send a command to the controller
|
|
* llcp_get_pkt - polls for a data packet
|
|
* llcp_send_pkt - sends a data packet
|
|
* strt_init - initiates llcp initialization
|
|
* send_info - sends host info to controller
|
|
* get_info - sends controller info to host
|
|
* llcp_error - gets error string and displays to console
|
|
* llcp_reset - decides to call reset_cmd or power_on_rst
|
|
* reset_cmd - attempts to s/w reset the cntrlr board
|
|
* pre_err_chk - checks llcp prior to issueing command
|
|
* post_err_chk - checks llcp after issueing command
|
|
* add_llc_hdr - adds llc snap hdr for ISO compatibility
|
|
* strip_llc_hdr - strips llcp snap hdr from packet
|
|
* llcp_get_status - gets a copy of the current register status
|
|
*
|
|
* initial - PAS - 3/16/88
|
|
*/
|
|
|
|
|
|
#ifdef PROMCODE
|
|
#include "../h/types.h"
|
|
#include "../dev/llcp.h"
|
|
#include "../h/sunromvec.h"
|
|
#include "../h/globram.h"
|
|
#include "../h/socket.h"
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/if_ether.h>
|
|
#include "../dev/if_llc.h"
|
|
#else PROMCODE
|
|
#include <sys/types.h>
|
|
#include <sunif/llcp.h>
|
|
#include <sys/mbuf.h>
|
|
#include <sys/uio.h>
|
|
#include <sys/map.h>
|
|
#include <sys/socket.h>
|
|
#include <net/if.h>
|
|
#include <netinet/in.h>
|
|
#include <netinet/if_ether.h>
|
|
#include "../sunif/if_llc.h"
|
|
#if defined(STANDALONE)
|
|
#include <mon/sunromvec.h>
|
|
#endif
|
|
#endif PROMCODE
|
|
|
|
|
|
#ifdef KERNEL
|
|
#define UNIXDVR 1
|
|
#endif
|
|
|
|
|
|
|
|
extern char *llcp_msgs[];
|
|
|
|
/*
|
|
* LLCP_SEND_CMD - the order of the operations is critical for the
|
|
* handshake. The command register being written
|
|
* to a non-zero value initiates controller action.
|
|
* The was changed to a macro to save space for
|
|
* cpu host prom.
|
|
*/
|
|
|
|
#define LLCP_SEND_CMD(regp,a,b,c)\
|
|
regp->len = a;\
|
|
regp->addr = b;\
|
|
regp->cmd = c; /* issue command */
|
|
|
|
|
|
|
|
/*
|
|
* llcp_get_pkt - polls for a packet of data for a maximum time as specified
|
|
* in the controller info structure. Returns 0 for no packet
|
|
* or an error, otherwise returns the length of the packet
|
|
* Upon command completion if an error occurs, prints a message
|
|
* to the console.
|
|
*/
|
|
|
|
int
|
|
llcp_get_pkt(llcptr, buf)
|
|
llcp_info_t *llcptr;
|
|
char *buf;
|
|
{
|
|
int length = 0;
|
|
llcp_reg_t treg;
|
|
register llcp_reg_t *regptr = llcptr->regp;
|
|
void cmd_wait(), strip_llc_hdr();
|
|
|
|
|
|
/*
|
|
* check for error conditions prior to issueing command
|
|
*/
|
|
#ifndef PROMCODE
|
|
if ( pre_err_chk(llcptr, LLCP_RDY) == LLCP_FAIL )
|
|
return(0); /* return packet of length 0 */
|
|
#endif
|
|
|
|
/* issue llcp command - (length, address, command) */
|
|
LLCP_SEND_CMD(regptr, 0L, (u_char *)0, LLCP_GET_PKT);
|
|
|
|
#ifndef UNIXDVR
|
|
cmd_wait(llcptr, LLCP_RDY); /* wait up to timeout */
|
|
|
|
/*
|
|
* check for errors on command completion
|
|
*/
|
|
if ( post_err_chk(llcptr, LLCP_RDY) == LLCP_FAIL )
|
|
return(0); /* return packet of length 0 */
|
|
|
|
/*
|
|
* command completed successfully
|
|
* so transfer data to buffer
|
|
*/
|
|
llcp_get_status(llcptr, &treg); /* get register values */
|
|
if ( ((length = (int) treg.len) > 0) && (length <= LLCP_BUF_SIZ) ) {
|
|
strip_llc_hdr((char *)llcptr->cinfop->buf, (char*)buf, &length);
|
|
return(length);
|
|
}
|
|
#endif
|
|
|
|
return(0); /* return packet of length 0 */
|
|
} /* llcp_get_pkt */
|
|
|
|
|
|
|
|
/*
|
|
* llcp_send_pkt - transmits a packet of data. Waits for a maximum time as
|
|
* specified in the controller info structure. Returns LLCP_FAIL
|
|
* for error and LLCP_SUCC otherwise. If an error occurs, prints a
|
|
* msg to the console.
|
|
*/
|
|
|
|
int
|
|
llcp_send_pkt(llcptr, buf, length)
|
|
llcp_info_t *llcptr;
|
|
char *buf;
|
|
int length;
|
|
{
|
|
register llcp_reg_t *regptr = llcptr->regp;
|
|
void cmd_wait(), add_llc_hdr();
|
|
|
|
/*
|
|
* check for error conditions prior to issueing command
|
|
*/
|
|
#ifndef PROMCODE
|
|
if ( pre_err_chk(llcptr, LLCP_RDY) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
#endif
|
|
|
|
/* add iso llc header and adjust len */
|
|
add_llc_hdr(buf, (char *)llcptr->cinfop->buf, &length);
|
|
|
|
/* issue llcp command - (length, address, command) */
|
|
LLCP_SEND_CMD(regptr, length, (u_char *)0, LLCP_SEND_PKT);
|
|
|
|
#ifndef UNIXDVR
|
|
cmd_wait(llcptr, LLCP_RDY); /* wait up to timeout */
|
|
|
|
/*
|
|
* check for errors on command completion
|
|
*/
|
|
if ( post_err_chk(llcptr, LLCP_RDY) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
#endif
|
|
|
|
return(LLCP_SUCC); /* command completed successfully */
|
|
} /* llcp_send_pkt */
|
|
|
|
|
|
|
|
/*
|
|
* strt_init - Initiates llcp initialization
|
|
* Returns either LLCP_SUCC or LLCP_FAIL.
|
|
*/
|
|
|
|
strt_init(llcptr)
|
|
llcp_info_t *llcptr;
|
|
{
|
|
llcp_reg_t treg;
|
|
register llcp_reg_t *regptr = llcptr->regp;
|
|
llcp_cntrlr_info_t *cinfoptr = llcptr->cinfop;
|
|
void cmd_wait();
|
|
|
|
|
|
#ifndef PROMCODE
|
|
if ( pre_err_chk(llcptr, LLCP_INIT1) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
#endif
|
|
|
|
/* issue llcp command - (length, address, command) */
|
|
LLCP_SEND_CMD(regptr, 0L,
|
|
((cinfoptr->memtyp == DMA_MEM)? cinfoptr->buf: (u_char *)0),
|
|
LLCP_STRT_INIT);
|
|
|
|
#ifndef UNIXDVR
|
|
cmd_wait(llcptr, LLCP_INIT2); /* wait up to timeout */
|
|
|
|
if ( post_err_chk(llcptr, LLCP_INIT2) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
|
|
/*
|
|
* save address of shared memory buffer and check if host
|
|
* has dma interface and controller expects shared mem or
|
|
* vice versa.
|
|
*/
|
|
llcp_get_status(llcptr, &treg); /* get register values*/
|
|
|
|
if ( cinfoptr->memtyp == SHARED_MEM ) { /* host has shared mem int*/
|
|
if ( treg.addr == (u_char *)0 ) {
|
|
printf(llcp_msgs[E_LLCP_DMA]);
|
|
return(LLCP_FAIL);
|
|
}
|
|
else /* save address of shared mem */
|
|
cinfoptr->phys_addr = treg.addr;
|
|
} else { /* host has dma interface */
|
|
if ( treg.addr != (u_char *)0 ) {
|
|
printf(llcp_msgs[E_LLCP_DMA]);
|
|
return(LLCP_FAIL);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return(LLCP_SUCC);
|
|
} /* strt_init */
|
|
|
|
|
|
|
|
/*
|
|
* get_info - sends controller info to host
|
|
* Returns either LLCP_SUCC or LLCP_FAIL.
|
|
*/
|
|
|
|
get_info(llcptr)
|
|
llcp_info_t *llcptr;
|
|
{
|
|
llcp_reg_t treg;
|
|
register llcp_reg_t *regptr = llcptr->regp;
|
|
void cmd_wait();
|
|
|
|
|
|
#ifndef PROMCODE
|
|
if ( pre_err_chk(llcptr, LLCP_INIT2) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
#endif
|
|
|
|
/* issue llcp command - (length, address, command) */
|
|
LLCP_SEND_CMD(regptr, 0L, (u_char *)0, LLCP_GET_INFO);
|
|
|
|
#ifndef UNIXDVR
|
|
cmd_wait(llcptr, LLCP_INIT3); /* wait up to timeout */
|
|
|
|
if ( post_err_chk(llcptr, LLCP_INIT3) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
|
|
llcp_get_status(llcptr, &treg); /* get register values */
|
|
|
|
/* transfer controller information structure */
|
|
if ( stuff_cinfo(llcptr, (int)treg.len) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
|
|
#ifdef DEBUG
|
|
/*
|
|
* print out entire Cinfo struct
|
|
*/
|
|
printf("---------------- CINFO STRUCTURE -------------------------\n");
|
|
printf("len = %d",llcptr->cinfop->len);
|
|
printf(" llcp_ver = %d\n",llcptr->cinfop->llcp_ver);
|
|
printf("addrtyp = %x",llcptr->cinfop->addrtyp);
|
|
printf(" net_laddr = %s\n",llcptr->cinfop->net_laddr);
|
|
printf("buf = 0x%x",llcptr->cinfop->buf);
|
|
printf(" memtyp = %x\n",llcptr->cinfop->memtyp);
|
|
printf("max_pkt = %d",llcptr->cinfop->max_pkt);
|
|
printf(" timeout = %d\n",llcptr->cinfop->timeout);
|
|
printf("----------------------------------------------------------\n");
|
|
#endif DEBUG
|
|
#endif
|
|
|
|
return(LLCP_SUCC);
|
|
} /* get_info */
|
|
|
|
|
|
|
|
/*
|
|
* send_info - sends host info to controller
|
|
* Returns either LLCP_SUCC or LLCP_FAIL.
|
|
*/
|
|
|
|
send_info(llcptr)
|
|
llcp_info_t *llcptr;
|
|
{
|
|
register llcp_reg_t *regptr = llcptr->regp;
|
|
void cmd_wait();
|
|
|
|
|
|
#ifndef PROMCODE
|
|
if ( pre_err_chk(llcptr, LLCP_INIT3) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
#endif
|
|
|
|
/*
|
|
* set length of structure and send second half of init command
|
|
*/
|
|
bcopy((char *)llcptr->hinfop, (char *)llcptr->cinfop->buf,
|
|
sizeof(llcp_host_info_t));
|
|
|
|
/* issue llcp command - (length, address, command) */
|
|
LLCP_SEND_CMD(regptr, (long) sizeof(llcp_host_info_t), (u_char *)0,
|
|
LLCP_SEND_INFO);
|
|
|
|
#ifndef UNIXDVR
|
|
cmd_wait(llcptr, LLCP_RDY); /* wait up to timeout */
|
|
|
|
if ( post_err_chk(llcptr, LLCP_RDY) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
#endif
|
|
|
|
return(LLCP_SUCC);
|
|
} /* send_info */
|
|
|
|
|
|
|
|
/*
|
|
* ena_net - sends the enable network command
|
|
* This command is always sent after the init sequence, and
|
|
* is not optional.
|
|
* Returns either LLCP_SUCC or LLCP_FAIL.
|
|
*/
|
|
|
|
ena_net(llcptr)
|
|
llcp_info_t *llcptr;
|
|
{
|
|
register llcp_reg_t *regptr = llcptr->regp;
|
|
void cmd_wait();
|
|
|
|
#ifndef PROMCODE
|
|
if ( pre_err_chk(llcptr, LLCP_RDY) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
#endif
|
|
|
|
/* issue llcp command - (length, address, command) */
|
|
LLCP_SEND_CMD(regptr, 0L, (u_char *)0, LLCP_ENA_NET);
|
|
|
|
#ifndef UNIXDVR
|
|
cmd_wait(llcptr, LLCP_RDY); /* wait up to timeout */
|
|
|
|
if ( post_err_chk(llcptr, LLCP_RDY) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
#endif
|
|
|
|
return(LLCP_SUCC);
|
|
} /* ena_net */
|
|
|
|
|
|
|
|
|
|
/*
|
|
* goto_hlcp - sends goto hlcp command to exit llcp.
|
|
* Returns either LLCP_SUCC or LLCP_FAIL.
|
|
*/
|
|
|
|
#ifndef PROMCODE
|
|
goto_hlcp(llcptr)
|
|
llcp_info_t *llcptr;
|
|
{
|
|
register llcp_reg_t *regptr = llcptr->regp;
|
|
void cmd_wait();
|
|
|
|
if ( pre_err_chk(llcptr, LLCP_RDY) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
|
|
/* issue llcp command - (length, address, command) */
|
|
LLCP_SEND_CMD(regptr, 0L, (u_char *)0, LLCP_GOTO_HLCP);
|
|
|
|
#ifndef UNIXDVR
|
|
cmd_wait(llcptr, LLCP_HLCP); /* wait up to timeout */
|
|
|
|
if ( post_err_chk(llcptr, LLCP_HLCP) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
#endif
|
|
|
|
return(LLCP_SUCC);
|
|
} /* goto_hlcp */
|
|
#endif
|
|
|
|
|
|
|
|
|
|
/*
|
|
* gen_cmd - sends any generic command to the controller
|
|
* The caller must fully set up the treg contents
|
|
* before calling this routine, so because of
|
|
* this extra knowledge needed, it should only be used
|
|
* with controller specific commands. Note that this
|
|
* command does not transfer any data.
|
|
* Returns either LLCP_SUCC or LLCP_FAIL.
|
|
*/
|
|
|
|
#ifndef PROMCODE
|
|
gen_cmd(llcptr,treg)
|
|
llcp_info_t *llcptr;
|
|
llcp_reg_t *treg;
|
|
{
|
|
register llcp_reg_t *regptr = llcptr->regp;
|
|
void cmd_wait();
|
|
|
|
if ( pre_err_chk(llcptr, LLCP_RDY) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
|
|
/* issue llcp command - (length, address, command) */
|
|
LLCP_SEND_CMD(regptr, treg->len, treg->addr, treg->cmd);
|
|
|
|
#ifndef UNIXDVR
|
|
cmd_wait(llcptr, LLCP_HLCP); /* wait up to timeout */
|
|
|
|
if ( post_err_chk(llcptr, LLCP_RDY) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
#endif
|
|
|
|
return(LLCP_SUCC);
|
|
} /* gen_cmd */
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
* llcp_error() - performs the llcp handshake to retrieve the error string,
|
|
* if one exists, and prints the message out. Checks on error
|
|
* state and command complete. Returns LLCP_SUCC if an error
|
|
* string is found, and LLCP_FAIL otherwise
|
|
*/
|
|
|
|
llcp_error(llcptr)
|
|
llcp_info_t *llcptr;
|
|
{
|
|
int length;
|
|
llcp_reg_t treg;
|
|
register llcp_reg_t *regptr = llcptr->regp;
|
|
void cmd_wait();
|
|
|
|
/* issue llcp command - (length, address, command) */
|
|
LLCP_SEND_CMD(regptr, 0L, (u_char *)0, LLCP_ERROR);
|
|
|
|
#ifndef UNIXDVR
|
|
cmd_wait(llcptr, LLCP_ERR); /* wait up to timeout */
|
|
|
|
/*
|
|
* Since some of the llcp registers could be broken, do not even
|
|
* check on command complete. As long as the length is non-zero
|
|
* we will attempt to print out the contents of the info buffer.
|
|
*/
|
|
llcp_get_status(llcptr, &treg); /* get register values */
|
|
if ( (length = (int) treg.len) != 0 ) {
|
|
*(llcptr->cinfop->buf + length) = '\0'; /* terminate str */
|
|
/* XXX what if shared memory has not been setup at this point!*/
|
|
printf(llcp_msgs[E_LLCP_EST], llcptr->cinfop->buf);
|
|
return(LLCP_SUCC);
|
|
}
|
|
|
|
return(LLCP_FAIL);
|
|
#else
|
|
return(LLCP_SUCC);
|
|
#endif
|
|
} /* llcp_error */
|
|
|
|
|
|
|
|
/*
|
|
* llcp_reset - software resets network board.
|
|
* Determines if the controller is in an undetermined state from
|
|
* power on reset. If so, does not write any of the shared memory
|
|
* registers until a timeout or valid combination of values is
|
|
* found. If a valid combination of values is found in the llcp
|
|
* register set, simply issues the reset command.
|
|
* This isn't very robust to hardware errors during runtime, but
|
|
* then again, the reset command doesn't do a whole hell of a lot!
|
|
* If there is an error, a message will be displayed through the
|
|
* post_err_chk routine.
|
|
*/
|
|
|
|
llcp_reset(llcptr)
|
|
llcp_info_t *llcptr;
|
|
{
|
|
#ifdef PROMCODE
|
|
int retval;
|
|
|
|
/* check if first time through the code on system power-up */
|
|
if ( first_time != 0 )
|
|
return( reset_cmd(llcptr) );
|
|
else {
|
|
retval = power_on_rst(llcptr);
|
|
first_time = 1; /* not the first time thru code anymore */
|
|
return(retval);
|
|
}
|
|
#else
|
|
/*
|
|
* can only have a power on reset from prom code
|
|
*/
|
|
return( reset_cmd(llcptr) );
|
|
#endif
|
|
|
|
} /* llcp_reset */
|
|
|
|
|
|
|
|
/*
|
|
* reset_cmd - software resets the controller board by writing
|
|
* the reset command to the llcp registers.
|
|
* Returns LLCP_SUCC on successful completion and
|
|
* LLCP_FAIL on failure.
|
|
*/
|
|
|
|
reset_cmd(llcptr)
|
|
llcp_info_t *llcptr;
|
|
{
|
|
register llcp_reg_t *regptr = llcptr->regp;
|
|
void cmd_wait();
|
|
|
|
llcptr->cinfop->timeout = LLCP_T_RESET; /* set 4s timeout for reset */
|
|
|
|
/* issue llcp command - (length, address, command) */
|
|
LLCP_SEND_CMD(regptr, 0L, (u_char *)0, LLCP_RESET);
|
|
|
|
#ifdef DEBUG
|
|
printf("rst_cmd: ®=0x%x \n", llcptr->regp);
|
|
#endif
|
|
|
|
#ifndef UNIXDVR
|
|
cmd_wait(llcptr, LLCP_INIT1); /* wait up to timeout */
|
|
|
|
if ( post_err_chk(llcptr, LLCP_INIT1) == LLCP_FAIL )
|
|
return(LLCP_FAIL);
|
|
#endif
|
|
|
|
return(LLCP_SUCC);
|
|
} /* reset_cmd */
|
|
|
|
|
|
|
|
/*
|
|
* pre_err_chk - checks all the registers and prints out the appropriate
|
|
* message if there is an error. This routine is called before
|
|
* a command to the controller has been issued. If the
|
|
* controller has gone into the error state, the error
|
|
* routine is invoked. Returns either LLCP_SUCC or LLCP_FAIL
|
|
*/
|
|
|
|
#ifndef PROMCODE
|
|
pre_err_chk(llcptr, expected_state)
|
|
llcp_info_t *llcptr;
|
|
state_t expected_state;
|
|
{
|
|
llcp_reg_t treg;
|
|
|
|
llcp_get_status(llcptr, &treg); /* get controller status */
|
|
|
|
/* check if in proper state and command complete */
|
|
if ( (treg.state != expected_state) || (treg.cmd != LLCP_CMD_COM) ) {
|
|
printf(llcp_msgs[E_LLCP_RDY]);
|
|
return(LLCP_FAIL);
|
|
}
|
|
|
|
return(LLCP_SUCC);
|
|
} /* pre_err_chk */
|
|
#endif
|
|
|
|
|
|
|
|
/*
|
|
* post_err_chk - checks all the registers and prints out the appropriate
|
|
* message if there is an error. This routine is called after
|
|
* a command to the controller has been issued. If the
|
|
* controller has gone into the error state, the error routine
|
|
* is invoked. Returns either LLCP_SUCC or LLCP_FAIL
|
|
*/
|
|
|
|
post_err_chk(llcptr, expected_state)
|
|
llcp_info_t *llcptr;
|
|
state_t expected_state;
|
|
{
|
|
llcp_reg_t treg;
|
|
|
|
llcp_get_status(llcptr, &treg); /* get controller status */
|
|
|
|
/* command did not complete, not in proper state, or bad fault code */
|
|
if ( (treg.cmd != LLCP_CMD_COM) || (treg.state != expected_state) ) {
|
|
printf(llcp_msgs[E_LLCP_RDY]);
|
|
return(LLCP_FAIL);
|
|
}
|
|
else if ( treg.fault != LLCP_FC_OK ) {
|
|
if ( treg.fault == LLCP_FC_INV_CMD )
|
|
printf(llcp_msgs[E_LLCP_INV]);
|
|
else if ( (treg.state != LLCP_RDY) && (treg.state != LLCP_INIT2)
|
|
&& (treg.state != LLCP_INIT3) )
|
|
/* cannot use common memory */
|
|
printf(llcp_msgs[E_LLCP_RDY]);
|
|
else {
|
|
#ifndef UNIXDVR
|
|
(void) llcp_error(llcptr); /* print out error string */
|
|
#endif
|
|
}
|
|
return(LLCP_FAIL);
|
|
}
|
|
|
|
return(LLCP_SUCC);
|
|
} /* post_err_chk */
|
|
|
|
|
|
|
|
/*
|
|
* add_llc_hdr - adds an llc header to our frames.
|
|
*
|
|
* The packet received by this routine originally looks like
|
|
* the following:
|
|
*
|
|
* ------------------------------------S------------
|
|
* | DA | SA | TYPE | DATA |
|
|
* ------------------------------------S------------
|
|
*
|
|
* It is converted to adhere to ISO standards, and subsequently
|
|
* looks like this:
|
|
*
|
|
* -------------------------------------------S------------
|
|
* | DA | SA | LLC_SNAP_HDR* | DATA |
|
|
* -------------------------------------------S------------
|
|
*
|
|
* *note that the end of the llc_snap_hdr contains the type
|
|
* field from the original packet
|
|
*
|
|
*/
|
|
|
|
void
|
|
add_llc_hdr(buf,tbufp,len)
|
|
char *buf, *tbufp;
|
|
int *len;
|
|
{
|
|
int addrlen, etherhdrlen;
|
|
struct llc_snap_hdr *snap_hdr;
|
|
short *intp;
|
|
|
|
/*
|
|
* copy over DA and SA
|
|
*/
|
|
addrlen = sizeof(struct ether_addr) * 2;
|
|
etherhdrlen = addrlen + sizeof(short);
|
|
bcopy(buf, (char *)tbufp, addrlen); /* DA,SA */
|
|
|
|
/*
|
|
* copy over ISO lsap_snap header
|
|
* for ISO compatibility
|
|
*/
|
|
tbufp += addrlen;
|
|
|
|
snap_hdr = (struct llc_snap_hdr *)(tbufp);
|
|
snap_hdr->d_lsap = 0xaa;
|
|
snap_hdr->s_lsap = 0xaa;
|
|
snap_hdr->control = CNTL_LLC_UI; /* un-numbered information packet */
|
|
snap_hdr->org[0] = 0x0;
|
|
snap_hdr->org[1] = 0x0;
|
|
snap_hdr->org[2] = 0x0;
|
|
intp = (short *)(buf + addrlen);
|
|
snap_hdr->type = (u_short)*intp; /* stuff in type of packet */
|
|
tbufp += LLC_SNAP_HDR_LEN;
|
|
|
|
/*
|
|
* copy over rest of data and adjust len
|
|
*/
|
|
bcopy(buf+etherhdrlen, tbufp, *len - etherhdrlen); /* Data */
|
|
*len += LLC_SNAP_HDR_LEN;
|
|
|
|
} /* add_llc_hdr */
|
|
|
|
|
|
|
|
/*
|
|
* strip_llc_hdr - strips an llc header from frames received.
|
|
* see above diagram for packet formats.
|
|
*/
|
|
|
|
void
|
|
strip_llc_hdr(tbufp,buf,len)
|
|
char *tbufp, *buf;
|
|
int *len;
|
|
{
|
|
int addrlen;
|
|
|
|
addrlen = sizeof(struct ether_addr) * 2;
|
|
|
|
bcopy((char *)tbufp, buf, addrlen); /* DA SA */
|
|
tbufp += addrlen;
|
|
/*
|
|
* note that this second bcopy skews over the llcp_snap_hdr saving
|
|
* the type field at the end of the llc header
|
|
*/
|
|
*len = *len - LLC_SNAP_HDR_LEN + sizeof(short);
|
|
bcopy((char *)tbufp+(LLC_SNAP_HDR_LEN - sizeof(short)),
|
|
buf+addrlen, *len - addrlen); /* Data&type */
|
|
|
|
} /* strip_llc_hdr */
|
|
|
|
|
|
|
|
llcp_get_status(llcptr, treg) /* get controller status */
|
|
llcp_info_t *llcptr;
|
|
llcp_reg_t *treg;
|
|
{
|
|
|
|
*treg = *llcptr->regp;
|
|
|
|
} /* llcp_get_status */
|
|
|