Commit | Line | Data |
---|---|---|
da7c5cc6 KM |
1 | /* |
2 | * Copyright (c) 1982 Regents of the University of California. | |
3 | * All rights reserved. The Berkeley software License Agreement | |
4 | * specifies the terms and conditions for redistribution. | |
5 | * | |
9a0b0c74 | 6 | * @(#)if_vv.c 6.13 (Berkeley) %G% |
da7c5cc6 | 7 | */ |
547e5718 | 8 | |
961945a8 | 9 | #include "vv.h" |
9a0b0c74 | 10 | #if NVV > 0 |
4cdd59b5 | 11 | |
547e5718 | 12 | /* |
0f9c1d6e MK |
13 | * Proteon proNET-10 and proNET-80 token ring driver. |
14 | * The name of this device driver derives from the old MIT | |
15 | * name of V2LNI for the proNET hardware, would would abbreviate | |
16 | * to "v2", but this won't work right. Thus the name is "vv". | |
4cdd59b5 | 17 | * |
0f9c1d6e MK |
18 | * This driver is compatible with the proNET 10 meagbit and |
19 | * 80 megabit token ring interfaces (models p1000 and p1080). | |
20 | * | |
21 | * TRAILERS: You must turn off trailers via ifconfig if you want to share | |
22 | * a ring with software using the following protocol types: | |
23 | * 3: Address Resolution Protocol | |
24 | * 4: HDLC (old Proteon drivers) | |
25 | * 5: VAX Debugging Protocol (never used) | |
26 | * This is because the protocol type values chosen for trailers | |
27 | * conflict with these protocols. It's too late to change either now. | |
28 | * | |
29 | * HARDWARE COMPATABILITY: This driver requires that the HSBU (p1001) | |
30 | * have a serial number >= 040, which is about March, 1982. Older | |
31 | * HSBUs do not carry across 64kbyte boundaries. The old warning | |
32 | * about use without Wire Centers applies only to CTL (p1002) cards with | |
33 | * serial <= 057, which have not received ECO 176-743, which was | |
34 | * implemented in March, 1982. Most such CTLs have received this ECO, | |
35 | * but they are only compatible with the old HSBUs (<=039) anyways. | |
547e5718 | 36 | */ |
38061563 | 37 | #include "../machine/pte.h" |
961945a8 | 38 | |
a6e960e7 JB |
39 | #include "param.h" |
40 | #include "systm.h" | |
41 | #include "mbuf.h" | |
42 | #include "buf.h" | |
43 | #include "protosw.h" | |
44 | #include "socket.h" | |
45 | #include "vmmac.h" | |
46 | #include "errno.h" | |
47 | #include "ioctl.h" | |
eaa60542 BJ |
48 | |
49 | #include "../net/if.h" | |
38061563 | 50 | #include "../net/netisr.h" |
eaa60542 | 51 | #include "../net/route.h" |
67eb6277 MK |
52 | |
53 | #ifdef BBNNET | |
54 | #define INET | |
55 | #endif | |
56 | #ifdef INET | |
d2cc167c BJ |
57 | #include "../netinet/in.h" |
58 | #include "../netinet/in_systm.h" | |
1a568327 | 59 | #include "../netinet/in_var.h" |
d2cc167c | 60 | #include "../netinet/ip.h" |
67eb6277 | 61 | #endif |
eaa60542 | 62 | |
38061563 | 63 | #include "../vax/cpu.h" |
2888e947 | 64 | #include "../vax/mtpr.h" |
a6e960e7 JB |
65 | #include "if_vv.h" |
66 | #include "if_uba.h" | |
2888e947 CL |
67 | #include "../vaxuba/ubareg.h" |
68 | #include "../vaxuba/ubavar.h" | |
38061563 | 69 | |
547e5718 | 70 | /* |
0f9c1d6e MK |
71 | * 80 megabit configuration |
72 | * Uncomment the next line if you are using the 80 megabit system. The | |
73 | * only change is the disposition of packets with parity/link_data_error | |
74 | * indication. | |
547e5718 | 75 | */ |
0f9c1d6e | 76 | /* #define PRONET80 */ |
547e5718 | 77 | |
0f9c1d6e MK |
78 | /* |
79 | * maximum transmission unit definition -- | |
80 | * you can set VVMTU at anything from 576 to 2024. | |
81 | * 1536 is a popular "large" value, because it is a multiple | |
82 | * of 512, which the trailer scheme likes. | |
83 | * The absolute maximum size is 2024, which is enforced. | |
84 | */ | |
547e5718 | 85 | |
67eb6277 | 86 | #define VVMTU (1536) |
0f9c1d6e MK |
87 | |
88 | #define VVMRU (VVMTU + 16) | |
89 | #define VVBUFSIZE (VVMRU + sizeof(struct vv_header)) | |
90 | #if VVMTU>2024 | |
91 | #undef VVMTU | |
92 | #undef VVMRU | |
93 | #undef VVBUFSIZE | |
94 | #define VVBUFSIZE (2046) | |
95 | #define VVMRU (VVBUFSIZE - sizeof (struct vv_header)) | |
96 | #define VVMTU (VVMRU - 16) | |
97 | #endif | |
5f3ad58b | 98 | |
0f9c1d6e MK |
99 | /* |
100 | * debugging and tracing stuff | |
101 | */ | |
aa531fcf | 102 | int vv_tracehdr = 0; /* 1 => trace headers (slowly!!) */ |
4cdd59b5 | 103 | |
0f9c1d6e | 104 | #define vvtracehdr if (vv_tracehdr) vvprt_hdr |
1a568327 | 105 | #define vvprintf if (vs->vs_if.if_flags & IFF_DEBUG) printf |
547e5718 | 106 | |
0f9c1d6e MK |
107 | /* |
108 | * externals, types, etc. | |
109 | */ | |
aa531fcf MK |
110 | int vvprobe(), vvattach(), vvreset(), vvinit(); |
111 | int vvidentify(), vvstart(), vvxint(), vvwatchdog(); | |
112 | int vvrint(), vvoutput(), vvioctl(), vvsetaddr(); | |
547e5718 SL |
113 | struct uba_device *vvinfo[NVV]; |
114 | u_short vvstd[] = { 0 }; | |
115 | struct uba_driver vvdriver = | |
116 | { vvprobe, 0, vvattach, 0, vvstd, "vv", vvinfo }; | |
117 | #define VVUNIT(x) minor(x) | |
547e5718 | 118 | |
0f9c1d6e MK |
119 | #define LOOPBACK /* use loopback for packets meant for us */ |
120 | #ifdef LOOPBACK | |
121 | extern struct ifnet loif; | |
122 | #endif | |
123 | ||
547e5718 SL |
124 | /* |
125 | * Software status of each interface. | |
126 | * | |
127 | * Each interface is referenced by a network interface structure, | |
128 | * vs_if, which the routing code uses to locate the interface. | |
129 | * This structure contains the output queue for the interface, its address, ... | |
130 | * We also have, for each interface, a UBA interface structure, which | |
131 | * contains information about the UNIBUS resources held by the interface: | |
132 | * map registers, buffered data paths, etc. Information is cached in this | |
133 | * structure for use by the if_uba.c routines in running the interface | |
134 | * efficiently. | |
135 | */ | |
136 | struct vv_softc { | |
137 | struct ifnet vs_if; /* network-visible interface */ | |
138 | struct ifuba vs_ifuba; /* UNIBUS resources */ | |
1a568327 | 139 | int vs_host; |
4cdd59b5 | 140 | short vs_oactive; /* is output active */ |
547e5718 | 141 | short vs_olen; /* length of last output */ |
2888e947 CL |
142 | u_short vs_lastx; /* address of last packet sent */ |
143 | u_short vs_lastr; /* address of last packet received */ | |
4cdd59b5 | 144 | short vs_tries; /* transmit current retry count */ |
547e5718 | 145 | short vs_init; /* number of ring inits */ |
0f9c1d6e | 146 | short vs_refused; /* number of packets refused */ |
2888e947 | 147 | short vs_timeouts; /* number of transmit timeouts */ |
0f9c1d6e MK |
148 | short vs_otimeout; /* number of output timeouts */ |
149 | short vs_ibadf; /* number of input bad formats */ | |
150 | short vs_parity; /* number of parity errors on 10 meg, */ | |
151 | /* link data errors on 80 meg */ | |
547e5718 SL |
152 | } vv_softc[NVV]; |
153 | ||
0f9c1d6e MK |
154 | /* |
155 | * probe the interface to see that the registers exist, and then | |
156 | * cause an interrupt to find its vector | |
157 | */ | |
547e5718 SL |
158 | vvprobe(reg) |
159 | caddr_t reg; | |
160 | { | |
161 | register int br, cvec; | |
aa531fcf | 162 | register struct vvreg *addr; |
547e5718 SL |
163 | |
164 | #ifdef lint | |
a23ec69a | 165 | br = 0; cvec = br; br = cvec; |
547e5718 | 166 | #endif |
aa531fcf | 167 | addr = (struct vvreg *)reg; |
0f9c1d6e | 168 | |
547e5718 SL |
169 | /* reset interface, enable, and wait till dust settles */ |
170 | addr->vvicsr = VV_RST; | |
171 | addr->vvocsr = VV_RST; | |
a23ec69a | 172 | DELAY(100000); |
0f9c1d6e | 173 | |
547e5718 | 174 | /* generate interrupt by doing 1 word DMA from 0 in uba space!! */ |
547e5718 SL |
175 | addr->vvoba = 0; /* low 16 bits */ |
176 | addr->vvoea = 0; /* extended bits */ | |
177 | addr->vvowc = -1; /* for 1 word */ | |
0f9c1d6e | 178 | addr->vvocsr = VV_IEN | VV_DEN; /* start the DMA, with interrupt */ |
547e5718 | 179 | DELAY(100000); |
0f9c1d6e | 180 | addr->vvocsr = VV_RST; /* clear out the CSR */ |
547e5718 | 181 | if (cvec && cvec != 0x200) |
a23ec69a | 182 | cvec -= 4; /* backup so vector => receive */ |
547e5718 SL |
183 | return(1); |
184 | } | |
185 | ||
186 | /* | |
187 | * Interface exists: make available by filling in network interface | |
188 | * record. System will initialize the interface when it is ready | |
189 | * to accept packets. | |
190 | */ | |
191 | vvattach(ui) | |
192 | struct uba_device *ui; | |
193 | { | |
a23ec69a | 194 | register struct vv_softc *vs; |
547e5718 | 195 | |
a23ec69a | 196 | vs = &vv_softc[ui->ui_unit]; |
547e5718 SL |
197 | vs->vs_if.if_unit = ui->ui_unit; |
198 | vs->vs_if.if_name = "vv"; | |
199 | vs->vs_if.if_mtu = VVMTU; | |
1a568327 | 200 | vs->vs_if.if_flags = IFF_BROADCAST; |
547e5718 | 201 | vs->vs_if.if_init = vvinit; |
1cd789fb | 202 | vs->vs_if.if_ioctl = vvioctl; |
547e5718 | 203 | vs->vs_if.if_output = vvoutput; |
38061563 | 204 | vs->vs_if.if_reset = vvreset; |
2888e947 CL |
205 | vs->vs_if.if_timer = 0; |
206 | vs->vs_if.if_watchdog = vvwatchdog; | |
5f3ad58b | 207 | vs->vs_ifuba.ifu_flags = UBA_CANTWAIT | UBA_NEEDBDP | UBA_NEED16; |
41fb002a MD |
208 | #if defined(VAX750) |
209 | /* don't chew up 750 bdp's */ | |
210 | if (cpu == VAX_750 && ui->ui_unit > 0) | |
211 | vs->vs_ifuba.ifu_flags &= ~UBA_NEEDBDP; | |
212 | #endif | |
547e5718 | 213 | if_attach(&vs->vs_if); |
547e5718 SL |
214 | } |
215 | ||
216 | /* | |
217 | * Reset of interface after UNIBUS reset. | |
218 | * If interface is on specified uba, reset its state. | |
219 | */ | |
220 | vvreset(unit, uban) | |
221 | int unit, uban; | |
222 | { | |
223 | register struct uba_device *ui; | |
547e5718 SL |
224 | |
225 | if (unit >= NVV || (ui = vvinfo[unit]) == 0 || ui->ui_alive == 0 || | |
226 | ui->ui_ubanum != uban) | |
227 | return; | |
228 | printf(" vv%d", unit); | |
229 | vvinit(unit); | |
230 | } | |
231 | ||
232 | /* | |
233 | * Initialization of interface; clear recorded pending | |
234 | * operations, and reinitialize UNIBUS usage. | |
235 | */ | |
236 | vvinit(unit) | |
237 | int unit; | |
238 | { | |
a23ec69a CL |
239 | register struct vv_softc *vs; |
240 | register struct uba_device *ui; | |
547e5718 | 241 | register struct vvreg *addr; |
aa531fcf | 242 | register int ubainfo, s; |
547e5718 | 243 | |
a23ec69a CL |
244 | vs = &vv_softc[unit]; |
245 | ui = vvinfo[unit]; | |
0f9c1d6e | 246 | |
1a568327 | 247 | if (vs->vs_if.if_addrlist == (struct ifaddr *)0) |
1cd789fb | 248 | return; |
0f9c1d6e | 249 | |
5f3ad58b | 250 | addr = (struct vvreg *)ui->ui_addr; |
547e5718 | 251 | if (if_ubainit(&vs->vs_ifuba, ui->ui_ubanum, |
a23ec69a | 252 | sizeof (struct vv_header), (int)btoc(VVMTU)) == 0) { |
2888e947 | 253 | printf("vv%d: can't initialize, if_ubainit() failed\n", unit); |
5f3ad58b | 254 | vs->vs_if.if_flags &= ~IFF_UP; |
547e5718 SL |
255 | return; |
256 | } | |
0f9c1d6e | 257 | |
5f3ad58b | 258 | /* |
a23ec69a CL |
259 | * Now that the uba is set up, figure out our address and |
260 | * update complete our host address. | |
5f3ad58b | 261 | */ |
1a568327 | 262 | if ((vs->vs_host = vvidentify(unit)) == -1) { |
2888e947 CL |
263 | vs->vs_if.if_flags &= ~IFF_UP; |
264 | return; | |
265 | } | |
1a568327 | 266 | printf("vv%d: host %d\n", unit, vs->vs_host); |
0f9c1d6e | 267 | |
5f3ad58b | 268 | /* |
0f9c1d6e | 269 | * Reset the interface, and stay in the ring |
5f3ad58b | 270 | */ |
0f9c1d6e MK |
271 | addr->vvocsr = VV_RST; /* take over output */ |
272 | addr->vvocsr = VV_CPB; /* clear packet buffer */ | |
273 | addr->vvicsr = VV_RST | VV_HEN; /* take over input, */ | |
274 | /* keep relay closed */ | |
5b319f7c | 275 | DELAY(500000); /* let contacts settle */ |
0f9c1d6e MK |
276 | |
277 | vs->vs_init = 0; /* clear counters, etc. */ | |
278 | vs->vs_refused = 0; | |
2888e947 | 279 | vs->vs_timeouts = 0; |
0f9c1d6e MK |
280 | vs->vs_otimeout = 0; |
281 | vs->vs_ibadf = 0; | |
282 | vs->vs_parity = 0; | |
2888e947 CL |
283 | vs->vs_lastx = 256; /* an invalid address */ |
284 | vs->vs_lastr = 256; /* an invalid address */ | |
0f9c1d6e | 285 | |
5f3ad58b SL |
286 | /* |
287 | * Hang a receive and start any | |
288 | * pending writes by faking a transmit complete. | |
289 | */ | |
290 | s = splimp(); | |
291 | ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; | |
1cd789fb SL |
292 | addr->vviba = (u_short)ubainfo; |
293 | addr->vviea = (u_short)(ubainfo >> 16); | |
0f9c1d6e MK |
294 | addr->vviwc = -(VVBUFSIZE) >> 1; |
295 | addr->vvicsr = VV_IEN | VV_HEN | VV_DEN | VV_ENB; | |
5f3ad58b | 296 | vs->vs_oactive = 1; |
1a568327 | 297 | vs->vs_if.if_flags |= IFF_RUNNING; |
5f3ad58b SL |
298 | vvxint(unit); |
299 | splx(s); | |
5f3ad58b SL |
300 | } |
301 | ||
302 | /* | |
0f9c1d6e MK |
303 | * Do a moderately thorough self-test in all three modes. Mostly |
304 | * to keeps defective nodes off the ring, rather than to be especially | |
305 | * thorough. The key issue is to detect any cable breaks before joining | |
306 | * the ring. Return our node address on success, return -1 on failure. | |
307 | * | |
5f3ad58b | 308 | */ |
0f9c1d6e MK |
309 | |
310 | /* the three self-test modes */ | |
311 | static u_short vv_modes[] = { | |
312 | VV_STE|VV_LPB, /* digital loopback */ | |
313 | VV_STE, /* analog loopback */ | |
314 | VV_HEN /* network mode */ | |
315 | }; | |
316 | ||
38061563 | 317 | vvidentify(unit) |
1cd789fb | 318 | int unit; |
38061563 | 319 | { |
a23ec69a CL |
320 | register struct vv_softc *vs; |
321 | register struct uba_device *ui; | |
5f3ad58b | 322 | register struct vvreg *addr; |
aa531fcf MK |
323 | register struct mbuf *m; |
324 | register struct vv_header *v; | |
0f9c1d6e MK |
325 | register int ubainfo; |
326 | register int i, successes, failures, waitcount; | |
327 | u_short shost = -1; | |
5f3ad58b | 328 | |
a23ec69a CL |
329 | vs = &vv_softc[unit]; |
330 | ui = vvinfo[unit]; | |
5f3ad58b | 331 | addr = (struct vvreg *)ui->ui_addr; |
0f9c1d6e MK |
332 | |
333 | /* | |
334 | * Build a multicast message to identify our address | |
335 | * We need do this only once, since nobody else is about to use | |
336 | * the intermediate transmit buffer (ifu_w.ifrw_addr) that | |
337 | * if_ubainit() aquired for us. | |
338 | */ | |
38061563 | 339 | m = m_get(M_DONTWAIT, MT_HEADER); |
2888e947 CL |
340 | if (m == NULL) { |
341 | printf("vv%d: can't initialize, m_get() failed\n", unit); | |
1cd789fb | 342 | return (0); |
2888e947 | 343 | } |
4cdd59b5 | 344 | m->m_next = 0; |
547e5718 SL |
345 | m->m_off = MMINOFF; |
346 | m->m_len = sizeof(struct vv_header); | |
547e5718 | 347 | v = mtod(m, struct vv_header *); |
4cdd59b5 | 348 | v->vh_dhost = VV_BROADCAST; /* multicast destination address */ |
547e5718 SL |
349 | v->vh_shost = 0; /* will be overwritten with ours */ |
350 | v->vh_version = RING_VERSION; | |
0f9c1d6e | 351 | v->vh_type = RING_DIAGNOSTICS; |
547e5718 | 352 | v->vh_info = 0; |
0f9c1d6e MK |
353 | /* map xmit message into uba, copying to intermediate buffer */ |
354 | vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); | |
5f3ad58b | 355 | |
547e5718 | 356 | /* |
0f9c1d6e MK |
357 | * For each of the modes (digital, analog, network), go through |
358 | * a self-test that requires me to send VVIDENTSUCC good packets | |
359 | * in VVIDENTRETRY attempts. Use broadcast destination to find out | |
360 | * who I am, then use this as my address to check my address match | |
361 | * logic. Only data checked is the vh_type field. | |
547e5718 | 362 | */ |
0f9c1d6e MK |
363 | |
364 | for (i = 0; i < 3; i++) { | |
365 | successes = 0; /* clear successes for this mode */ | |
366 | failures = 0; /* and clear failures, too */ | |
367 | ||
368 | /* take over device, and leave ring */ | |
369 | addr->vvicsr = VV_RST; | |
370 | addr->vvocsr = VV_RST; | |
371 | addr->vvicsr = vv_modes[i]; /* test mode */ | |
372 | ||
373 | /* | |
374 | * let the flag and token timers pop so that the init ring bit | |
375 | * will be allowed to work, by waiting about 1 second | |
376 | */ | |
377 | DELAY(1000000L); | |
378 | ||
379 | /* | |
380 | * retry loop | |
381 | */ | |
382 | while ((successes < VVIDENTSUCC) && (failures < VVIDENTRETRY)) | |
383 | { | |
384 | /* start a receive */ | |
385 | ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; | |
386 | addr->vvicsr = VV_RST | vv_modes[i]; /* abort last */ | |
387 | addr->vviba = (u_short) ubainfo; | |
388 | addr->vviea = (u_short) (ubainfo >> 16); | |
389 | addr->vviwc = -(VVBUFSIZE) >> 1; | |
390 | addr->vvicsr = vv_modes[i] | VV_DEN | VV_ENB; | |
391 | ||
392 | /* purge stale data from BDP */ | |
393 | if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) | |
394 | UBAPURGE(vs->vs_ifuba.ifu_uba, | |
395 | vs->vs_ifuba.ifu_w.ifrw_bdp); | |
396 | ||
397 | /* do a transmit */ | |
398 | ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; | |
399 | addr->vvocsr = VV_RST; /* abort last try */ | |
400 | addr->vvoba = (u_short) ubainfo; | |
401 | addr->vvoea = (u_short) (ubainfo >> 16); | |
402 | addr->vvowc = -((vs->vs_olen + 1) >> 1); | |
403 | addr->vvocsr = VV_CPB | VV_DEN | VV_INR | VV_ENB; | |
404 | ||
405 | /* poll receive side for completion */ | |
406 | DELAY(10000); /* give it a chance */ | |
407 | for (waitcount = 0; waitcount < 10; waitcount++) { | |
408 | if (addr->vvicsr & VV_RDY) | |
409 | goto gotit; | |
410 | DELAY(1000); | |
411 | } | |
412 | failures++; /* no luck */ | |
38061563 | 413 | continue; |
0f9c1d6e MK |
414 | |
415 | gotit: /* we got something--is it any good? */ | |
416 | if ((addr->vvicsr & (VVRERR|VV_LDE)) || | |
1a568327 | 417 | (addr->vvocsr & (VVXERR|VV_RFS))) { |
0f9c1d6e MK |
418 | failures++; |
419 | continue; | |
420 | } | |
421 | ||
422 | /* Purge BDP before looking at received packet */ | |
423 | if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) | |
424 | UBAPURGE(vs->vs_ifuba.ifu_uba, | |
425 | vs->vs_ifuba.ifu_r.ifrw_bdp); | |
67eb6277 MK |
426 | m = if_rubaget(&vs->vs_ifuba, sizeof(struct vv_header), |
427 | 0, 0); | |
0f9c1d6e MK |
428 | if (m != NULL) |
429 | m_freem(m); | |
430 | ||
431 | v = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); | |
432 | ||
433 | /* check message type, catch our node address */ | |
434 | if ((v->vh_type & 0xff) == RING_DIAGNOSTICS) { | |
435 | if (shost == -1) { | |
436 | shost = v->vh_shost & 0xff; | |
437 | /* send to ourself now */ | |
438 | ((struct vv_header *) | |
439 | (vs->vs_ifuba.ifu_r.ifrw_addr)) | |
440 | ->vh_dhost = shost; | |
441 | } | |
442 | successes++; | |
443 | v->vh_type = 0; /* clear to check again */ | |
444 | } | |
445 | } | |
446 | ||
447 | if (failures >= VVIDENTRETRY) | |
448 | { | |
449 | printf("vv%d: failed self-test after %d tries \ | |
450 | in %s mode\n", | |
451 | unit, VVIDENTRETRY, i == 0 ? "digital loopback" : | |
452 | (i == 1 ? "analog loopback" : "network")); | |
453 | printf("vv%d: icsr = %b, ocsr = %b\n", | |
454 | unit, 0xffff & addr->vvicsr, VV_IBITS, | |
455 | 0xffff & addr->vvocsr, VV_OBITS); | |
456 | addr->vvicsr = VV_RST; /* kill the sick board */ | |
457 | addr->vvocsr = VV_RST; | |
458 | shost = -1; | |
459 | goto done; | |
4cdd59b5 | 460 | } |
4cdd59b5 | 461 | } |
0f9c1d6e MK |
462 | |
463 | done: | |
464 | /* deallocate mbuf used for send packet (won't be one, anyways) */ | |
2888e947 | 465 | if (vs->vs_ifuba.ifu_xtofree) { |
547e5718 | 466 | m_freem(vs->vs_ifuba.ifu_xtofree); |
2888e947 CL |
467 | vs->vs_ifuba.ifu_xtofree = 0; |
468 | } | |
0f9c1d6e MK |
469 | |
470 | return(shost); | |
4cdd59b5 SL |
471 | } |
472 | ||
547e5718 SL |
473 | /* |
474 | * Start or restart output on interface. | |
4cdd59b5 SL |
475 | * If interface is active, this is a retransmit, so just |
476 | * restuff registers and go. | |
547e5718 SL |
477 | * If interface is not already active, get another datagram |
478 | * to send off of the interface queue, and map it to the interface | |
479 | * before starting the output. | |
480 | */ | |
481 | vvstart(dev) | |
482 | dev_t dev; | |
483 | { | |
aa531fcf | 484 | register struct uba_device *ui; |
a23ec69a | 485 | register struct vv_softc *vs; |
547e5718 | 486 | register struct vvreg *addr; |
aa531fcf MK |
487 | register struct mbuf *m; |
488 | register int unit, ubainfo, dest, s; | |
547e5718 | 489 | |
aa531fcf | 490 | unit = VVUNIT(dev); |
a23ec69a CL |
491 | ui = vvinfo[unit]; |
492 | vs = &vv_softc[unit]; | |
547e5718 SL |
493 | if (vs->vs_oactive) |
494 | goto restart; | |
547e5718 SL |
495 | /* |
496 | * Not already active: dequeue another request | |
497 | * and map it to the UNIBUS. If no more requests, | |
498 | * just return. | |
499 | */ | |
2888e947 | 500 | s = splimp(); |
547e5718 | 501 | IF_DEQUEUE(&vs->vs_if.if_snd, m); |
2888e947 | 502 | splx(s); |
38061563 | 503 | if (m == NULL) { |
547e5718 SL |
504 | vs->vs_oactive = 0; |
505 | return; | |
506 | } | |
507 | dest = mtod(m, struct vv_header *)->vh_dhost; | |
508 | vs->vs_olen = if_wubaput(&vs->vs_ifuba, m); | |
509 | vs->vs_lastx = dest; | |
547e5718 SL |
510 | restart: |
511 | /* | |
512 | * Have request mapped to UNIBUS for transmission. | |
2888e947 CL |
513 | * Purge any stale data from this BDP, and start the output. |
514 | * | |
515 | * Make sure this packet will fit in the interface. | |
a23ec69a | 516 | */ |
0f9c1d6e MK |
517 | if (vs->vs_olen > VVBUFSIZE) { |
518 | printf("vv%d vs_olen: %d > VVBUFSIZE\n", unit, vs->vs_olen); | |
4cdd59b5 SL |
519 | panic("vvdriver vs_olen botch"); |
520 | } | |
0f9c1d6e MK |
521 | |
522 | vs->vs_if.if_timer = VVTIMEOUT; | |
523 | vs->vs_oactive = 1; | |
524 | ||
525 | /* ship it */ | |
547e5718 SL |
526 | if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) |
527 | UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_w.ifrw_bdp); | |
528 | addr = (struct vvreg *)ui->ui_addr; | |
529 | ubainfo = vs->vs_ifuba.ifu_w.ifrw_info; | |
530 | addr->vvoba = (u_short) ubainfo; | |
531 | addr->vvoea = (u_short) (ubainfo >> 16); | |
532 | addr->vvowc = -((vs->vs_olen + 1) >> 1); | |
0f9c1d6e MK |
533 | addr->vvowc = -((vs->vs_olen + 1) >> 1); /* extra byte is garbage */ |
534 | if (addr->vvocsr & VV_NOK) | |
535 | vs->vs_init++; /* count ring inits */ | |
547e5718 | 536 | addr->vvocsr = VV_IEN | VV_CPB | VV_DEN | VV_INR | VV_ENB; |
2888e947 | 537 | vs->vs_if.if_timer = VVTIMEOUT; |
547e5718 SL |
538 | vs->vs_oactive = 1; |
539 | } | |
540 | ||
541 | /* | |
0f9c1d6e | 542 | * proNET transmit interrupt |
547e5718 SL |
543 | * Start another output if more data to send. |
544 | */ | |
545 | vvxint(unit) | |
546 | int unit; | |
547 | { | |
a23ec69a CL |
548 | register struct uba_device *ui; |
549 | register struct vv_softc *vs; | |
547e5718 SL |
550 | register struct vvreg *addr; |
551 | register int oc; | |
547e5718 | 552 | |
a23ec69a CL |
553 | ui = vvinfo[unit]; |
554 | vs = &vv_softc[unit]; | |
2888e947 | 555 | vs->vs_if.if_timer = 0; |
547e5718 SL |
556 | addr = (struct vvreg *)ui->ui_addr; |
557 | oc = 0xffff & (addr->vvocsr); | |
558 | if (vs->vs_oactive == 0) { | |
0f9c1d6e | 559 | vvprintf("vv%d: stray interrupt vvocsr = %b\n", unit, |
a23ec69a | 560 | oc, VV_OBITS); |
547e5718 SL |
561 | return; |
562 | } | |
0f9c1d6e MK |
563 | |
564 | /* | |
565 | * we retransmit on soft error | |
566 | * TODO: sort retransmits to end of queue if possible! | |
567 | */ | |
568 | if (oc & (VV_OPT | VV_RFS)) { | |
4cdd59b5 | 569 | if (vs->vs_tries++ < VVRETRY) { |
547e5718 | 570 | if (oc & VV_OPT) |
0f9c1d6e MK |
571 | vs->vs_otimeout++; |
572 | if (oc & VV_RFS) { | |
573 | vs->vs_if.if_collisions++; | |
574 | vs->vs_refused++; | |
575 | } | |
4cdd59b5 | 576 | vvstart(unit); /* restart this message */ |
547e5718 SL |
577 | return; |
578 | } | |
547e5718 SL |
579 | } |
580 | vs->vs_if.if_opackets++; | |
581 | vs->vs_oactive = 0; | |
582 | vs->vs_tries = 0; | |
0f9c1d6e | 583 | |
547e5718 SL |
584 | if (oc & VVXERR) { |
585 | vs->vs_if.if_oerrors++; | |
0f9c1d6e | 586 | vvprintf("vv%d: error vvocsr = %b\n", unit, 0xffff & oc, |
a23ec69a | 587 | VV_OBITS); |
547e5718 SL |
588 | } |
589 | if (vs->vs_ifuba.ifu_xtofree) { | |
590 | m_freem(vs->vs_ifuba.ifu_xtofree); | |
591 | vs->vs_ifuba.ifu_xtofree = 0; | |
592 | } | |
547e5718 SL |
593 | vvstart(unit); |
594 | } | |
595 | ||
2888e947 CL |
596 | /* |
597 | * Transmit watchdog timer routine. | |
598 | * This routine gets called when we lose a transmit interrupt. | |
599 | * The best we can do is try to restart output. | |
600 | */ | |
601 | vvwatchdog(unit) | |
602 | int unit; | |
603 | { | |
604 | register struct vv_softc *vs; | |
605 | register int s; | |
606 | ||
607 | vs = &vv_softc[unit]; | |
0f9c1d6e | 608 | vvprintf("vv%d: lost a transmit interrupt.\n", unit); |
2888e947 CL |
609 | vs->vs_timeouts++; |
610 | s = splimp(); | |
611 | vvstart(unit); | |
612 | splx(s); | |
613 | } | |
614 | ||
547e5718 | 615 | /* |
0f9c1d6e | 616 | * proNET interface receiver interrupt. |
547e5718 | 617 | * If input error just drop packet. |
a23ec69a | 618 | * Otherwise purge input buffered data path and examine |
547e5718 | 619 | * packet to determine type. If can't determine length |
a23ec69a | 620 | * from type, then have to drop packet. Otherwise decapsulate |
547e5718 SL |
621 | * packet based on type and pass to type specific higher-level |
622 | * input routine. | |
623 | */ | |
624 | vvrint(unit) | |
625 | int unit; | |
626 | { | |
a23ec69a | 627 | register struct vv_softc *vs; |
aa531fcf | 628 | register struct vvreg *addr; |
547e5718 SL |
629 | register struct vv_header *vv; |
630 | register struct ifqueue *inq; | |
aa531fcf | 631 | register struct mbuf *m; |
2888e947 | 632 | int ubainfo, len, off, s; |
5f3ad58b | 633 | short resid; |
547e5718 | 634 | |
a23ec69a | 635 | vs = &vv_softc[unit]; |
547e5718 | 636 | vs->vs_if.if_ipackets++; |
aa531fcf | 637 | addr = (struct vvreg *)vvinfo[unit]->ui_addr; |
0f9c1d6e | 638 | |
547e5718 SL |
639 | /* |
640 | * Purge BDP; drop if input error indicated. | |
641 | */ | |
642 | if (vs->vs_ifuba.ifu_flags & UBA_NEEDBDP) | |
643 | UBAPURGE(vs->vs_ifuba.ifu_uba, vs->vs_ifuba.ifu_r.ifrw_bdp); | |
0f9c1d6e MK |
644 | |
645 | /* | |
646 | * receive errors? | |
647 | */ | |
547e5718 | 648 | if (addr->vvicsr & VVRERR) { |
0f9c1d6e MK |
649 | vvprintf("vv%d: receive error, vvicsr = %b\n", unit, |
650 | 0xffff&(addr->vvicsr), VV_IBITS); | |
651 | if (addr->vvicsr & VV_BDF) | |
652 | vs->vs_ibadf++; | |
5f3ad58b | 653 | goto dropit; |
547e5718 | 654 | } |
5f3ad58b | 655 | |
547e5718 | 656 | /* |
0f9c1d6e MK |
657 | * parity errors? |
658 | */ | |
659 | if (addr->vvicsr & VV_LDE) { | |
660 | /* we don't have to clear it because the receive command */ | |
661 | /* writes 0 to parity bit */ | |
662 | vs->vs_parity++; | |
663 | #ifndef PRONET80 | |
664 | /* | |
665 | * only on 10 megabit proNET is VV_LDE an end-to-end parity | |
666 | * bit. On 80 megabit, it returns to the intended use of | |
667 | * node-to-node parity. End-to-end parity errors on 80 megabit | |
668 | * give VV_BDF. | |
669 | */ | |
670 | goto dropit; | |
671 | #endif | |
672 | } | |
673 | ||
674 | /* | |
675 | * Get packet length from residual word count | |
5f3ad58b SL |
676 | * |
677 | * Compute header offset if trailer protocol | |
678 | * | |
679 | * Pull packet off interface. Off is nonzero if packet | |
680 | * has trailing header; if_rubaget will then force this header | |
681 | * information to be at the front. The vh_info field | |
682 | * carries the offset to the trailer data in trailer | |
683 | * format packets. | |
547e5718 | 684 | */ |
5f3ad58b | 685 | vv = (struct vv_header *)(vs->vs_ifuba.ifu_r.ifrw_addr); |
4cdd59b5 | 686 | vvtracehdr("vi", vv); |
0f9c1d6e | 687 | resid = addr->vviwc & 01777; /* only low 10 bits valid */ |
5f3ad58b | 688 | if (resid) |
0f9c1d6e MK |
689 | resid |= 0176000; /* high 6 bits are undefined */ |
690 | len = ((VVBUFSIZE >> 1) + resid) << 1; | |
5f3ad58b | 691 | len -= sizeof(struct vv_header); |
0f9c1d6e MK |
692 | |
693 | if ((addr->vvicsr & VV_DPR) || len > VVMRU || len <= 0) { | |
694 | vvprintf("vv%d: len too long or short, \ | |
695 | len = %d, vvicsr = %b\n", | |
2888e947 | 696 | unit, len, 0xffff&(addr->vvicsr), VV_IBITS); |
5f3ad58b | 697 | goto dropit; |
2888e947 | 698 | } |
0f9c1d6e MK |
699 | |
700 | /* check the protocol header version */ | |
701 | if (vv->vh_version != RING_VERSION) { | |
702 | vvprintf("vv%d: bad protocol header version %d\n", | |
703 | unit, vv->vh_version & 0xff); | |
704 | goto dropit; | |
705 | } | |
706 | ||
5f3ad58b | 707 | #define vvdataaddr(vv, off, type) ((type)(((caddr_t)((vv)+1)+(off)))) |
1cd789fb SL |
708 | if (vv->vh_type >= RING_IPTrailer && |
709 | vv->vh_type < RING_IPTrailer+RING_IPNTrailer) { | |
5f3ad58b | 710 | off = (vv->vh_type - RING_IPTrailer) * 512; |
2888e947 | 711 | if (off > VVMTU) { |
0f9c1d6e | 712 | vvprintf("vv%d: off > VVMTU, off = %d, vvicsr = %b\n", |
2888e947 | 713 | unit, off, 0xffff&(addr->vvicsr), VV_IBITS); |
5f3ad58b | 714 | goto dropit; |
2888e947 | 715 | } |
5f3ad58b SL |
716 | vv->vh_type = *vvdataaddr(vv, off, u_short *); |
717 | resid = *(vvdataaddr(vv, off+2, u_short *)); | |
2888e947 | 718 | if (off + resid > len) { |
0f9c1d6e MK |
719 | vvprintf("vv%d: trailer packet too short\n", unit); |
720 | vvprintf("vv%d: off = %d, resid = %d, vvicsr = %b\n", | |
2888e947 CL |
721 | unit, off, resid, |
722 | 0xffff&(addr->vvicsr), VV_IBITS); | |
5f3ad58b | 723 | goto dropit; |
2888e947 | 724 | } |
5f3ad58b | 725 | len = off + resid; |
38061563 | 726 | } else |
5f3ad58b | 727 | off = 0; |
0f9c1d6e | 728 | |
2888e947 | 729 | if (len == 0) { |
0f9c1d6e | 730 | vvprintf("vv%d: len is zero, vvicsr = %b\n", unit, |
2888e947 | 731 | 0xffff&(addr->vvicsr), VV_IBITS); |
5f3ad58b | 732 | goto dropit; |
2888e947 | 733 | } |
0f9c1d6e | 734 | |
67eb6277 | 735 | m = if_rubaget(&vs->vs_ifuba, len, off, &vs->vs_if); |
2888e947 | 736 | if (m == NULL) { |
0f9c1d6e | 737 | vvprintf("vv%d: if_rubaget() failed, vvicsr = %b\n", unit, |
2888e947 | 738 | 0xffff&(addr->vvicsr), VV_IBITS); |
5f3ad58b | 739 | goto dropit; |
2888e947 | 740 | } |
5f3ad58b | 741 | if (off) { |
67eb6277 MK |
742 | struct ifnet *ifp; |
743 | ||
744 | ifp = *(mtod(m, struct ifnet **)); | |
745 | m->m_off += 2 * sizeof (u_short); | |
746 | m->m_len -= 2 * sizeof (u_short); | |
747 | *(mtod(m, struct ifnet **)) = ifp; | |
5f3ad58b | 748 | } |
4cdd59b5 | 749 | |
2888e947 CL |
750 | /* Keep track of source address of this packet */ |
751 | vs->vs_lastr = vv->vh_shost; | |
0f9c1d6e | 752 | |
4cdd59b5 | 753 | /* |
a23ec69a | 754 | * Demultiplex on packet type |
4cdd59b5 | 755 | */ |
547e5718 | 756 | switch (vv->vh_type) { |
4cdd59b5 | 757 | |
547e5718 SL |
758 | #ifdef INET |
759 | case RING_IP: | |
547e5718 SL |
760 | schednetisr(NETISR_IP); |
761 | inq = &ipintrq; | |
762 | break; | |
763 | #endif | |
764 | default: | |
0f9c1d6e | 765 | vvprintf("vv%d: unknown pkt type 0x%x\n", unit, vv->vh_type); |
5f3ad58b | 766 | m_freem(m); |
547e5718 SL |
767 | goto setup; |
768 | } | |
2888e947 | 769 | s = splimp(); |
5f3ad58b SL |
770 | if (IF_QFULL(inq)) { |
771 | IF_DROP(inq); | |
772 | m_freem(m); | |
38061563 | 773 | } else |
5f3ad58b | 774 | IF_ENQUEUE(inq, m); |
a23ec69a | 775 | |
2888e947 | 776 | splx(s); |
547e5718 | 777 | /* |
a23ec69a | 778 | * Reset for the next packet. |
4cdd59b5 | 779 | */ |
a23ec69a CL |
780 | setup: |
781 | ubainfo = vs->vs_ifuba.ifu_r.ifrw_info; | |
782 | addr->vviba = (u_short) ubainfo; | |
783 | addr->vviea = (u_short) (ubainfo >> 16); | |
0f9c1d6e MK |
784 | addr->vviwc = -(VVBUFSIZE) >> 1; |
785 | addr->vvicsr = VV_HEN | VV_IEN | VV_DEN | VV_ENB; | |
a23ec69a | 786 | return; |
4cdd59b5 | 787 | |
4cdd59b5 | 788 | /* |
38061563 | 789 | * Drop packet on floor -- count them!! |
547e5718 | 790 | */ |
5f3ad58b SL |
791 | dropit: |
792 | vs->vs_if.if_ierrors++; | |
5f3ad58b | 793 | goto setup; |
547e5718 SL |
794 | } |
795 | ||
796 | /* | |
0f9c1d6e | 797 | * proNET output routine. |
547e5718 SL |
798 | * Encapsulate a packet of type family for the local net. |
799 | * Use trailer local net encapsulation if enough data in first | |
800 | * packet leaves a multiple of 512 bytes of data in remainder. | |
801 | */ | |
802 | vvoutput(ifp, m0, dst) | |
803 | struct ifnet *ifp; | |
804 | struct mbuf *m0; | |
805 | struct sockaddr *dst; | |
806 | { | |
aa531fcf | 807 | register struct mbuf *m; |
547e5718 | 808 | register struct vv_header *vv; |
5f3ad58b | 809 | register int off; |
aa531fcf MK |
810 | register int unit; |
811 | register struct vvreg *addr; | |
812 | register struct vv_softc *vs; | |
813 | register int s; | |
814 | int type, dest, error; | |
815 | ||
816 | m = m0; | |
817 | unit = ifp->if_unit; | |
818 | addr = (struct vvreg *)vvinfo[unit]->ui_addr; | |
819 | vs = &vv_softc[unit]; | |
0f9c1d6e | 820 | |
aa531fcf | 821 | /* |
0f9c1d6e MK |
822 | * Check to see if the input side has wedged due the UBA |
823 | * vectoring through 0. | |
aa531fcf MK |
824 | * |
825 | * We are lower than device ipl when we enter this routine, | |
826 | * so if the interface is ready with an input packet then | |
827 | * an input interrupt must have slipped through the cracks. | |
828 | * | |
829 | * Avoid the race with an input interrupt by watching to see | |
830 | * if any packets come in. | |
831 | */ | |
832 | s = vs->vs_if.if_ipackets; | |
833 | if (addr->vvicsr & VV_RDY && s == vs->vs_if.if_ipackets) { | |
0f9c1d6e | 834 | vvprintf("vv%d: lost a receive interrupt, icsr = %b\n", |
aa531fcf MK |
835 | unit, 0xffff&(addr->vvicsr), VV_IBITS); |
836 | s = splimp(); | |
837 | vvrint(unit); | |
838 | splx(s); | |
839 | } | |
547e5718 SL |
840 | |
841 | switch (dst->sa_family) { | |
4cdd59b5 | 842 | |
547e5718 | 843 | #ifdef INET |
a23ec69a | 844 | case AF_INET: |
1a568327 MK |
845 | if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr)) |
846 | dest = VV_BROADCAST; | |
847 | else | |
848 | dest = in_lnaof(((struct sockaddr_in *)dst)->sin_addr); | |
0f9c1d6e | 849 | #ifdef LOOPBACK |
1a568327 MK |
850 | if (dest == vs->vs_host && (loif.if_flags & IFF_UP)) |
851 | return (looutput(&loif, m0, dst)); | |
0f9c1d6e | 852 | #endif LOOPBACK |
1a568327 | 853 | if (dest >= 0x100) { |
5f3ad58b SL |
854 | error = EPERM; |
855 | goto bad; | |
856 | } | |
5f3ad58b | 857 | off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; |
0f9c1d6e MK |
858 | /* |
859 | * Trailerize, if the configuration allows it. | |
860 | * TODO: Need per host negotiation. | |
861 | */ | |
44eb2da3 SL |
862 | if ((ifp->if_flags & IFF_NOTRAILERS) == 0) |
863 | if (off > 0 && (off & 0x1ff) == 0 && | |
5f3ad58b SL |
864 | m->m_off >= MMINOFF + 2 * sizeof (u_short)) { |
865 | type = RING_IPTrailer + (off>>9); | |
866 | m->m_off -= 2 * sizeof (u_short); | |
867 | m->m_len += 2 * sizeof (u_short); | |
868 | *mtod(m, u_short *) = RING_IP; | |
869 | *(mtod(m, u_short *) + 1) = m->m_len; | |
870 | goto gottrailertype; | |
871 | } | |
547e5718 SL |
872 | type = RING_IP; |
873 | off = 0; | |
874 | goto gottype; | |
547e5718 SL |
875 | #endif |
876 | default: | |
aa531fcf | 877 | printf("vv%d: can't handle af%d\n", unit, dst->sa_family); |
5f3ad58b SL |
878 | error = EAFNOSUPPORT; |
879 | goto bad; | |
547e5718 SL |
880 | } |
881 | ||
882 | gottrailertype: | |
883 | /* | |
884 | * Packet to be sent as trailer: move first packet | |
885 | * (control information) to end of chain. | |
886 | */ | |
887 | while (m->m_next) | |
888 | m = m->m_next; | |
889 | m->m_next = m0; | |
890 | m = m0->m_next; | |
891 | m0->m_next = 0; | |
892 | m0 = m; | |
547e5718 SL |
893 | gottype: |
894 | /* | |
895 | * Add local net header. If no space in first mbuf, | |
896 | * allocate another. | |
897 | */ | |
898 | if (m->m_off > MMAXOFF || | |
899 | MMINOFF + sizeof (struct vv_header) > m->m_off) { | |
38061563 SL |
900 | m = m_get(M_DONTWAIT, MT_HEADER); |
901 | if (m == NULL) { | |
5f3ad58b SL |
902 | error = ENOBUFS; |
903 | goto bad; | |
547e5718 SL |
904 | } |
905 | m->m_next = m0; | |
906 | m->m_off = MMINOFF; | |
907 | m->m_len = sizeof (struct vv_header); | |
908 | } else { | |
909 | m->m_off -= sizeof (struct vv_header); | |
910 | m->m_len += sizeof (struct vv_header); | |
911 | } | |
912 | vv = mtod(m, struct vv_header *); | |
1a568327 MK |
913 | vv->vh_shost = vs->vs_host; |
914 | vv->vh_dhost = dest; | |
547e5718 SL |
915 | vv->vh_version = RING_VERSION; |
916 | vv->vh_type = type; | |
5f3ad58b | 917 | vv->vh_info = off; |
4cdd59b5 | 918 | vvtracehdr("vo", vv); |
547e5718 SL |
919 | |
920 | /* | |
921 | * Queue message on interface, and start output if interface | |
922 | * not yet active. | |
923 | */ | |
924 | s = splimp(); | |
5f3ad58b SL |
925 | if (IF_QFULL(&ifp->if_snd)) { |
926 | IF_DROP(&ifp->if_snd); | |
927 | error = ENOBUFS; | |
928 | goto qfull; | |
929 | } | |
547e5718 | 930 | IF_ENQUEUE(&ifp->if_snd, m); |
aa531fcf MK |
931 | if (vs->vs_oactive == 0) |
932 | vvstart(unit); | |
547e5718 | 933 | splx(s); |
5f3ad58b | 934 | return (0); |
5f3ad58b SL |
935 | qfull: |
936 | m0 = m; | |
937 | splx(s); | |
938 | bad: | |
939 | m_freem(m0); | |
940 | return(error); | |
547e5718 SL |
941 | } |
942 | ||
1cd789fb SL |
943 | /* |
944 | * Process an ioctl request. | |
945 | */ | |
946 | vvioctl(ifp, cmd, data) | |
947 | register struct ifnet *ifp; | |
948 | int cmd; | |
949 | caddr_t data; | |
950 | { | |
1a568327 MK |
951 | struct ifaddr *ifa = (struct ifaddr *) data; |
952 | int s = splimp(), error = 0; | |
1cd789fb SL |
953 | |
954 | switch (cmd) { | |
955 | ||
956 | case SIOCSIFADDR: | |
67eb6277 | 957 | ifp->if_flags |= IFF_UP; |
1a568327 | 958 | if ((ifp->if_flags & IFF_RUNNING) == 0) |
1cd789fb | 959 | vvinit(ifp->if_unit); |
1a568327 MK |
960 | /* |
961 | * Attempt to check agreement of protocol address | |
962 | * and board address. | |
963 | */ | |
964 | switch (ifa->ifa_addr.sa_family) { | |
965 | case AF_INET: | |
966 | if (in_lnaof(IA_SIN(ifa)->sin_addr) != | |
967 | vv_softc[ifp->if_unit].vs_host) | |
e37ca38f | 968 | error = EADDRNOTAVAIL; |
1a568327 MK |
969 | break; |
970 | } | |
1cd789fb SL |
971 | break; |
972 | ||
973 | default: | |
974 | error = EINVAL; | |
975 | } | |
976 | splx(s); | |
1a568327 | 977 | return (error); |
547e5718 | 978 | } |
5417a52b MK |
979 | |
980 | /* | |
981 | * vvprt_hdr(s, v) print the local net header in "v" | |
982 | * with title is "s" | |
983 | */ | |
984 | vvprt_hdr(s, v) | |
985 | char *s; | |
986 | register struct vv_header *v; | |
987 | { | |
988 | printf("%s: dsvti: 0x%x 0x%x 0x%x 0x%x 0x%x\n", | |
989 | s, | |
990 | 0xff & (int)(v->vh_dhost), 0xff & (int)(v->vh_shost), | |
991 | 0xff & (int)(v->vh_version), 0xff & (int)(v->vh_type), | |
992 | 0xffff & (int)(v->vh_info)); | |
993 | } | |
9a0b0c74 | 994 | #endif |