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