/* if_imp.c 4.3 82/02/01 */
* ARPAnet IMP interface driver.
* The IMP-host protocol is handled here, leaving
* hardware specifics to the lower level interface driver.
#include "../h/protosw.h"
#include "../net/in_systm.h"
#include "../net/if_imp.h"
#include "../net/ip_var.h"
* IMP software status per interface.
* (partially shared with the hardware specific module)
* Each interface is referenced by a network interface structure,
* imp_if, which the routing code uses to locate the interface.
* This structure contains the output queue for the interface, its
* address, ... IMP specific structures used in connecting the
* IMP software modules to the hardware specific interface routines
* are also stored here. These structures are visible in the interface
* driver through back pointers set up in the hardware's attach routine.
* NOTE: imp_if and imp_cb are assumed adjacent in hardware code.
struct ifnet imp_if
; /* network visible interface */
struct impcb imp_cb
; /* hooks to hardware module */
u_char imp_state
; /* current state of IMP */
char imp_dropcnt
; /* used during initialization */
short imp_timer
; /* going down timer */
* Messages from IMP regarding why
static char *impmsg
[] = {
* IMP attach routine. Called from hardware device attach routine
* at configuration time with a pointer to the UNIBUS device structure.
* Sets up local state and returns pointer to base of ifnet+impcb
* structures. This is then used by the device's attach routine
* set up its back pointers.
struct imp_softc
*sc
= &imp_softc
[ui
->ui_unit
];
register struct ifnet
*ifp
= &sc
->imp_if
;
/* UNIT COULD BE AMBIGUOUS */
ifp
->if_unit
= ui
->ui_unit
;
ifp
->if_net
= ui
->ui_flags
;
/* ifp->if_addr = if_makeaddr(ifp->if_net, ifp->if_host); */
/* kludge to hand pointers back to hardware attach routine */
return ((int)&sc
->imp_if
);
* IMP initialization routine: call hardware module to
* setup UNIBUS resources, init state and get ready for
* NOOPs the IMP should send us, and that we want to drop.
register struct imp_softc
*sc
= &imp_softc
[unit
];
(*sc
->imp_cb
.ic_init
)(unit
);
sc
->imp_state
= IMPS_INIT
;
sc
->imp_dropcnt
= IMP_DROPCNT
;
struct sockproto impproto
= { PF_IMPLINK
};
struct sockaddr_in impdst
= { AF_IMPLINK
};
struct sockaddr_in impsrc
= { AF_IMPLINK
};
* ARPAnet 1822 input routine.
* Called from hardware input interrupt routine to handle 1822
* IMP-host messages. Type 0 messages (non-control) are
* passed to higher level protocol processors on the basis
* of link number. Other type messages (control) are handled here.
register struct imp_leader
*ip
;
register struct imp_softc
*sc
= &imp_softc
[unit
];
register struct host
*hp
;
register struct ifqueue
*inq
;
* We should generate a "bad leader" message
* to the IMP about messages too short.
if (m
->m_len
< sizeof(struct imp_leader
) &&
m_pullup(m
, sizeof(struct imp_leader
)) == 0)
ip
= mtod(m
, struct imp_leader
*);
* Check leader type -- should notify IMP
if (ip
->il_format
!= IMP_NFF
)
* Certain messages require a host structure.
* Do this in one shot here.
case IMPTYPE_HOSTUNREACH
:
addr
.s_host
= ntohs(ip
->il_host
); /* XXX */
* Data for a protocol. Dispatch to the appropriate
* protocol routine (running at software interrupt).
* If this isn't a raw interface, advance pointer
* into mbuf past leader (done below).
ip
->il_length
= ntohs(ip
->il_length
) >> 3;
* IMP leader error. Reset the IMP and discard the packet.
* According to 1822 document, this message
* will be generated in response to the
* first noop sent to the IMP after
* the host resets the IMP interface.
if (sc
->imp_state
!= IMPS_RESET
) {
imperr(sc
, "leader error");
h_reset(sc
->imp_if
.if_net
); /* XXX */
* IMP going down. Print message, and if not immediate,
* set off a timer to insure things will be reset at the
if ((ip
->il_link
& IMP_DMASK
) == 0) {
sc
->imp_state
= IMPS_GOINGDOWN
;
timeout(impdown
, sc
, 30 * 60 * HZ
);
imperr(sc
, "going down %s", impmsg
[ip
->il_link
& IMP_DMASK
]);
* A NOP usually seen during the initialization sequence.
* Compare the local address with that in the message.
* Reset the local address notion if it doesn't match.
if (sc
->imp_state
== IMPS_DOWN
) {
sc
->imp_state
= IMPS_INIT
;
sc
->imp_dropcnt
= IMP_DROPCNT
;
if (sc
->imp_state
== IMPS_INIT
&& --sc
->imp_dropcnt
== 0) {
/* restart output in case something was q'd */
(*sc
->imp_cb
.ic_start
)(sc
->imp_if
.if_unit
);
if (ip
->il_host
!= sc
->imp_if
.if_addr
.s_host
||
ip
->il_impno
!= sc
->imp_if
.if_addr
.s_imp
) {
sc
->imp_if
.if_addr
.s_host
= ip
->il_host
;
sc
->imp_if
.if_addr
.s_imp
= ip
->il_imp
;
imperr(sc
, "imp%d: address set to %d/%d\n",
ip
->il_host
, ip
->il_impno
);
* RFNM or INCOMPLETE message, record in
* host table and prime output routine.
* SHOULD NOTIFY PROTOCOL ABOUT INCOMPLETES.
hp
->h_q
->m_act
= n
->m_act
;
* Host or IMP can't be reached. Flush any packets
* awaiting transmission and release the host structure.
* HOW DO WE NOTIFY THE PROTOCOL?
* HOW DO WE AGE THE HOST STRUCTURE TO SAVE STATUS?
case IMPTYPE_HOSTUNREACH
:
h_free(hp
); /* won't work right */
* Error in data. Clear RFNM status for this host and send
* noops to the IMP to clear the interface.
imperr(sc
, "data error");
imperr(sc
, "interface reset");
sc
->imp_state
= IMPS_RESET
;
sc
->imp_if
.if_collisions
++; /* XXX */
* Queue on protocol's input queue.
m
->m_len
-= sizeof(struct imp_leader
);
m
->m_off
+= sizeof(struct imp_leader
);
impproto
.sp_protocol
= ip
->il_link
;
impdst
.sin_addr
= sc
->imp_if
.if_addr
;
impsrc
.sin_addr
.s_net
= ip
->il_network
;
impsrc
.sin_addr
.s_host
= ip
->il_host
;
impsrc
.sin_addr
.s_imp
= ip
->il_imp
;
raw_input(m
, impproto
, impdst
, impsrc
);
* Bring the IMP down after notification.
sc
->imp_state
= IMPS_DOWN
;
/* notify protocols with messages waiting? */
printf("imp%d: ", sc
->imp_if
.if_unit
);
* ARPAnet 1822 output routine.
* Called from higher level protocol routines to set up messages for
* transmission to the imp. Sets up the header and calls impsnd to
* enqueue the message for this IMP's hardware driver.
register struct ifnet
*ifp
;
register struct imp_leader
*imp
;
register struct mbuf
*m
= m0
;
int x
, dhost
, dimp
, dlink
, len
;
* Don't even try if the IMP is unavailable.
x
= imp_softc
[ifp
->if_unit
].imp_state
;
if (x
== IMPS_DOWN
|| x
== IMPS_GOINGDOWN
)
register struct ip
*ip
= mtod(m0
, struct ip
*);
dhost
= ip
->ip_dst
.s_host
;
printf("imp%d: can't encapsulate pf%d\n", ifp
->if_unit
, pf
);
* Add IMP leader. If there's not enough space in the
* first mbuf, allocate another. If that should fail, we
if (m
->m_off
> MMAXOFF
||
MMINOFF
+ sizeof(struct imp_leader
) > m
->m_off
) {
m
->m_len
= sizeof(struct imp_leader
);
m
->m_off
-= sizeof(struct imp_leader
);
m
->m_len
+= sizeof(struct imp_leader
);
imp
= mtod(m
, struct imp_leader
*);
imp
->il_format
= IMP_NFF
;
imp
->il_length
= (len
+ sizeof(struct imp_leader
)) << 3;
* Hand message to impsnd to perform RFNM counting
* and eventual transmission.
* Put a message on an interface's output queue.
* Perform RFNM counting: no more than 8 message may be
* in flight to any one host.
register struct imp_leader
*ip
;
register struct host
*hp
;
ip
= mtod(m
, struct imp_leader
*);
* Do RFNM counting for data messages
* (no more than 8 outstanding to any host)
if (ip
->il_mtype
== IMPTYPE_DATA
) {
addr
.s_net
= ifp
->if_net
;
addr
.s_host
= ip
->il_host
;
* If IMP would block, queue until RFNM
* Keeping the count in the host structure
* causes the packing scheme to lose too much.
for (; n
!= (struct mbuf
*)hp
; n
= n
->m_act
)
* Q is kept as circulare list with h_q
* (head) pointing to the last entry.
IF_ENQUEUE(&ifp
->if_snd
, m
);
icp
= &imp_softc
[ifp
->if_unit
].imp_cb
;
if (icp
->ic_oactive
== 0)
(*icp
->ic_start
)(ifp
->if_unit
);
* Put three 1822 NOOPs at the head of the output queue.
* Part of host-IMP initialization procedure.
* (Should return success/failure, but noone knows
* what to do with this, so why bother?)
register struct imp_softc
*sc
;
register struct imp_leader
*ip
;
sc
->imp_state
= IMPS_INIT
;
sc
->imp_dropcnt
= IMP_DROPCNT
;
for (i
= 0; i
< IMP_DROPCNT
; i
++ ) {
if ((m
= m_getclr(M_DONTWAIT
)) == 0)
m
->m_len
= sizeof(struct imp_leader
);
ip
= mtod(m
, struct imp_leader
*);
ip
->il_mtype
= IMPTYPE_NOOP
;
IF_PREPEND(&sc
->imp_if
.if_snd
, m
);
if (sc
->imp_cb
.ic_oactive
== 0)
(*sc
->imp_cb
.ic_start
)(sc
->imp_if
.if_unit
);