Commit | Line | Data |
---|---|---|
547e5718 SL |
1 | /* if_vv.c 4.1 82/06/04 */ |
2 | ||
3 | /* | |
4 | * Proteon 10 Meg Ring Driver. | |
5 | * This device is called "vv" because its "real name", | |
6 | * V2LNI won't work if shortened to the obvious "v2". | |
7 | * Hence the subterfuge. | |
8 | */ | |
9 | #include "../h/param.h" | |
10 | #include "../h/systm.h" | |
11 | #include "../h/mbuf.h" | |
12 | #include "../h/pte.h" | |
13 | #include "../h/buf.h" | |
14 | #include "../h/protosw.h" | |
15 | #include "../h/socket.h" | |
16 | #include "../h/ubareg.h" | |
17 | #include "../h/ubavar.h" | |
18 | #include "../h/cpu.h" | |
19 | #include "../h/mtpr.h" | |
20 | #include "../h/vmmac.h" | |
21 | #include "../net/in.h" | |
22 | #include "../net/in_systm.h" | |
23 | #include "../net/if.h" | |
24 | #include "../net/if_vv.h" | |
25 | #include "../net/if_uba.h" | |
26 | #include "../net/ip.h" | |
27 | #include "../net/ip_var.h" | |
28 | #include "../net/route.h" | |
29 | ||
30 | #include "vv.h" | |
31 | #include "imp.h" | |
32 | ||
33 | /* | |
34 | * N.B. - if WIRECENTER is defined wrong, it can well break | |
35 | * the hardware!! | |
36 | */ | |
37 | #undef AUTOIDENTIFY | |
38 | #define WIRECENTER | |
39 | ||
40 | #ifdef WIRECENTER | |
41 | #define VV_CONF VV_HEN /* drive wire center relay */ | |
42 | #else | |
43 | #define VV_CONF VV_STE /* allow operation without wire center */ | |
44 | #endif | |
45 | ||
46 | #define VVMTU (1024+512) | |
47 | ||
48 | int vvprobe(), vvattach(), vvrint(), vvxint(); | |
49 | struct uba_device *vvinfo[NVV]; | |
50 | u_short vvstd[] = { 0 }; | |
51 | struct uba_driver vvdriver = | |
52 | { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; | |
53 | #define VVUNIT(x) minor(x) | |
54 | int vvinit(),vvoutput(),vvreset(); | |
55 | ||
56 | /* | |
57 | * Software status of each interface. | |
58 | * | |
59 | * Each interface is referenced by a network interface structure, | |
60 | * vs_if, which the routing code uses to locate the interface. | |
61 | * This structure contains the output queue for the interface, its address, ... | |
62 | * We also have, for each interface, a UBA interface structure, which | |
63 | * contains information about the UNIBUS resources held by the interface: | |
64 | * map registers, buffered data paths, etc. Information is cached in this | |
65 | * structure for use by the if_uba.c routines in running the interface | |
66 | * efficiently. | |
67 | */ | |
68 | struct vv_softc { | |
69 | struct ifnet vs_if; /* network-visible interface */ | |
70 | struct ifuba vs_ifuba; /* UNIBUS resources */ | |
71 | short vs_oactive; /* is output active? */ | |
72 | short vs_olen; /* length of last output */ | |
73 | u_short vs_lastx; /* last destination address */ | |
74 | short vs_tries; /* current retry count */ | |
75 | short vs_init; /* number of ring inits */ | |
76 | short vs_flush; /* number of flushed packets */ | |
77 | short vs_nottaken; /* number of packets refused */ | |
78 | } vv_softc[NVV]; | |
79 | ||
80 | vvprobe(reg) | |
81 | caddr_t reg; | |
82 | { | |
83 | register int br, cvec; | |
84 | register struct vvreg *addr = (struct vvreg *)reg; | |
85 | ||
86 | #ifdef lint | |
87 | br = 0; cvec = br; br = cvec; | |
88 | #endif | |
89 | /* reset interface, enable, and wait till dust settles */ | |
90 | addr->vvicsr = VV_RST; | |
91 | addr->vvocsr = VV_RST; | |
92 | DELAY(100000); | |
93 | /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ | |
94 | addr->vvocsr = VV_IEN; /* enable interrupt */ | |
95 | addr->vvoba = 0; /* low 16 bits */ | |
96 | addr->vvoea = 0; /* extended bits */ | |
97 | addr->vvowc = -1; /* for 1 word */ | |
98 | addr->vvocsr |= VV_DEN; /* start the DMA */ | |
99 | DELAY(100000); | |
100 | addr->vvocsr = 0; | |
101 | if (cvec && cvec != 0x200) | |
102 | cvec -= 4; /* backup so vector => recieve */ | |
103 | return(1); | |
104 | } | |
105 | ||
106 | /* | |
107 | * Interface exists: make available by filling in network interface | |
108 | * record. System will initialize the interface when it is ready | |
109 | * to accept packets. | |
110 | */ | |
111 | vvattach(ui) | |
112 | struct uba_device *ui; | |
113 | { | |
114 | register struct vv_softc *vs = &vv_softc[ui->ui_unit]; | |
115 | register struct sockaddr_in *sin; | |
116 | COUNT(VVATTACH); | |
117 | ||
118 | vs->vs_if.if_unit = ui->ui_unit; | |
119 | vs->vs_if.if_name = "vv"; | |
120 | vs->vs_if.if_mtu = VVMTU; | |
121 | vs->vs_if.if_net = ui->ui_flags; | |
122 | vs->vs_if.if_host[0] = 0; /* this will be reset in vvinit() */ | |
123 | ||
124 | sin = (struct sockaddr_in *)&vs->vs_if.if_addr; | |
125 | sin->sin_family = AF_INET; | |
126 | sin->sin_addr = if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); | |
127 | ||
128 | sin = (struct sockaddr_in *)&vs->vs_if.if_broadaddr; | |
129 | sin->sin_family = AF_INET; | |
130 | sin->sin_addr = if_makeaddr(vs->vs_if.if_net, VV_BROADCAST); | |
131 | vs->vs_if.if_flags = IFF_BROADCAST; | |
132 | ||
133 | vs->vs_if.if_init = vvinit; | |
134 | vs->vs_if.if_output = vvoutput; | |
135 | vs->vs_if.if_ubareset = vvreset; | |
136 | vs->vs_ifuba.ifu_flags = UBA_NEEDBDP | UBA_NEED16; | |
137 | if_attach(&vs->vs_if); | |
138 | #if NIMP == 0 | |
139 | if (ui->ui_flags & ~0xff) | |
140 | vvlhinit((ui->ui_flags &~ 0xff) | 0x0a); | |
141 | #endif | |
142 | } | |
143 | ||
144 | /* | |
145 | * Reset of interface after UNIBUS reset. | |
146 | * If interface is on specified uba, reset its state. | |
147 | */ | |
148 | vvreset(unit, uban) | |
149 | int unit, uban; | |
150 | { | |
151 | register struct uba_device *ui; | |
152 | COUNT(VVRESET); | |
153 | ||
154 | if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || | |
155 | ui->ui_ubanum != uban) | |
156 | return; | |
157 | printf(" vv%d", unit); | |
158 | vvinit(unit); | |
159 | } | |
160 | ||
161 | /* | |
162 | * Initialization of interface; clear recorded pending | |
163 | * operations, and reinitialize UNIBUS usage. | |
164 | */ | |
165 | vvinit(unit) | |
166 | int unit; | |
167 | { | |
168 | register struct vv_softc *vs = &vv_softc[unit]; | |
169 | register struct uba_device *ui = vvinfo[unit]; | |
170 | register struct vvreg *addr; | |
171 | struct sockaddr_in *sin; | |
172 | struct mbuf *m; | |
173 | struct vv_header *v; | |
174 | int ubainfo, retrying, attempts, waitcount, s; | |
175 | ||
176 | if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, | |
177 | sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { | |
178 | printf("vv%d: can't initialize\n", unit); | |
179 | return; | |
180 | } | |
181 | addr = (struct vvreg *)ui->ui_addr; | |
182 | ||
183 | #ifdef AUTOIDENTIFY | |
184 | /* | |
185 | * Build a multicast message to identify our address | |
186 | */ | |
187 | attempts = 0; /* total attempts, including bad msg type */ | |
188 | top: | |
189 | retrying = 0; /* first time through */ | |
190 | m = m_get(M_DONTWAIT); | |
191 | if (m == 0) | |
192 | panic("vvinit: can't get mbuf"); | |
193 | m->m_next = 0; | |
194 | m->m_off = MMINOFF; | |
195 | m->m_len = sizeof(struct vv_header); | |
196 | ||
197 | v = mtod(m, struct vv_header *); | |
198 | v->vh_dhost = 0; /* multicast destination address */ | |
199 | v->vh_shost = 0; /* will be overwritten with ours */ | |
200 | v->vh_version = RING_VERSION; | |
201 | v->vh_type = RING_WHOAMI; | |
202 | v->vh_info = 0; | |
203 | ||
204 | /* | |
205 | * Reset interface, establish Digital Loopback Mode, and | |
206 | * send the multicast (to myself) with Input Copy enabled. | |
207 | */ | |
208 | retry: | |
209 | ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; | |
210 | addr->vvicsr = VV_RST; | |
211 | addr->vviba = (u_short) ubainfo; | |
212 | addr->vviea = (u_short) (ubainfo >> 16); | |
213 | addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; | |
214 | addr->vvicsr = VV_STE | VV_DEN | VV_ENB | VV_LPB; | |
215 | /* map xmit message into uba if not already there */ | |
216 | if (!retrying) | |
217 | vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); | |
218 | if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) | |
219 | UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); | |
220 | addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ | |
221 | ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; | |
222 | addr->vvoba = (u_short) ubainfo; | |
223 | addr->vvoea = (u_short) (ubainfo >> 16); | |
224 | addr->vvowc = -((vs->vs_olen + 1) >> 1); | |
225 | addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; | |
226 | ||
227 | /* | |
228 | * Wait for receive side to finish. | |
229 | * Extract source address (which will our own), | |
230 | * and post to interface structure. | |
231 | */ | |
232 | DELAY(1000); | |
233 | for (waitcount = 0; ((addr->vvicsr) & VV_RDY) == 0; waitcount++) { | |
234 | if (waitcount < 10) | |
235 | DELAY(1000); | |
236 | else { | |
237 | if (attempts++ < 10)s | |
238 | goto retry; | |
239 | else { | |
240 | printf("vv%d: can't initialize\n", unit); | |
241 | printf("vvinit loopwait: icsr = %b\n", | |
242 | 0xffff&(addr->vvicsr),VV_IBITS); | |
243 | return; | |
244 | } | |
245 | } | |
246 | } | |
247 | ||
248 | if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) | |
249 | UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); | |
250 | if (vs->vs_ifuba.ifu_xtofree) | |
251 | m_freem(vs->vs_ifuba.ifu_xtofree); | |
252 | if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) | |
253 | UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); | |
254 | m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), 0); | |
255 | if (m) | |
256 | m_freem(m); | |
257 | /* | |
258 | * check message type before we believe the source host address | |
259 | */ | |
260 | v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); | |
261 | if (v->vh_type == RING_WHOAMI) | |
262 | vs->vs_if.if_host[0] = v->vh_shost; | |
263 | else | |
264 | goto top; | |
265 | #else | |
266 | vs->vs_if.if_host[0] = 24; | |
267 | #endif | |
268 | ||
269 | printf("vv%d: host %d\n", unit, vs->vs_if.if_host[0]); | |
270 | sin = (struct sockaddr_in *)&vs->vs_if.if_addr; | |
271 | sin->sin_family = AF_INET; | |
272 | sin->sin_addr = | |
273 | if_makeaddr(vs->vs_if.if_net, vs->vs_if.if_host[0]); | |
274 | ||
275 | /* | |
276 | * Reset the interface, and join the ring | |
277 | */ | |
278 | addr->vvocsr = VV_RST | VV_CPB; /* clear packet buffer */ | |
279 | addr->vvicsr = VV_RST | VV_CONF; /* close logical relay */ | |
280 | sleep((caddr_t)&lbolt, PZERO); /* let contacts settle */ | |
281 | vs->vs_init = 0; | |
282 | vs->vs_flush = 0; | |
283 | vs->vs_nottaken = 0; | |
284 | ||
285 | /* | |
286 | * Hang a receive and start any | |
287 | * pending writes by faking a transmit complete. | |
288 | */ | |
289 | s = splimp(); | |
290 | ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; | |
291 | addr->vviba = (u_short) ubainfo; | |
292 | addr->vviea = (u_short) (ubainfo >> 16); | |
293 | addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; | |
294 | addr->vvicsr = VV_IEN | VV_CONF | VV_DEN | VV_ENB; | |
295 | vs->vs_oactive = 1; | |
296 | vvxint(unit); | |
297 | splx(s); | |
298 | if_rtinit(&vs->vs_if, RTF_DIRECT|RTF_UP); | |
299 | } | |
300 | ||
301 | /* | |
302 | * Start or restart output on interface. | |
303 | * If interface is not already active, get another datagram | |
304 | * to send off of the interface queue, and map it to the interface | |
305 | * before starting the output. | |
306 | */ | |
307 | vvstart(dev) | |
308 | dev_t dev; | |
309 | { | |
310 | int unit = VVUNIT(dev); | |
311 | struct uba_device *ui = vvinfo[unit]; | |
312 | register struct vv_softc *vs = &vv_softc[unit]; | |
313 | register struct vvreg *addr; | |
314 | struct mbuf *m; | |
315 | int ubainfo; | |
316 | int dest; | |
317 | COUNT(VVSTART); | |
318 | ||
319 | if (vs->vs_oactive) | |
320 | goto restart; | |
321 | ||
322 | /* | |
323 | * Not already active: dequeue another request | |
324 | * and map it to the UNIBUS. If no more requests, | |
325 | * just return. | |
326 | */ | |
327 | IF_DEQUEUE(&vs->vs_if.if_snd, m); | |
328 | if (m == 0) { | |
329 | vs->vs_oactive = 0; | |
330 | return; | |
331 | } | |
332 | dest = mtod(m, struct vv_header *)->vh_dhost; | |
333 | vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); | |
334 | vs->vs_lastx = dest; | |
335 | ||
336 | restart: | |
337 | /* | |
338 | * Have request mapped to UNIBUS for transmission. | |
339 | * Purge any stale data from this BDP, and start the otput. | |
340 | */ | |
341 | if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) | |
342 | UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); | |
343 | addr = (struct vvreg *)ui->ui_addr; | |
344 | ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; | |
345 | addr->vvoba = (u_short) ubainfo; | |
346 | addr->vvoea = (u_short) (ubainfo >> 16); | |
347 | addr->vvowc = -((vs->vs_olen + 1) >> 1); | |
348 | addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; | |
349 | vs->vs_oactive = 1; | |
350 | } | |
351 | ||
352 | /* | |
353 | * VVLNI transmit interrupt | |
354 | * Start another output if more data to send. | |
355 | */ | |
356 | vvxint(unit) | |
357 | int unit; | |
358 | { | |
359 | register struct uba_device *ui = vvinfo[unit]; | |
360 | register struct vv_softc *vs = &vv_softc[unit]; | |
361 | register struct vvreg *addr; | |
362 | register int oc; | |
363 | COUNT(ENXINT); | |
364 | ||
365 | addr = (struct vvreg *)ui->ui_addr; | |
366 | oc = 0xffff & (addr->vvocsr); | |
367 | if (vs->vs_oactive == 0) { | |
368 | printf("vv%d: stray interrupt vvocsr = %b\n", unit, | |
369 | oc, VV_OBITS); | |
370 | return; | |
371 | } | |
372 | if (oc & (VV_OPT | VV_RFS)) { | |
373 | if (++(vs->vs_tries) < VVRETRY) { | |
374 | if (oc & VV_OPT) | |
375 | vs->vs_init++; | |
376 | if (oc & VV_RFS) | |
377 | vs->vs_nottaken++; | |
378 | addr->vvocsr = VV_IEN | VV_ENB | VV_INR; | |
379 | return; | |
380 | } | |
381 | if (oc & VV_OPT) | |
382 | printf("vv%d: output timeout\n"); | |
383 | } | |
384 | vs->vs_if.if_opackets++; | |
385 | vs->vs_oactive = 0; | |
386 | vs->vs_tries = 0; | |
387 | if (oc & VVXERR) { | |
388 | vs->vs_if.if_oerrors++; | |
389 | printf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, | |
390 | VV_OBITS); | |
391 | } | |
392 | if (vs->vs_ifuba.ifu_xtofree) { | |
393 | m_freem(vs->vs_ifuba.ifu_xtofree); | |
394 | vs->vs_ifuba.ifu_xtofree = 0; | |
395 | } | |
396 | if (vs->vs_if.if_snd.ifq_head == 0) { | |
397 | vs->vs_lastx = 0; | |
398 | return; | |
399 | } | |
400 | vvstart(unit); | |
401 | } | |
402 | ||
403 | /* | |
404 | * V2lni interface receiver interrupt. | |
405 | * If input error just drop packet. | |
406 | * Otherwise purge input buffered data path and examine | |
407 | * packet to determine type. If can't determine length | |
408 | * from type, then have to drop packet. Othewise decapsulate | |
409 | * packet based on type and pass to type specific higher-level | |
410 | * input routine. | |
411 | */ | |
412 | vvrint(unit) | |
413 | int unit; | |
414 | { | |
415 | register struct vv_softc *vs = &vv_softc[unit]; | |
416 | struct vvreg *addr = (struct vvreg *)vvinfo[unit]->ui_addr; | |
417 | register struct vv_header *vv; | |
418 | register struct ifqueue *inq; | |
419 | struct mbuf *m; | |
420 | int ubainfo, len, off; | |
421 | COUNT(VVRINT); | |
422 | ||
423 | vs->vs_if.if_ipackets++; | |
424 | /* | |
425 | * Purge BDP; drop if input error indicated. | |
426 | */ | |
427 | if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) | |
428 | UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); | |
429 | if (addr->vvicsr & VVRERR) { | |
430 | vs->vs_if.if_ierrors++; | |
431 | printf("vv%d: error vvicsr = %b\n", unit, | |
432 | 0xffff&(addr->vvicsr), VV_IBITS); | |
433 | goto setup; | |
434 | } | |
435 | off = 0; | |
436 | len = 0; | |
437 | vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); | |
438 | /* | |
439 | * Demultiplex on packet type and deal with oddities of | |
440 | * trailer protocol format | |
441 | */ | |
442 | switch (vv->vh_type) { | |
443 | ||
444 | #ifdef INET | |
445 | case RING_IP: | |
446 | len = htons((u_short)((struct ip *) vv)->ip_len); | |
447 | schednetisr(NETISR_IP); | |
448 | inq = &ipintrq; | |
449 | break; | |
450 | #endif | |
451 | default: | |
452 | printf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); | |
453 | goto setup; | |
454 | } | |
455 | if (len == 0) | |
456 | goto setup; | |
457 | /* | |
458 | * Pull packet off interface. Off is nonzero if packet | |
459 | * has trailing header; if_rubaget will then force this header | |
460 | * information to be at the front, but we still have to drop | |
461 | * the two-byte type which is at the front of any trailer data. | |
462 | */ | |
463 | m = if_rubaget(&vs->vs_ifuba, len, off); | |
464 | if (m == 0) | |
465 | goto setup; | |
466 | IF_ENQUEUE(inq, m); | |
467 | ||
468 | setup: | |
469 | /* | |
470 | * Reset for next packet. | |
471 | */ | |
472 | ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; | |
473 | addr->vviba = (u_short) ubainfo; | |
474 | addr->vviea = (u_short) (ubainfo >> 16); | |
475 | addr->vviwc = -(sizeof (struct vv_header) + VVMTU) >> 1; | |
476 | addr->vvicsr = VV_RST | VV_CONF; | |
477 | addr->vvicsr |= VV_IEN | VV_DEN | VV_ENB; | |
478 | ||
479 | } | |
480 | ||
481 | /* | |
482 | * V2lni output routine. | |
483 | * Encapsulate a packet of type family for the local net. | |
484 | * Use trailer local net encapsulation if enough data in first | |
485 | * packet leaves a multiple of 512 bytes of data in remainder. | |
486 | */ | |
487 | vvoutput(ifp, m0, dst) | |
488 | struct ifnet *ifp; | |
489 | struct mbuf *m0; | |
490 | struct sockaddr *dst; | |
491 | { | |
492 | register struct mbuf *m = m0; | |
493 | register struct vv_header *vv; | |
494 | int type, dest, s; | |
495 | ||
496 | switch (dst->sa_family) { | |
497 | ||
498 | #ifdef INET | |
499 | case AF_INET: { | |
500 | register struct ip *ip = mtod(m0, struct ip *); | |
501 | int off; | |
502 | ||
503 | dest = ip->ip_dst.s_addr >> 24; | |
504 | type = RING_IP; | |
505 | off = 0; | |
506 | goto gottype; | |
507 | } | |
508 | #endif | |
509 | default: | |
510 | printf("vv%d: can't handle af%d\n", ifp->if_unit, | |
511 | dst->sa_family); | |
512 | m_freem(m0); | |
513 | return (0); | |
514 | } | |
515 | ||
516 | gottrailertype: | |
517 | /* | |
518 | * Packet to be sent as trailer: move first packet | |
519 | * (control information) to end of chain. | |
520 | */ | |
521 | while (m->m_next) | |
522 | m = m->m_next; | |
523 | m->m_next = m0; | |
524 | m = m0->m_next; | |
525 | m0->m_next = 0; | |
526 | m0 = m; | |
527 | ||
528 | gottype: | |
529 | /* | |
530 | * Add local net header. If no space in first mbuf, | |
531 | * allocate another. | |
532 | */ | |
533 | if (m->m_off > MMAXOFF || | |
534 | MMINOFF + sizeof (struct vv_header) > m->m_off) { | |
535 | m = m_get(M_DONTWAIT); | |
536 | if (m == 0) { | |
537 | m_freem(m0); | |
538 | return (0); | |
539 | } | |
540 | m->m_next = m0; | |
541 | m->m_off = MMINOFF; | |
542 | m->m_len = sizeof (struct vv_header); | |
543 | } else { | |
544 | m->m_off -= sizeof (struct vv_header); | |
545 | m->m_len += sizeof (struct vv_header); | |
546 | } | |
547 | vv = mtod(m, struct vv_header *); | |
548 | vv->vh_shost = ifp->if_host[0]; | |
549 | vv->vh_dhost = dest; | |
550 | vv->vh_version = RING_VERSION; | |
551 | vv->vh_type = type; | |
552 | vv->vh_info = m->m_len; | |
553 | ||
554 | /* | |
555 | * Queue message on interface, and start output if interface | |
556 | * not yet active. | |
557 | */ | |
558 | s = splimp(); | |
559 | IF_ENQUEUE(&ifp->if_snd, m); | |
560 | if (vv_softc[ifp->if_unit].vs_oactive == 0) | |
561 | vvstart(ifp->if_unit); | |
562 | splx(s); | |
563 | return (1); | |
564 | } | |
565 | ||
566 | #ifdef notdef | |
567 | /* | |
568 | * vvprt_hdr(s, v) print the local net header in "v" | |
569 | * with title is "s" | |
570 | */ | |
571 | vvprt_hdr(s, v) | |
572 | char *s; | |
573 | register struct vv_header *v; | |
574 | { | |
575 | printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", | |
576 | s, | |
577 | 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), | |
578 | 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), | |
579 | 0xffff & (int)(v->vh_info)); | |
580 | } | |
581 | ||
582 | /* | |
583 | * print "l" hex bytes starting at "s" | |
584 | */ | |
585 | vvprt_hex(s, l) | |
586 | char *s; | |
587 | int l; | |
588 | { | |
589 | register int i; | |
590 | register int z; | |
591 | ||
592 | for (i=0 ; i < l; i++) { | |
593 | z = 0xff & (int)(*(s + i)); | |
594 | printf("%c%c ", | |
595 | "0123456789abcdef"[(z >> 4) & 0x0f], | |
596 | "0123456789abcdef"[z & 0x0f] | |
597 | ); | |
598 | } | |
599 | } | |
600 | #endif | |
601 | ||
602 | #if NIMP == 0 && NVV > 0 | |
603 | /* | |
604 | * Logical host interface driver. | |
605 | * Allows host to appear as an ARPAnet | |
606 | * logical host. Must also have routing | |
607 | * table entry set up to forward packets | |
608 | * to appropriate geteway on localnet. | |
609 | */ | |
610 | struct ifnet vvlhif; | |
611 | int looutput(); | |
612 | ||
613 | /* | |
614 | * Called by localnet interface to allow logical | |
615 | * host interface to "attach". | |
616 | */ | |
617 | vvlhinit(vvifp, addr) | |
618 | struct ifnet *vvifp; | |
619 | int addr; | |
620 | { | |
621 | register struct ifnet *ifp = &vvlhif; | |
622 | register struct sockaddr_in *sin; | |
623 | ||
624 | COUNT(VVLHINIT); | |
625 | ifp->if_name = "lh"; | |
626 | ifp->if_mtu = VVMTU; | |
627 | sin = (struct sockaddr_in *)&ifp->if_addr; | |
628 | sin->sin_family = AF_INET; | |
629 | sin->sin_addr.s_addr = addr; | |
630 | ifp->if_net = netpart(sin->sin_addr); | |
631 | ifp->if_flags = IFF_UP; | |
632 | ifp->if_output = looutput; | |
633 | if_attach(ifp); | |
634 | rtinit(&ifp->if_addr, &ifp->if_addr, RTF_DIRECT|RTF_UP|RTF_HOST); | |
635 | } | |
636 | #endif |