1*5640Sroot /* if_imp.c 4.1 82/02/01 */ 2*5640Sroot 3*5640Sroot #include "imp.h" 4*5640Sroot #if NIMP > 0 5*5640Sroot /* 6*5640Sroot * ARPAnet IMP interface driver. 7*5640Sroot * 8*5640Sroot * The IMP-host protocol is handled here, leaving 9*5640Sroot * hardware specifics to the lower level interface driver. 10*5640Sroot */ 11*5640Sroot #include "../h/param.h" 12*5640Sroot #include "../h/systm.h" 13*5640Sroot #include "../h/mbuf.h" 14*5640Sroot #include "../h/pte.h" 15*5640Sroot #include "../h/buf.h" 16*5640Sroot #include "../h/protosw.h" 17*5640Sroot #include "../h/socket.h" 18*5640Sroot #include "../h/ubareg.h" 19*5640Sroot #include "../h/ubavar.h" 20*5640Sroot #include "../h/cpu.h" 21*5640Sroot #include "../h/mtpr.h" 22*5640Sroot #include "../h/vmmac.h" 23*5640Sroot #include "../net/in.h" 24*5640Sroot #include "../net/in_systm.h" 25*5640Sroot #include "../net/if.h" 26*5640Sroot #include "../net/if_imp.h" 27*5640Sroot #include "../net/host.h" 28*5640Sroot #include "../net/ip.h" 29*5640Sroot #include "../net/ip_var.h" 30*5640Sroot 31*5640Sroot /* 32*5640Sroot * IMP software status per interface. 33*5640Sroot * (partially shared with the hardware specific module) 34*5640Sroot * 35*5640Sroot * Each interface is referenced by a network interface structure, 36*5640Sroot * imp_if, which the routing code uses to locate the interface. 37*5640Sroot * This structure contains the output queue for the interface, its 38*5640Sroot * address, ... IMP specific structures used in connecting the 39*5640Sroot * IMP software modules to the hardware specific interface routines 40*5640Sroot * are also stored here. These structures are visible in the interface 41*5640Sroot * driver through back pointers set up in the hardware's attach routine. 42*5640Sroot * 43*5640Sroot * NOTE: imp_if and imp_cb are assumed adjacent in hardware code. 44*5640Sroot */ 45*5640Sroot struct imp_softc { 46*5640Sroot struct ifnet imp_if; /* network visible interface */ 47*5640Sroot struct impcb imp_cb; /* hooks to hardware module */ 48*5640Sroot u_char imp_state; /* current state of IMP */ 49*5640Sroot char imp_dropcnt; /* used during initialization */ 50*5640Sroot short imp_timer; /* going down timer */ 51*5640Sroot } imp_softc[NIMP]; 52*5640Sroot 53*5640Sroot /* 54*5640Sroot * Messages from IMP regarding why 55*5640Sroot * it's going down. 56*5640Sroot */ 57*5640Sroot static char *impmsg[] = { 58*5640Sroot "in 30 seconds", 59*5640Sroot "for hardware PM", 60*5640Sroot "to reload software", 61*5640Sroot "for emergency reset" 62*5640Sroot }; 63*5640Sroot 64*5640Sroot /* 65*5640Sroot * IMP attach routine. Called from hardware device attach routine 66*5640Sroot * at configuration time with a pointer to the UNIBUS device structure. 67*5640Sroot * Sets up local state and returns pointer to base of ifnet+impcb 68*5640Sroot * structures. This is then used by the device's attach routine 69*5640Sroot * set up its back pointers. 70*5640Sroot */ 71*5640Sroot impattach(ui) 72*5640Sroot struct uba_device *ui; 73*5640Sroot { 74*5640Sroot struct imp_softc *sc = &imp_softc[ui->ui_unit]; 75*5640Sroot register struct ifnet *ifp = &sc->imp_if; 76*5640Sroot 77*5640Sroot COUNT(IMPATTACH); 78*5640Sroot /* UNIT COULD BE AMBIGUOUS */ 79*5640Sroot ifp->if_unit = ui->ui_unit; 80*5640Sroot ifp->if_name = "imp"; 81*5640Sroot ifp->if_mtu = IMP_MTU; 82*5640Sroot ifp->if_net = ui->ui_flags; 83*5640Sroot /* ifp->if_host = ... */ 84*5640Sroot /* ifp->if_addr = if_makeaddr(ifp->if_net, ifp->if_host); */ 85*5640Sroot if_attach(ifp); 86*5640Sroot /* kludge to hand pointers back to hardware attach routine */ 87*5640Sroot return ((int)&sc->imp_if); 88*5640Sroot } 89*5640Sroot 90*5640Sroot /* 91*5640Sroot * IMP initialization routine: call hardware module to 92*5640Sroot * setup UNIBUS resources, init state and get ready for 93*5640Sroot * NOOPs the IMP should send us, and that we want to drop. 94*5640Sroot */ 95*5640Sroot impinit(unit) 96*5640Sroot int unit; 97*5640Sroot { 98*5640Sroot register struct imp_softc *sc = &imp_softc[unit]; 99*5640Sroot 100*5640Sroot (*sc->imp_cb.ic_init)(unit); 101*5640Sroot sc->imp_state = IMPS_INIT; 102*5640Sroot sc->imp_dropcnt = IMP_DROPCNT; 103*5640Sroot } 104*5640Sroot 105*5640Sroot struct sockproto impproto = { PF_IMPLINK }; 106*5640Sroot struct sockaddr_in impaddr = { AF_IMPLINK }; 107*5640Sroot 108*5640Sroot /* 109*5640Sroot * ARPAnet 1822 input routine. 110*5640Sroot * Called from hardware input interrupt routine to handle 1822 111*5640Sroot * IMP-host messages. Type 0 messages (non-control) are 112*5640Sroot * passed to higher level protocol processors on the basis 113*5640Sroot * of link number. Other type messages (control) are handled here. 114*5640Sroot */ 115*5640Sroot impinput(unit, m0) 116*5640Sroot int unit; 117*5640Sroot struct mbuf *m0; 118*5640Sroot { 119*5640Sroot int s; 120*5640Sroot register struct mbuf *m; 121*5640Sroot register struct imp_leader *ip; 122*5640Sroot register struct imp_softc *sc = &imp_softc[unit]; 123*5640Sroot register struct host *hp; 124*5640Sroot register struct ifqueue *inq; 125*5640Sroot struct in_addr addr; 126*5640Sroot 127*5640Sroot COUNT(IMP_INPUT); 128*5640Sroot m = m0; 129*5640Sroot if (m->m_len < sizeof(struct imp_leader) && 130*5640Sroot m_pullup(m, sizeof(struct imp_leader)) == 0) 131*5640Sroot goto drop; 132*5640Sroot ip = mtod(m, struct imp_leader *); 133*5640Sroot 134*5640Sroot /* check leader type. */ 135*5640Sroot if (ip->il_format != IMP_NFF) 136*5640Sroot goto drop; 137*5640Sroot 138*5640Sroot /* 139*5640Sroot * Certain messages require a host structure. 140*5640Sroot * Do this in one shot here. 141*5640Sroot */ 142*5640Sroot switch (ip->il_mtype) { 143*5640Sroot 144*5640Sroot case IMPTYPE_RFNM: 145*5640Sroot case IMPTYPE_INCOMPLETE: 146*5640Sroot case IMPTYPE_HOSTDEAD: 147*5640Sroot case IMPTYPE_HOSTUNREACH: 148*5640Sroot case IMPTYPE_BADDATA: 149*5640Sroot addr.s_host = ntohs(ip->il_host); 150*5640Sroot hp = h_lookup(addr); 151*5640Sroot break; 152*5640Sroot } 153*5640Sroot 154*5640Sroot switch (ip->il_mtype) { 155*5640Sroot 156*5640Sroot /* 157*5640Sroot * Data for a protocol. Dispatch to the appropriate 158*5640Sroot * protocol routine (running at software interrupt). 159*5640Sroot * If this isn't a raw interface, advance pointer 160*5640Sroot * into mbuf past leader. 161*5640Sroot */ 162*5640Sroot case IMPTYPE_DATA: 163*5640Sroot ip->il_length = ntohs(ip->il_length) >> 3; 164*5640Sroot break; 165*5640Sroot 166*5640Sroot /* 167*5640Sroot * IMP leader error. Reset the IMP and discard the packet. 168*5640Sroot */ 169*5640Sroot case IMPTYPE_BADLEADER: 170*5640Sroot imperr(sc, "leader error"); 171*5640Sroot h_reset(sc->imp_if.if_net); /* XXX */ 172*5640Sroot impnoops(sc); 173*5640Sroot goto drop; 174*5640Sroot 175*5640Sroot /* 176*5640Sroot * IMP going down. Print message, and if not immediate, 177*5640Sroot * set off a timer to insure things will be reset at the 178*5640Sroot * appropriate time. 179*5640Sroot */ 180*5640Sroot case IMPTYPE_DOWN: 181*5640Sroot if ((ip->il_link & IMP_DMASK) == 0) { 182*5640Sroot sc->imp_state = IMPS_GOINGDOWN; 183*5640Sroot sc->imp_timer = IMPTV_DOWN; 184*5640Sroot } 185*5640Sroot imperr(sc, "going down %s", impmsg[ip->il_link & IMP_DMASK]); 186*5640Sroot goto drop; 187*5640Sroot 188*5640Sroot /* 189*5640Sroot * A NOP usually seen during the initialization sequence. 190*5640Sroot * Compare the local address with that in the message. 191*5640Sroot * Reset the local address notion if it doesn't match. 192*5640Sroot */ 193*5640Sroot case IMPTYPE_NOOP: 194*5640Sroot if (sc->imp_state == IMPS_INIT && --sc->imp_dropcnt == 0) { 195*5640Sroot sc->imp_state = IMPS_UP; 196*5640Sroot /* restart output in case something was q'd */ 197*5640Sroot (*sc->imp_cb.ic_start)(sc->imp_if.if_unit); 198*5640Sroot } 199*5640Sroot if (ip->il_host != sc->imp_if.if_addr.s_host || 200*5640Sroot ip->il_impno != sc->imp_if.if_addr.s_imp) { 201*5640Sroot sc->imp_if.if_addr.s_host = ip->il_host; 202*5640Sroot sc->imp_if.if_addr.s_imp = ip->il_imp; 203*5640Sroot imperr(sc, "imp%d: address set to %d/%d\n", 204*5640Sroot ip->il_host, ip->il_impno); 205*5640Sroot } 206*5640Sroot goto drop; 207*5640Sroot 208*5640Sroot /* 209*5640Sroot * RFNM or INCOMPLETE message, record in 210*5640Sroot * host table and prime output routine. 211*5640Sroot * 212*5640Sroot * SHOULD RETRANSMIT ON INCOMPLETE. 213*5640Sroot */ 214*5640Sroot case IMPTYPE_RFNM: 215*5640Sroot case IMPTYPE_INCOMPLETE: 216*5640Sroot if (hp && hp->h_rfnm) { 217*5640Sroot register struct mbuf *n; 218*5640Sroot 219*5640Sroot hp->h_rfnm--; 220*5640Sroot /* poke holding queue */ 221*5640Sroot if (n = hp->h_q) { 222*5640Sroot if (n->m_act == n) 223*5640Sroot hp->h_q = 0; 224*5640Sroot else { 225*5640Sroot n = n->m_act; 226*5640Sroot hp->h_q->m_act = n->m_act; 227*5640Sroot } 228*5640Sroot (void) impsnd(n, sc); 229*5640Sroot } 230*5640Sroot } 231*5640Sroot break; 232*5640Sroot 233*5640Sroot /* 234*5640Sroot * Host or IMP can't be reached. Flush any packets 235*5640Sroot * awaiting transmission and release the host structure. 236*5640Sroot * 237*5640Sroot * HOW DO WE NOTIFY THE PROTOCOL? 238*5640Sroot * HOW DO WE AGE THE HOST STRUCTURE TO SAVE STATUS? 239*5640Sroot */ 240*5640Sroot case IMPTYPE_HOSTDEAD: 241*5640Sroot case IMPTYPE_HOSTUNREACH: 242*5640Sroot if (hp) 243*5640Sroot h_free(hp); /* won't work right */ 244*5640Sroot break; 245*5640Sroot 246*5640Sroot /* 247*5640Sroot * Error in data. Clear RFNM status for this host and send 248*5640Sroot * noops to the IMP to clear the interface. 249*5640Sroot */ 250*5640Sroot case IMPTYPE_BADDATA: 251*5640Sroot imperr(sc, "data error"); 252*5640Sroot if (hp) 253*5640Sroot hp->h_rfnm = 0; 254*5640Sroot impnoops(sc); 255*5640Sroot break; 256*5640Sroot 257*5640Sroot /* 258*5640Sroot * IMP reset complete. 259*5640Sroot */ 260*5640Sroot case IMPTYPE_RESET: 261*5640Sroot if (sc->imp_state == IMPS_DOWN) 262*5640Sroot sc->imp_state = IMPS_UP; 263*5640Sroot else 264*5640Sroot imperr(sc, "unexpected reset"); 265*5640Sroot goto drop; 266*5640Sroot 267*5640Sroot default: 268*5640Sroot sc->imp_if.if_collisions++; /* XXX */ 269*5640Sroot goto drop; 270*5640Sroot } 271*5640Sroot 272*5640Sroot /* 273*5640Sroot * Queue on protocol's input queue. 274*5640Sroot */ 275*5640Sroot switch (ip->il_link) { 276*5640Sroot 277*5640Sroot #ifdef INET 278*5640Sroot case IMPLINK_IP: 279*5640Sroot m->m_len -= sizeof(struct imp_leader); 280*5640Sroot m->m_off += sizeof(struct imp_leader); 281*5640Sroot setipintr(); 282*5640Sroot inq = &ipintrq; 283*5640Sroot break; 284*5640Sroot #endif 285*5640Sroot 286*5640Sroot default: 287*5640Sroot impproto.sp_protocol = ip->il_link; 288*5640Sroot impaddr.sin_addr.s_net = ip->il_network; 289*5640Sroot impaddr.sin_addr.s_host = ip->il_host; 290*5640Sroot impaddr.sin_addr.s_imp = ip->il_imp; 291*5640Sroot raw_input(m, impproto, impaddr); 292*5640Sroot return; 293*5640Sroot } 294*5640Sroot IF_ENQUEUE(inq, m); 295*5640Sroot return; 296*5640Sroot 297*5640Sroot drop: 298*5640Sroot m_freem(m); 299*5640Sroot } 300*5640Sroot 301*5640Sroot /*VARARGS*/ 302*5640Sroot imperr(sc, fmt, a1, a2) 303*5640Sroot struct imp_softc *sc; 304*5640Sroot char *fmt; 305*5640Sroot { 306*5640Sroot printf("imp%d: ", sc->imp_if.if_unit); 307*5640Sroot printf(fmt, a1, a2); 308*5640Sroot printf("\n"); 309*5640Sroot } 310*5640Sroot 311*5640Sroot /* 312*5640Sroot * ARPAnet 1822 output routine. 313*5640Sroot * Called from higher level protocol routines to set up messages for 314*5640Sroot * transmission to the imp. Sets up the header and calls impsnd to 315*5640Sroot * enqueue the message for this IMP's hardware driver. 316*5640Sroot */ 317*5640Sroot impoutput(ifp, m0, pf) 318*5640Sroot register struct ifnet *ifp; 319*5640Sroot struct mbuf *m0; 320*5640Sroot { 321*5640Sroot register struct imp_leader *imp; 322*5640Sroot register struct mbuf *m = m0; 323*5640Sroot int x, dhost, dimp, dlink, len; 324*5640Sroot 325*5640Sroot /* 326*5640Sroot * Don't even try if the IMP is unavailable. 327*5640Sroot */ 328*5640Sroot if (imp_softc[ifp->if_unit].imp_state == IMPS_DOWN) { 329*5640Sroot m_freem(m0); 330*5640Sroot return (0); 331*5640Sroot } 332*5640Sroot 333*5640Sroot switch (pf) { 334*5640Sroot 335*5640Sroot #ifdef INET 336*5640Sroot case PF_INET: { 337*5640Sroot register struct ip *ip = mtod(m0, struct ip *); 338*5640Sroot 339*5640Sroot dhost = ip->ip_dst.s_host; 340*5640Sroot dimp = ip->ip_dst.s_imp; 341*5640Sroot dlink = IMPLINK_IP; 342*5640Sroot len = ntohs(ip->ip_len); 343*5640Sroot break; 344*5640Sroot } 345*5640Sroot #endif 346*5640Sroot case PF_IMPLINK: 347*5640Sroot goto leaderexists; 348*5640Sroot 349*5640Sroot default: 350*5640Sroot printf("imp%d: can't encapsulate pf%d\n", ifp->if_unit, pf); 351*5640Sroot m_freem(m0); 352*5640Sroot return (0); 353*5640Sroot } 354*5640Sroot 355*5640Sroot /* 356*5640Sroot * Add IMP leader. If there's not enough space in the 357*5640Sroot * first mbuf, allocate another. If that should fail, we 358*5640Sroot * drop this sucker. 359*5640Sroot */ 360*5640Sroot if (m->m_off > MMAXOFF || 361*5640Sroot MMINOFF + sizeof(struct imp_leader) > m->m_off) { 362*5640Sroot m = m_get(M_DONTWAIT); 363*5640Sroot if (m == 0) { 364*5640Sroot m_freem(m0); 365*5640Sroot return (0); 366*5640Sroot } 367*5640Sroot m->m_next = m0; 368*5640Sroot m->m_off = MMINOFF; 369*5640Sroot m->m_len = sizeof(struct imp_leader); 370*5640Sroot } else { 371*5640Sroot m->m_off -= sizeof(struct imp_leader); 372*5640Sroot m->m_len += sizeof(struct imp_leader); 373*5640Sroot } 374*5640Sroot imp = mtod(m, struct imp_leader *); 375*5640Sroot imp->il_format = IMP_NFF; 376*5640Sroot imp->il_host = dhost; 377*5640Sroot imp->il_impno = dimp; 378*5640Sroot imp->il_length = (len + sizeof(struct imp_leader)) << 3; 379*5640Sroot imp->il_link = dlink; 380*5640Sroot 381*5640Sroot leaderexists: 382*5640Sroot /* 383*5640Sroot * Hand message to impsnd to perform RFNM counting 384*5640Sroot * and eventual transmission. 385*5640Sroot */ 386*5640Sroot return (impsnd(ifp, m)); 387*5640Sroot } 388*5640Sroot 389*5640Sroot /* 390*5640Sroot * Put a message on an interface's output queue. 391*5640Sroot * Perform RFNM counting: no more than 8 message may be 392*5640Sroot * in flight to any one host. 393*5640Sroot */ 394*5640Sroot impsnd(ifp, m) 395*5640Sroot struct ifnet *ifp; 396*5640Sroot struct mbuf *m; 397*5640Sroot { 398*5640Sroot register struct imp_leader *ip; 399*5640Sroot register struct host *hp; 400*5640Sroot struct impcb *icp; 401*5640Sroot int x; 402*5640Sroot 403*5640Sroot ip = mtod(m, struct imp_leader *); 404*5640Sroot 405*5640Sroot /* 406*5640Sroot * Do RFNM counting for data messages 407*5640Sroot * (no more than 8 outstanding to any host) 408*5640Sroot */ 409*5640Sroot if (ip->il_mtype == IMPTYPE_DATA) { 410*5640Sroot struct in_addr addr; 411*5640Sroot 412*5640Sroot addr.s_net = ifp->if_net; 413*5640Sroot addr.s_host = ip->il_host; 414*5640Sroot addr.s_imp = ip->il_imp; 415*5640Sroot hp = h_enter(addr); 416*5640Sroot 417*5640Sroot /* 418*5640Sroot * If IMP would block, queue until rfnm 419*5640Sroot */ 420*5640Sroot if (hp) { 421*5640Sroot register struct mbuf *n; 422*5640Sroot int cnt; 423*5640Sroot 424*5640Sroot if (hp->h_rfnm < 8) { 425*5640Sroot hp->h_rfnm++; 426*5640Sroot goto enque; 427*5640Sroot } 428*5640Sroot /* 429*5640Sroot * Keeping the count in the host structure 430*5640Sroot * causes the packing scheme to lose too much. 431*5640Sroot */ 432*5640Sroot cnt = 0, n = hp->h_q; 433*5640Sroot for (; n != (struct mbuf *)hp; n = n->m_act) 434*5640Sroot cnt++; 435*5640Sroot if (cnt >= 8) 436*5640Sroot goto drop; 437*5640Sroot if ((n = hp->h_q) == 0) 438*5640Sroot hp->h_q = m->m_act = m; 439*5640Sroot else { 440*5640Sroot m->m_act = n->m_act; 441*5640Sroot hp->h_q = n->m_act = m; 442*5640Sroot } 443*5640Sroot goto start; 444*5640Sroot } 445*5640Sroot drop: 446*5640Sroot m_freem(m); 447*5640Sroot return (0); 448*5640Sroot } 449*5640Sroot enque: 450*5640Sroot x = splimp(); 451*5640Sroot IF_ENQUEUE(&ifp->if_snd, m); 452*5640Sroot splx(x); 453*5640Sroot 454*5640Sroot start: 455*5640Sroot icp = &imp_softc[ifp->if_unit].imp_cb; 456*5640Sroot if (icp->ic_oactive == 0) 457*5640Sroot (*icp->ic_start)(ifp->if_unit); 458*5640Sroot return (1); 459*5640Sroot } 460*5640Sroot 461*5640Sroot /* 462*5640Sroot * Put three 1822 NOOPs at the head of the output queue. 463*5640Sroot * Part of host-IMP initialization procedure. 464*5640Sroot * (Should return success/failure, but noone knows 465*5640Sroot * what to do with this, so why bother?) 466*5640Sroot */ 467*5640Sroot impnoops(sc) 468*5640Sroot register struct imp_softc *sc; 469*5640Sroot { 470*5640Sroot register i; 471*5640Sroot register struct mbuf *m; 472*5640Sroot register struct imp_leader *ip; 473*5640Sroot int x; 474*5640Sroot 475*5640Sroot sc->imp_state = IMPS_INIT; 476*5640Sroot sc->imp_dropcnt = IMP_DROPCNT; 477*5640Sroot for (i = 0; i < IMP_DROPCNT; i++ ) { 478*5640Sroot if ((m = m_getclr(M_DONTWAIT)) == 0) 479*5640Sroot return; 480*5640Sroot m->m_off = MMINOFF; 481*5640Sroot m->m_len = sizeof(struct imp_leader); 482*5640Sroot ip = mtod(m, struct imp_leader *); 483*5640Sroot ip->il_format = IMP_NFF; 484*5640Sroot ip->il_link = i; 485*5640Sroot ip->il_mtype = IMPTYPE_NOOP; 486*5640Sroot x = splimp(); 487*5640Sroot IF_PREPEND(&sc->imp_if.if_snd, m); 488*5640Sroot splx(x); 489*5640Sroot } 490*5640Sroot if (sc->imp_cb.ic_oactive == 0) 491*5640Sroot (*sc->imp_cb.ic_start)(sc->imp_if.if_unit); 492*5640Sroot } 493*5640Sroot #endif 494