* Copyright (c) 1982, 1986, 1988 Regents of the University of California.
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)if_vv.c 7.4 (Berkeley) 10/22/88
* Proteon ProNET-10 and ProNET-80 token ring driver.
* The name of this device driver derives from the old MIT
* name of V2LNI for the proNET hardware, would would abbreviate
* to "v2", but this won't work right in config. Thus the name is "vv".
* This driver is compatible with the Unibus ProNET 10 megabit and
* 80 megabit token ring interfaces (models p1000 and p1080).
* A unit may be marked as 80 megabit using "flags 1" in the
* This driver is also compatible with the Q-bus ProNET 10 megabit and
* 80 megabit token ring interfaces (models p1100 and p1180), but
* only on a MicroVAX-II or MicroVAX-III. No attempt is made to
* support the MicroVAX-I.
* TRAILERS: This driver has a new implementation of trailers that
* is at least a tolerable neighbor on the ring. The offset is not
* stored in the protocol type, but instead only in the vh_info
* field. Also, the vh_info field, and the two shorts before the
* trailing header, are in network byte order, not VAX byte order.
* Of course, nothing but BSD UNIX supports trailers on ProNET.
* If you need interoperability with anything else (like the p4200),
* turn off trailers using the -trailers option to /etc/ifconfig!
* HARDWARE COMPATABILITY: This driver prefers that the HSBU (p1001)
* have a serial number >= 040, which is about March, 1982. Older
* HSBUs do not carry across 64kbyte boundaries. They can be supported
* by adding "| UBA_NEED16" to the vs_ifuba.ifu_flags initialization
* The old warning about use without Wire Centers applies only to CTL
* (p1002) cards with serial <= 057, which have not received ECO 176-743,
* which was implemented in March, 1982. Most such CTLs have received
#include "../machine/pte.h"
#include "../net/netisr.h"
#include "../net/route.h"
#include "../netinet/in.h"
#include "../netinet/in_systm.h"
#include "../netinet/in_var.h"
#include "../netinet/ip.h"
#include "../vaxuba/ubareg.h"
#include "../vaxuba/ubavar.h"
* maximum transmission unit definition --
* you can set VVMTU at anything from 576 to 2036.
* 1536 is a popular "large" value, because it is a multiple
* of 512, which the trailer scheme likes.
* The absolute maximum size is 2036, which is enforced.
#define VVMRU (VVMTU + (2 * sizeof(u_short)))
#define VVBUFSIZE (VVMRU + sizeof(struct vv_header))
#define VVMRU (VVBUFSIZE - sizeof (struct vv_header))
#define VVMTU (VVMRU - (2 * sizeof(u_short)))
* debugging and tracing stuff
int vv_tracehdr
= 0; /* 1 => trace headers (slowly!!) */
#define vvtracehdr if (vv_tracehdr) vvprt_hdr
#define vvprintf if (vs->vs_if.if_flags & IFF_DEBUG) printf
int vvprobe(), vvattach(), vvreset(), vvinit();
int vvidentify(), vvstart(), vvxint(), vvwatchdog();
int vvrint(), vvoutput(), vvioctl();
struct uba_device
*vvinfo
[NVV
];
struct uba_driver vvdriver
=
{ vvprobe
, 0, vvattach
, 0, vvstd
, "vv", vvinfo
};
#define VVUNIT(x) minor(x)
#define LOOPBACK /* use loopback for packets meant for us */
extern struct ifnet loif
;
* Software status of each interface.
* Each interface is referenced by a network interface structure,
* vs_if, which the routing code uses to locate the interface.
* This structure contains the output queue for the interface, its address, ...
* We also have, for each interface, a UBA interface structure, which
* contains information about the UNIBUS resources held by the interface:
* map registers, buffered data paths, etc. Information is cached in this
* structure for use by the if_uba.c routines in running the interface
struct ifnet vs_if
; /* network-visible interface */
struct ifuba vs_ifuba
; /* UNIBUS resources */
u_short vs_host
; /* this interface address */
short vs_oactive
; /* is output active */
short vs_is80
; /* is 80 megabit version */
short vs_olen
; /* length of last output */
u_short vs_lastx
; /* address of last packet sent */
u_short vs_lastr
; /* address of last packet received */
short vs_tries
; /* transmit current retry count */
short vs_init
; /* number of ring inits */
short vs_refused
; /* number of packets refused */
short vs_timeouts
; /* number of transmit timeouts */
short vs_otimeout
; /* number of output timeouts */
short vs_ibadf
; /* number of input bad formats */
short vs_parity
; /* number of parity errors on 10 meg, */
/* link data errors on 80 meg */
short vs_ipl
; /* interrupt priority on Q-bus */
#define NOHOST 0xffff /* illegal host number */
* probe the interface to see that the registers exist, and then
* cause an interrupt to find its vector
register struct vvreg
*addr
;
br
= 0; cvec
= br
; br
= cvec
;
addr
= (struct vvreg
*)reg
;
/* reset interface, enable, and wait till dust settles */
/* generate interrupt by doing 1 word DMA from 0 in uba space!! */
addr
->vvoba
= 0; /* low 16 bits */
addr
->vvoea
= 0; /* extended bits */
addr
->vvowc
= -1; /* for 1 word */
addr
->vvocsr
= VV_IEN
| VV_DEN
; /* start the DMA, with interrupt */
vv_softc
[ui
->ui_unit
].vs_ipl
= br
= qbgetpri();
addr
->vvocsr
= VV_RST
; /* clear out the CSR */
if (cvec
&& cvec
!= 0x200)
cvec
-= 4; /* backup so vector => receive */
return (sizeof(struct vvreg
));
* Interface exists: make available by filling in network interface
* record. System will initialize the interface when it is ready
register struct vv_softc
*vs
;
vs
= &vv_softc
[ui
->ui_unit
];
vs
->vs_if
.if_unit
= ui
->ui_unit
;
vs
->vs_if
.if_name
= "vv";
vs
->vs_if
.if_mtu
= VVMTU
;
vs
->vs_if
.if_flags
= IFF_BROADCAST
;
vs
->vs_if
.if_init
= vvinit
;
vs
->vs_if
.if_ioctl
= vvioctl
;
vs
->vs_if
.if_output
= vvoutput
;
vs
->vs_if
.if_reset
= vvreset
;
vs
->vs_if
.if_watchdog
= vvwatchdog
;
vs
->vs_ifuba
.ifu_flags
= UBA_CANTWAIT
| UBA_NEEDBDP
;
/* use flag to determine if this is proNET-80 */
vs
->vs_is80
= (short)(ui
->ui_flags
& 01);
/* don't chew up 750 bdp's */
if (cpu
== VAX_750
&& ui
->ui_unit
> 0)
vs
->vs_ifuba
.ifu_flags
&= ~UBA_NEEDBDP
;
* Reset of interface after UNIBUS reset.
* If interface is on specified uba, reset its state.
register struct uba_device
*ui
;
if (unit
>= NVV
|| (ui
= vvinfo
[unit
]) == 0 || ui
->ui_alive
== 0 ||
* Initialization of interface; clear recorded pending
* operations, and reinitialize UNIBUS usage.
register struct vv_softc
*vs
;
register struct uba_device
*ui
;
register struct vvreg
*addr
;
if (vs
->vs_if
.if_addrlist
== (struct ifaddr
*)0)
addr
= (struct vvreg
*)ui
->ui_addr
;
if ((vs
->vs_if
.if_flags
& IFF_RUNNING
) == 0 &&
if_ubainit(&vs
->vs_ifuba
, ui
->ui_ubanum
,
sizeof (struct vv_header
), (int)btoc(VVMRU
)) == 0) {
printf("vv%d: can't initialize, if_ubainit() failed\n", unit
);
vs
->vs_if
.if_flags
&= ~IFF_UP
;
vs
->vs_if
.if_flags
|= IFF_RUNNING
;
* Now that the uba is set up, figure out our address and
* update complete our host address.
if ((vs
->vs_host
= vvidentify(unit
)) == NOHOST
) {
vs
->vs_if
.if_flags
&= ~IFF_UP
;
printf("vv%d: host %u\n", unit
, vs
->vs_host
);
* Reset the interface, and stay in the ring
addr
->vvocsr
= VV_RST
; /* take over output */
addr
->vvocsr
= VV_CPB
; /* clear packet buffer */
addr
->vvicsr
= VV_RST
| VV_HEN
; /* take over input, */
DELAY(500000); /* let contacts settle */
vs
->vs_init
= 0; /* clear counters, etc. */
vs
->vs_lastx
= 256; /* an invalid address */
vs
->vs_lastr
= 256; /* an invalid address */
* Hang a receive and start any
* pending writes by faking a transmit complete.
ubaaddr
= UBAI_ADDR(vs
->vs_ifuba
.ifu_r
.ifrw_info
);
addr
->vviba
= (u_short
)ubaaddr
;
addr
->vviea
= (u_short
)(ubaaddr
>> 16);
addr
->vviwc
= -(VVBUFSIZE
) >> 1;
addr
->vvicsr
= VV_IEN
| VV_HEN
| VV_DEN
| VV_ENB
;
vs
->vs_if
.if_flags
|= IFF_UP
;
* Do a moderately thorough self-test in all three modes. Mostly
* to keeps defective nodes off the ring, rather than to be especially
* thorough. The key issue is to detect any cable breaks before joining
* the ring. Return our node address on success, return -1 on failure.
/* the three self-test modes */
static u_short vv_modes
[] = {
VV_STE
|VV_LPB
, /* digital loopback */
VV_STE
, /* analog loopback */
VV_HEN
/* network mode */
register struct vv_softc
*vs
;
register struct uba_device
*ui
;
register struct vvreg
*addr
;
register struct vv_header
*v
;
register int i
, successes
, failures
, waitcount
;
addr
= (struct vvreg
*)ui
->ui_addr
;
* Build a multicast message to identify our address
* We need do this only once, since nobody else is about to use
* the intermediate transmit buffer (ifu_w.ifrw_addr) that
* if_ubainit() aquired for us.
m
= m_get(M_DONTWAIT
, MT_HEADER
);
printf("vv%d: can't initialize, m_get() failed\n", unit
);
m
->m_len
= sizeof(struct vv_header
);
v
= mtod(m
, struct vv_header
*);
v
->vh_dhost
= VV_BROADCAST
; /* multicast destination address */
v
->vh_shost
= 0; /* will be overwritten with ours */
v
->vh_version
= RING_VERSION
;
v
->vh_type
= RING_DIAGNOSTICS
;
/* map xmit message into uba, copying to intermediate buffer */
vs
->vs_olen
= if_wubaput(&vs
->vs_ifuba
, m
);
* For each of the modes (digital, analog, network), go through
* a self-test that requires me to send VVIDENTSUCC good packets
* in VVIDENTRETRY attempts. Use broadcast destination to find out
* who I am, then use this as my address to check my address match
* logic. Only data checked is the vh_type field.
for (i
= 0; i
< 3; i
++) {
successes
= 0; /* clear successes for this mode */
failures
= 0; /* and clear failures, too */
/* take over device, and leave ring */
addr
->vvicsr
= vv_modes
[i
]; /* test mode */
* let the flag and token timers pop so that the init ring bit
* will be allowed to work, by waiting about 1 second
while ((successes
< VVIDENTSUCC
) && (failures
< VVIDENTRETRY
))
ubaaddr
= UBAI_ADDR(vs
->vs_ifuba
.ifu_r
.ifrw_info
);
addr
->vvicsr
= VV_RST
| vv_modes
[i
]; /* abort last */
addr
->vviba
= (u_short
) ubaaddr
;
addr
->vviea
= (u_short
) (ubaaddr
>> 16);
addr
->vviwc
= -(VVBUFSIZE
) >> 1;
addr
->vvicsr
= vv_modes
[i
] | VV_DEN
| VV_ENB
;
/* purge stale data from BDP */
if (vs
->vs_ifuba
.ifu_flags
& UBA_NEEDBDP
)
UBAPURGE(vs
->vs_ifuba
.ifu_uba
,
vs
->vs_ifuba
.ifu_w
.ifrw_bdp
);
ubaaddr
= UBAI_ADDR(vs
->vs_ifuba
.ifu_w
.ifrw_info
);
addr
->vvocsr
= VV_RST
; /* abort last try */
addr
->vvoba
= (u_short
) ubaaddr
;
addr
->vvoea
= (u_short
) (ubaaddr
>> 16);
addr
->vvowc
= -((vs
->vs_olen
+ 1) >> 1);
addr
->vvocsr
= VV_CPB
| VV_DEN
| VV_INR
| VV_ENB
;
/* poll receive side for completion */
DELAY(10000); /* give it a chance */
for (waitcount
= 0; waitcount
< 10; waitcount
++) {
if (addr
->vvicsr
& VV_RDY
)
failures
++; /* no luck */
gotit
: /* we got something--is it any good? */
if ((addr
->vvicsr
& (VVRERR
|VV_LDE
)) ||
(addr
->vvocsr
& (VVXERR
|VV_RFS
))) {
/* Purge BDP before looking at received packet */
if (vs
->vs_ifuba
.ifu_flags
& UBA_NEEDBDP
)
UBAPURGE(vs
->vs_ifuba
.ifu_uba
,
vs
->vs_ifuba
.ifu_r
.ifrw_bdp
);
m
= if_rubaget(&vs
->vs_ifuba
, sizeof(struct vv_header
),
v
= (struct vv_header
*)(vs
->vs_ifuba
.ifu_r
.ifrw_addr
);
/* check message type, catch our node address */
if ((v
->vh_type
& 0xff) == RING_DIAGNOSTICS
) {
shost
= v
->vh_shost
& 0xff;
/* send to ourself now */
(vs
->vs_ifuba
.ifu_r
.ifrw_addr
))
v
->vh_type
= 0; /* clear to check again */
if (failures
>= VVIDENTRETRY
)
printf("vv%d: failed self-test after %d tries \
unit
, VVIDENTRETRY
, i
== 0 ? "digital loopback" :
(i
== 1 ? "analog loopback" : "network"));
printf("vv%d: icsr = %b, ocsr = %b\n",
unit
, 0xffff & addr
->vvicsr
, VV_IBITS
,
0xffff & addr
->vvocsr
, VV_OBITS
);
addr
->vvicsr
= VV_RST
; /* kill the sick board */
/* deallocate mbuf used for send packet (won't be one, anyways) */
if (vs
->vs_ifuba
.ifu_xtofree
) {
m_freem(vs
->vs_ifuba
.ifu_xtofree
);
vs
->vs_ifuba
.ifu_xtofree
= 0;
* Start or restart output on interface.
* If interface is active, this is a retransmit, so just
* restuff registers and go.
* If interface is not already active, get another datagram
* to send off of the interface queue, and map it to the interface
* before starting the output.
register struct uba_device
*ui
;
register struct vv_softc
*vs
;
register struct vvreg
*addr
;
register int unit
, ubaaddr
, dest
, s
;
* Not already active: dequeue another request
* and map it to the UNIBUS. If no more requests,
IF_DEQUEUE(&vs
->vs_if
.if_snd
, m
);
dest
= mtod(m
, struct vv_header
*)->vh_dhost
;
vs
->vs_olen
= if_wubaput(&vs
->vs_ifuba
, m
);
* Have request mapped to UNIBUS for transmission.
* Purge any stale data from this BDP, and start the output.
* Make sure this packet will fit in the interface.
if (vs
->vs_olen
> VVBUFSIZE
) {
printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit
, vs
->vs_olen
);
panic("vvdriver vs_olen botch");
vs
->vs_if
.if_timer
= VVTIMEOUT
;
if (vs
->vs_ifuba
.ifu_flags
& UBA_NEEDBDP
)
UBAPURGE(vs
->vs_ifuba
.ifu_uba
, vs
->vs_ifuba
.ifu_w
.ifrw_bdp
);
addr
= (struct vvreg
*)ui
->ui_addr
;
ubaaddr
= UBAI_ADDR(vs
->vs_ifuba
.ifu_w
.ifrw_info
);
addr
->vvoba
= (u_short
) ubaaddr
;
addr
->vvoea
= (u_short
) (ubaaddr
>> 16);
addr
->vvowc
= -((vs
->vs_olen
+ 1) >> 1);
addr
->vvowc
= -((vs
->vs_olen
+ 1) >> 1); /* extra byte is garbage */
if (addr
->vvocsr
& VV_NOK
)
vs
->vs_init
++; /* count ring inits */
addr
->vvocsr
= VV_IEN
| VV_CPB
| VV_DEN
| VV_INR
| VV_ENB
;
* proNET transmit interrupt
* Start another output if more data to send.
register struct uba_device
*ui
;
register struct vv_softc
*vs
;
register struct vvreg
*addr
;
splx(vv_softc
[unit
].vs_ipl
);
addr
= (struct vvreg
*)ui
->ui_addr
;
oc
= 0xffff & (addr
->vvocsr
);
if (vs
->vs_oactive
== 0) {
vvprintf("vv%d: stray interrupt vvocsr = %b\n", unit
,
* we retransmit on soft error
* TODO: sort retransmits to end of queue if possible!
if (oc
& (VV_OPT
| VV_RFS
)) {
if (vs
->vs_tries
++ < VVRETRY
) {
vs
->vs_if
.if_collisions
++;
vvstart(unit
); /* restart this message */
vvprintf("vv%d: error vvocsr = %b\n", unit
, 0xffff & oc
,
if (vs
->vs_ifuba
.ifu_xtofree
) {
m_freem(vs
->vs_ifuba
.ifu_xtofree
);
vs
->vs_ifuba
.ifu_xtofree
= 0;
* Transmit watchdog timer routine.
* This routine gets called when we lose a transmit interrupt.
* The best we can do is try to restart output.
register struct vv_softc
*vs
;
vvprintf("vv%d: lost a transmit interrupt.\n", unit
);
* proNET interface receiver interrupt.
* If input error just drop packet.
* Otherwise purge input buffered data path and examine
* packet to determine type. If can't determine length
* from type, then have to drop packet. Otherwise decapsulate
* packet based on type and pass to type specific higher-level
register struct vv_softc
*vs
;
register struct vvreg
*addr
;
register struct vv_header
*vv
;
register struct ifqueue
*inq
;
int ubaaddr
, len
, off
, s
;
splx(vv_softc
[unit
].vs_ipl
);
addr
= (struct vvreg
*)vvinfo
[unit
]->ui_addr
;
if (vs
->vs_ifuba
.ifu_flags
& UBA_NEEDBDP
)
UBAPURGE(vs
->vs_ifuba
.ifu_uba
, vs
->vs_ifuba
.ifu_r
.ifrw_bdp
);
if (addr
->vvicsr
& VVRERR
) {
vvprintf("vv%d: receive error, vvicsr = %b\n", unit
,
0xffff&(addr
->vvicsr
), VV_IBITS
);
if (addr
->vvicsr
& VV_BDF
)
if (addr
->vvicsr
& VV_LDE
) {
/* we don't have to clear it because the receive command */
/* writes 0 to parity bit */
* only on 10 megabit proNET is VV_LDE an end-to-end parity
* bit. On 80 megabit, it returns to the intended use of
* node-to-node parity. End-to-end parity errors on 80 megabit
* Get packet length from residual word count
* Compute header offset if trailer protocol
* Pull packet off interface. Off is nonzero if packet
* has trailing header; if_rubaget will then force this header
* information to be at the front. The vh_info field
* carries the offset to the trailer data in trailer
vv
= (struct vv_header
*)(vs
->vs_ifuba
.ifu_r
.ifrw_addr
);
resid
= addr
->vviwc
& 01777; /* only low 10 bits valid */
resid
|= 0176000; /* high 6 bits are undefined */
len
= ((VVBUFSIZE
>> 1) + resid
) << 1;
len
-= sizeof(struct vv_header
);
if ((addr
->vvicsr
& VV_DPR
) || len
> VVMRU
|| len
<= 0) {
vvprintf("vv%d: len too long or short, \
len = %d, vvicsr = %b\n",
unit
, len
, 0xffff&(addr
->vvicsr
), VV_IBITS
);
/* check the protocol header version */
if (vv
->vh_version
!= RING_VERSION
) {
vvprintf("vv%d: bad protocol header version %d\n",
unit
, vv
->vh_version
& 0xff);
#define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off))))
if (vv
->vh_type
== RING_TRAILER
) {
off
= ntohs((u_short
)vv
->vh_info
);
vvprintf("vv%d: off > VVMTU, off = %d, vvicsr = %b\n",
unit
, off
, 0xffff&(addr
->vvicsr
), VV_IBITS
);
vv
->vh_type
= ntohs(*vvdataaddr(vv
, off
, u_short
*));
resid
= ntohs(*(vvdataaddr(vv
, off
+sizeof(u_short
), u_short
*)));
vvprintf("vv%d: trailer packet too short\n", unit
);
vvprintf("vv%d: off = %d, resid = %d, vvicsr = %b\n",
0xffff&(addr
->vvicsr
), VV_IBITS
);
vvprintf("vv%d: len is zero, vvicsr = %b\n", unit
,
0xffff&(addr
->vvicsr
), VV_IBITS
);
m
= if_rubaget(&vs
->vs_ifuba
, len
, off
, &vs
->vs_if
);
vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit
,
0xffff&(addr
->vvicsr
), VV_IBITS
);
ifp
= *(mtod(m
, struct ifnet
**));
m
->m_off
+= 2 * sizeof (u_short
);
m
->m_len
-= 2 * sizeof (u_short
);
*(mtod(m
, struct ifnet
**)) = ifp
;
/* Keep track of source address of this packet */
vs
->vs_lastr
= vv
->vh_shost
;
* Demultiplex on packet type
vvprintf("vv%d: unknown pkt type 0x%x\n", unit
, vv
->vh_type
);
* Reset for the next packet.
ubaaddr
= UBAI_ADDR(vs
->vs_ifuba
.ifu_r
.ifrw_info
);
addr
->vviba
= (u_short
) ubaaddr
;
addr
->vviea
= (u_short
) (ubaaddr
>> 16);
addr
->vviwc
= -(VVBUFSIZE
) >> 1;
addr
->vvicsr
= VV_HEN
| VV_IEN
| VV_DEN
| VV_ENB
;
* Drop packet on floor -- count them!!
* Encapsulate a packet of type family for the local net.
* Use trailer local net encapsulation if enough data in first
* packet leaves a multiple of 512 bytes of data in remainder.
register struct vv_header
*vv
;
register struct vvreg
*addr
;
register struct vv_softc
*vs
;
addr
= (struct vvreg
*)vvinfo
[unit
]->ui_addr
;
* Check to see if the input side has wedged due the UBA
* We are lower than device ipl when we enter this routine,
* so if the interface is ready with an input packet then
* an input interrupt must have slipped through the cracks.
* Avoid the race with an input interrupt by watching to see
* if any packets come in.
s
= vs
->vs_if
.if_ipackets
;
if (addr
->vvicsr
& VV_RDY
&& s
== vs
->vs_if
.if_ipackets
) {
vvprintf("vv%d: lost a receive interrupt, icsr = %b\n",
unit
, 0xffff&(addr
->vvicsr
), VV_IBITS
);
switch (dst
->sa_family
) {
if (in_broadcast(((struct sockaddr_in
*)dst
)->sin_addr
))
dest
= in_lnaof(((struct sockaddr_in
*)dst
)->sin_addr
);
if (dest
== vs
->vs_host
&& (loif
.if_flags
& IFF_UP
))
return (looutput(&loif
, m0
, dst
));
off
= ntohs((u_short
)mtod(m
, struct ip
*)->ip_len
) - m
->m_len
;
* Trailerize, if the configuration allows it.
* TODO: Need per host negotiation.
if ((ifp
->if_flags
& IFF_NOTRAILERS
) == 0)
if (off
> 0 && (off
& 0x1ff) == 0 &&
m
->m_off
>= MMINOFF
+ 2 * sizeof (u_short
)) {
m
->m_off
-= 2 * sizeof (u_short
);
m
->m_len
+= 2 * sizeof (u_short
);
*mtod(m
, u_short
*) = htons((short)RING_IP
);
*(mtod(m
, u_short
*) + 1) = htons((u_short
)m
->m_len
);
printf("vv%d: can't handle af%d\n", unit
, dst
->sa_family
);
* Packet to be sent as trailer: move first packet
* (control information) to end of chain.
* Add local net header. If no space in first mbuf,
if (m
->m_off
> MMAXOFF
||
MMINOFF
+ sizeof (struct vv_header
) > m
->m_off
) {
m
= m_get(M_DONTWAIT
, MT_HEADER
);
m
->m_len
= sizeof (struct vv_header
);
m
->m_off
-= sizeof (struct vv_header
);
m
->m_len
+= sizeof (struct vv_header
);
vv
= mtod(m
, struct vv_header
*);
vv
->vh_shost
= vs
->vs_host
;
vv
->vh_version
= RING_VERSION
;
vv
->vh_info
= htons((u_short
)off
);
* Queue message on interface, and start output if interface
if (IF_QFULL(&ifp
->if_snd
)) {
IF_ENQUEUE(&ifp
->if_snd
, m
);
* Process an ioctl request.
register struct ifnet
*ifp
;
struct ifaddr
*ifa
= (struct ifaddr
*) data
;
int s
= splimp(), error
= 0;
if ((ifp
->if_flags
& IFF_RUNNING
) == 0)
if ((ifp
->if_flags
& IFF_UP
) == 0)
* Attempt to check agreement of protocol address
switch (ifa
->ifa_addr
.sa_family
) {
if ((in_lnaof(IA_SIN(ifa
)->sin_addr
) & 0xff) !=
vv_softc
[ifp
->if_unit
].vs_host
)
* vvprt_hdr(s, v) print the local net header in "v"
register struct vv_header
*v
;
printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n",
0xff & (int)(v
->vh_dhost
), 0xff & (int)(v
->vh_shost
),
0xff & (int)(v
->vh_version
), 0xff & (int)(v
->vh_type
),
0xffff & (int)(v
->vh_info
));