Commit | Line | Data |
---|---|---|
8b1363a5 KB |
1 | /* |
2 | * Copyright IBM Corporation 1987,1990 | |
3 | * | |
4 | * All Rights Reserved | |
5 | * | |
6 | * Permission to use, copy, modify, and distribute this software and its | |
7 | * documentation for any purpose and without fee is hereby granted, | |
8 | * provided that the above copyright notice appear in all copies and that | |
9 | * both that copyright notice and this permission notice appear in | |
10 | * supporting documentation, and that the name of IBM not be | |
11 | * used in advertising or publicity pertaining to distribution of the | |
12 | * software without specific, written prior permission. | |
13 | * | |
14 | * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
15 | * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR USE. | |
16 | * IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL | |
17 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR | |
18 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS | |
19 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF | |
20 | * THIS SOFTWARE. | |
21 | * | |
22 | * @(#)if_un.eg 7.1 (Berkeley) %G% | |
23 | */ | |
24 | ||
25 | /* | |
26 | * Ungermann-Bass PC-NIC (Ethernet) Adapter (4.3 driver) | |
27 | */ | |
28 | ||
29 | #include "un.h" | |
30 | #if NUN > 0 | |
31 | ||
32 | #include "../machine/pte.h" | |
33 | ||
34 | #include "param.h" | |
35 | #include "systm.h" | |
36 | #include "mbuf.h" | |
37 | #include "buf.h" | |
38 | #include "protosw.h" | |
39 | #include "socket.h" | |
40 | #include "vmmac.h" | |
41 | #include "ioctl.h" | |
42 | #include "errno.h" | |
43 | ||
44 | #include "../net/if.h" | |
45 | #include "../net/netisr.h" | |
46 | #include "../net/route.h" | |
47 | ||
48 | #ifdef INET | |
49 | #include "../netinet/in.h" | |
50 | #include "../netinet/in_systm.h" | |
51 | #include "../netinet/in_var.h" | |
52 | #include "../netinet/ip.h" | |
53 | #include "../netinet/if_ether.h" | |
54 | #endif INET | |
55 | ||
56 | #ifdef NS | |
57 | #include "../netns/ns.h" | |
58 | #include "../netns/ns_if.h" | |
59 | #endif NS | |
60 | ||
61 | #ifdef ISO | |
62 | #include "../netargo/if_clnp.h" | |
63 | #include "../netargo/iso.h" | |
64 | #include "../netargo/iso_var.h" | |
65 | #include "../netargo/argo_debug.h" | |
66 | #endif ISO | |
67 | ||
68 | #include "../machine/io.h" | |
69 | #include "if_unreg.h" | |
70 | #ifdef IEEELLC | |
71 | #include "if_llc.h" | |
72 | #endif IEEELLC | |
73 | #include "../machineio/ioccvar.h" | |
74 | #include "../machine/debug.h" | |
75 | ||
76 | int unprobe(), unattach(); | |
77 | ||
78 | #ifdef AT | |
79 | caddr_t unstd[] = { (caddr_t) 0xa0000, (caddr_t) 0xa8000, | |
80 | (caddr_t) 0xb0000, (caddr_t) 0xb8000, 0 }; | |
81 | #else | |
82 | caddr_t unstd[] = { (caddr_t) 0xf4080000, (caddr_t) 0xf4088000, | |
83 | (caddr_t) 0xf4090000, (caddr_t) 0xf4098000, 0 }; | |
84 | #endif AT | |
85 | ||
86 | struct iocc_device *uninfo[NUN]; | |
87 | ||
88 | int unint(), uninit(), unioctl(), unoutput(), unreset(); | |
89 | ||
90 | struct iocc_driver undriver = | |
91 | { unprobe, 0, unattach, 0, unstd, "un", uninfo, | |
92 | 0, 0, unint, UN_EADDROFF }; | |
93 | ||
94 | struct mbuf *unget(); | |
95 | ||
96 | /* | |
97 | * Ethernet software status per adapter. | |
98 | */ | |
99 | struct un_softc { | |
100 | struct arpcom us_ac; /* generic network interface stuff */ | |
101 | #define us_if us_ac.ac_if /* ifnet struct */ | |
102 | #define us_addr us_ac.ac_enaddr /* hardware (i.e. ethernet) address */ | |
103 | short us_oactive; /* 1 => output active */ | |
104 | short us_nextpage; /* next receive buffer page */ | |
105 | short us_xbuf; /* in-use xmt buf (if output active) */ | |
106 | short us_xfull[2]; /* 1 => a full xmt buf */ | |
107 | short us_xstart[2]; /* start address used in unstart */ | |
108 | } un_softc[NUN]; | |
109 | ||
110 | #ifdef DEBUG | |
111 | char undebug = 0; | |
112 | #endif DEBUG | |
113 | ||
114 | #ifdef ATR | |
115 | #define move_window(window, addr) {\ | |
116 | int real_addr;\ | |
117 | int new_window;\ | |
118 | \ | |
119 | window = get_128_window();\ | |
120 | real_addr = 0xfffff & (int) addr;\ | |
121 | new_window = real_addr & 0xe0000;\ | |
122 | set_128_window(new_window);\ | |
123 | addr = (struct undevice *) (real_addr - new_window);\ | |
124 | } | |
125 | ||
126 | #define restore_window(window) set_128_window(window) | |
127 | #define bcopyin(from,to,len) bcopy((from)+pcif_128_fw,to,len) | |
128 | #define bcopyout(from,to,len) bcopy(from,(to)+pcif_128_fw,len) | |
129 | #endif ATR | |
130 | ||
131 | #ifdef IBMRTPC | |
132 | #define bcopyin bcopy | |
133 | #define bcopyout bcopy | |
134 | #endif IBMRTPC | |
135 | /* | |
136 | * unprobe - try to generate an interrupt (to see if the board is there) | |
137 | */ | |
138 | unprobe(p) | |
139 | register caddr_t p; | |
140 | { | |
141 | register struct undevice *addr = (struct undevice *) p; | |
142 | #ifdef ATR | |
143 | register int old_window; | |
144 | move_window(old_window, addr); | |
145 | #endif ATR | |
146 | (void) unzap(addr); | |
147 | UN_GLOBIENB(0); /* global interrrupt enable */ | |
148 | MM_OUT(&addr->un_csr, UN_GSFTINT); /* generate software interrupt */ | |
149 | PROBE_DELAY(100000); | |
150 | MM_OUT(&addr->un_csr, 0); | |
151 | #ifdef ATR | |
152 | restore_window(old_window); | |
153 | #endif ATR | |
154 | return(PROBE_OK); | |
155 | } | |
156 | ||
157 | /* | |
158 | * unattach - make the interface available to the network software | |
159 | * (if the auto-configuration software determines that the interface | |
160 | * exists). The system will initialize the interface when it is | |
161 | * ready to accept packets. | |
162 | */ | |
163 | unattach(iod) | |
164 | register struct iocc_device *iod; | |
165 | { | |
166 | register struct un_softc *us = &un_softc[iod->iod_unit]; | |
167 | register struct ifnet *ifp = &us->us_if; | |
168 | register struct undevice *addr = (struct undevice *) iod->iod_addr; | |
169 | register int i; | |
170 | #ifdef ATR | |
171 | register int old_window; | |
172 | ||
173 | move_window(old_window, addr); | |
174 | #endif ATR | |
175 | ifp->if_unit = iod->iod_unit; | |
176 | ifp->if_name = "un"; | |
177 | ||
178 | #ifdef IEEELLC | |
179 | ifp->if_mtu = ETHERMTU - 3; /* 3 bytes for UI LLC frame */ | |
180 | #else | |
181 | ifp->if_mtu = ETHERMTU; | |
182 | #endif IEEELCC | |
183 | ||
184 | /* | |
185 | * Read the ethernet address off the board. | |
186 | * Save it and also write it to the edlc chip. | |
187 | */ | |
188 | for (i = 0; i < ETH_ADDR_SIZE; i++){ | |
189 | us->us_addr[i] = MM_IN(&addr->un_eprom[UN_EADDROFF+i]); | |
190 | MM_OUT(&addr->un_edlc.nodeID[i], us->us_addr[i]); | |
191 | } | |
192 | printf("un%d: ethernet address ", ifp->if_unit); | |
193 | unprintethaddr(us->us_addr); | |
194 | printf("\n"); | |
195 | ifp->if_init = uninit; | |
196 | ifp->if_ioctl = unioctl; | |
197 | ifp->if_output = unoutput; | |
198 | ifp->if_reset = unreset; | |
199 | ifp->if_flags = IFF_BROADCAST; | |
200 | #ifdef ISO | |
201 | ifp->if_flags |= IFF_EAVESDROP; | |
202 | #endif ISO | |
203 | if_attach(ifp); | |
204 | DEBUGF(undebug, printf("un%d: attached\n", iod->iod_unit);) | |
205 | #ifdef ATR | |
206 | restore_window(old_window); | |
207 | #endif ATR | |
208 | } | |
209 | ||
210 | /* | |
211 | * unreset - reset interface | |
212 | */ | |
213 | unreset(unit) | |
214 | register unsigned int unit; | |
215 | { | |
216 | register struct iocc_device *iod; | |
217 | ||
218 | if (unit < NUN && (iod = uninfo[unit]) != 0 && iod->iod_alive != 0){ | |
219 | un_softc[unit].us_if.if_flags &= ~IFF_RUNNING; | |
220 | DEBUGF(undebug, printf("un%d: reset\n", unit);) | |
221 | uninit(unit); | |
222 | } | |
223 | } | |
224 | ||
225 | /* | |
226 | * uninit - initialize interface, enable packet reception, start any | |
227 | * pending writes | |
228 | */ | |
229 | uninit(unit) | |
230 | register int unit; | |
231 | { | |
232 | register struct un_softc *us = &un_softc[unit]; | |
233 | register struct ifnet *ifp = &us->us_if; | |
234 | register int s; | |
235 | register struct undevice *addr; | |
236 | register int i; | |
237 | ||
238 | if (ifp->if_addrlist == (struct ifaddr *) 0){ | |
239 | /* no address */ | |
240 | return; | |
241 | } | |
242 | if ((ifp->if_flags & IFF_RUNNING) == 0){ | |
243 | int old_window; | |
244 | ||
245 | addr = (struct undevice *) (uninfo[unit]->iod_addr); | |
246 | #ifdef ATR | |
247 | move_window(old_window, addr); | |
248 | #endif ATR | |
249 | s = splimp(); | |
250 | us->us_nextpage = unzap(addr); /* initialize hardware */ | |
251 | /* unzap returns next receive page to be used */ | |
252 | for (i = 0; i < ETH_ADDR_SIZE; i++){ | |
253 | MM_OUT(&addr->un_edlc.nodeID[i], us->us_addr[i]); | |
254 | } | |
255 | us->us_oactive = 0; /* output not active */ | |
256 | /* turn adapter on */ | |
257 | ifp->if_flags |= IFF_RUNNING; | |
258 | MM_OUT(&addr->un_csr, UN_PAVIENB); | |
259 | /* Allow packet available interrupts */ | |
260 | UN_GLOBIENB(us->us_nextpage); /* global interrrupt enable */ | |
261 | if (ifp->if_snd.ifq_head){ /* anything on send queue */ | |
262 | struct mbuf *m; | |
263 | ||
264 | IF_DEQUEUE(&ifp->if_snd, m); | |
265 | unput(us, addr, m, 0); | |
266 | unstart(us, addr, 0); | |
267 | if (ifp->if_snd.ifq_head){ | |
268 | IF_DEQUEUE(&ifp->if_snd, m); | |
269 | unput(us, addr, m, 1); | |
270 | } | |
271 | } | |
272 | splx(s); | |
273 | #ifdef ATR | |
274 | restore_window(old_window); | |
275 | #endif ATR | |
276 | } | |
277 | DEBUGF(undebug, printf("un%d: init'ed\n", unit);) | |
278 | } | |
279 | ||
280 | /* | |
281 | * unstart - start output from one of the adapter's 2 transmit buffers | |
282 | */ | |
283 | unstart(us, addr, xbuf) | |
284 | register struct un_softc *us; | |
285 | register struct undevice *addr; | |
286 | register int xbuf; | |
287 | { | |
288 | us->us_oactive = 1; | |
289 | us->us_xbuf = xbuf; | |
290 | UN_XMIT(addr, us->us_xstart[xbuf]); | |
291 | MM_OUT(&addr->un_csr, UN_IENABLE); /* enable transmit done interrupt */ | |
292 | } | |
293 | ||
294 | /* | |
295 | * unint - interrupt handler. find the cause of the interrupt and | |
296 | * dispatch an appropriate handler routine. | |
297 | */ | |
298 | unint(unit) | |
299 | register int unit; | |
300 | { | |
301 | register struct un_softc *us = &un_softc[unit]; | |
302 | register struct undevice *addr = | |
303 | (struct undevice *) uninfo[unit]->iod_addr; | |
304 | register char status; | |
305 | register int rc = 1; | |
306 | #ifdef ATR | |
307 | register int old_window; | |
308 | ||
309 | move_window(old_window, addr); | |
310 | #endif ATR | |
311 | ||
312 | UN_DISABLE(us->us_nextpage); | |
313 | while ((status = ~MM_IN(&addr->un_csr)) & UN_PAVINT){ | |
314 | DEBUGF(undebug & 0x2, printf("unint: unit = %d, csr = %b", | |
315 | unit, status & 0xff, UN_CSRBITS);) | |
316 | unrint(unit, us, addr); | |
317 | rc = 0; | |
318 | } | |
319 | if (status & UN_TXRINT){ | |
320 | DEBUGF(undebug & 0x2, printf("unint: unit = %d, csr = %b", | |
321 | unit, status & 0xff, UN_CSRBITS);) | |
322 | unxint(unit, us, addr); | |
323 | rc = 0; | |
324 | } | |
325 | UN_ENABLE(us->us_nextpage); | |
326 | #ifdef ATR | |
327 | restore_window(old_window); | |
328 | #endif ATR | |
329 | return(rc); | |
330 | } | |
331 | ||
332 | /* | |
333 | * unrint - interrupt handler for packet reception. | |
334 | * | |
335 | * log error if error bits are latched, examine packet to determine | |
336 | * type, if can't determine packet length from type, drop packet. | |
337 | * otherwise decapsulate packet based on type and pass to an appropriate | |
338 | * higher-level input routine. | |
339 | */ | |
340 | unrint(unit, us, addr) | |
341 | int unit; | |
342 | register struct un_softc *us; | |
343 | register struct undevice *addr; | |
344 | { | |
345 | register struct ether_header *eh; | |
346 | register struct mbuf *m; | |
347 | register int len; | |
348 | register int off; | |
349 | int resid; | |
350 | struct ifqueue *inq; | |
351 | char status = MM_IN(&addr->un_edlc.rstat); | |
352 | u_short type; | |
353 | u_short ungetushortatoff(); | |
354 | #ifdef IEEELLC | |
355 | struct ether_header ehbuf; | |
356 | #endif IEEELLC | |
357 | ||
358 | MM_OUT(&addr->un_edlc.rstat, status); /* clear status */ | |
359 | /* (the hardware xor's in the value of status setting rstat to 0) */ | |
360 | DEBUGF(undebug & 0x2, printf(" rstat = %b", status, RS_BITS);) | |
361 | /* | |
362 | * Latch errors. (Errors found correspond to packets | |
363 | * that were received prior to the current packet | |
364 | * since packet available interrupts are generated | |
365 | * for good packets only.) | |
366 | */ | |
367 | if (status & RS_ERR){ | |
368 | DEBUGF(undebug, printf("unrint: input error\n");) | |
369 | us->us_if.if_ierrors++; | |
370 | } | |
371 | us->us_if.if_ipackets++; | |
372 | ||
373 | /* | |
374 | * determine the length of the received packet. | |
375 | */ | |
376 | len = 0; | |
377 | off = us->us_nextpage; | |
378 | ||
379 | #define BUMP(page) if (++(page) == UN_NUMRBUFS) page = 0 | |
380 | while ((MM_IN(&addr->un_pram[us->us_nextpage]) & UN_LAST_PAGE) == 0){ | |
381 | len += UN_RBUFSIZE; | |
382 | BUMP(us->us_nextpage); | |
383 | } | |
384 | len += (MM_IN(&addr->un_pram[us->us_nextpage]) & | |
385 | UN_PAGE_LENGTH_MASK) + 1; | |
386 | BUMP(us->us_nextpage); | |
387 | #undef BUMP | |
388 | DEBUGF(undebug & 0x2, printf(" len = %d ", len);) | |
389 | if (len > UN_XBSIZE){ | |
390 | printf("un%d: huge packet!\n",unit); | |
391 | goto chuckit; | |
392 | } | |
393 | /* | |
394 | * Process the packet | |
395 | */ | |
396 | eh = (struct ether_header *) &addr->un_rcvbuf[off][0]; | |
397 | DEBUGF(undebug & 0x2, | |
398 | { char cbuf[6]; | |
399 | printf(" from = "); | |
400 | bcopyin(eh->ether_shost, cbuf, sizeof(cbuf)); | |
401 | unprintethaddr(cbuf); | |
402 | printf(" to = "); | |
403 | bcopyin(eh->ether_dhost, cbuf, sizeof(cbuf)); | |
404 | unprintethaddr(cbuf); | |
405 | printf(" "); } | |
406 | ) | |
407 | len -= sizeof(struct ether_header); | |
408 | type = ntohs((u_short) MM_INW(&eh->ether_type)); | |
409 | /* | |
410 | * The ETHERTYPE_NTRAILER packet types starting at ETHERTYPE_TRAIL | |
411 | * have (type - ETHERTYPE_TRAIL) * 512 bytes of data followed by | |
412 | * a type field and then a (variable length) header | |
413 | */ | |
414 | if (type >= ETHERTYPE_TRAIL && | |
415 | type < ETHERTYPE_TRAIL+ETHERTYPE_NTRAILER){ | |
416 | off = (type - ETHERTYPE_TRAIL) * 512; | |
417 | if (off >= ETHERMTU){ | |
418 | goto chuckit; | |
419 | } | |
420 | type = ungetushortatoff(addr, eh, off); | |
421 | resid = ungetushortatoff(addr, eh, off + 2); | |
422 | if (off + resid > len){ | |
423 | goto chuckit; | |
424 | } | |
425 | len = off + resid; | |
426 | } else { | |
427 | off = 0; | |
428 | } | |
429 | if (len == 0){ | |
430 | goto chuckit; | |
431 | } | |
432 | ||
433 | #ifdef IEEELLC | |
434 | if (type <= ETHERMTU) { | |
435 | /* may need ether_header for XID, TEST LLC functions */ | |
436 | ehbuf = *eh; | |
437 | } | |
438 | #endif IEEELLC | |
439 | ||
440 | /* | |
441 | * pull packet off interface. if off is non-zero, the | |
442 | * packet has a trailing "header". unget will move this | |
443 | * header to the front, but we still have to remove the | |
444 | * type and length fields from the front of the data. | |
445 | */ | |
446 | m = unget(addr, (char *) eh, len, off, &us->us_if); | |
447 | /* | |
448 | * update the full page pointer and clear the packet available | |
449 | * flag if necessary. update the fpp here to free the on-board | |
450 | * receive pages as soon as possible. | |
451 | */ | |
452 | unupdatefpp(addr, us->us_nextpage); | |
453 | if (m != 0){ | |
454 | if (off){ | |
455 | #ifdef ISO | |
456 | /* | |
457 | * Move snpa header over by 4 bytes to skip | |
458 | * the trailer Type and Header length fields. | |
459 | */ | |
460 | struct snpa_hdr sh; | |
461 | ||
462 | bcopy(mtod(m, char *), (caddr_t)&sh, sizeof(struct snpa_hdr)); | |
463 | m->m_off += 2 * sizeof(u_short); | |
464 | m->m_len -= 2 * sizeof(u_short); | |
465 | bcopy((caddr_t)&sh, mtod(m, char *), sizeof(struct snpa_hdr)); | |
466 | #else ISO | |
467 | struct ifnet *ifp; | |
468 | /* | |
469 | * bcopy is used since word moves must be on 4 byte | |
470 | * boundaries on the RT PC | |
471 | */ | |
472 | bcopy(mtod(m, char *), (char *) &ifp, sizeof(ifp)); | |
473 | m->m_off += 2 * sizeof(u_short); | |
474 | m->m_len -= 2 * sizeof(u_short); | |
475 | bcopy((char *) &ifp, mtod(m, char *), sizeof(ifp)); | |
476 | #endif ISO | |
477 | } | |
478 | switch (type){ | |
479 | #ifdef INET | |
480 | case ETHERTYPE_IP: | |
481 | { | |
482 | int s; | |
483 | ||
484 | DEBUGF(undebug & 0x2, printf("ip packet\n");) | |
485 | schednetisr(NETISR_IP); | |
486 | s = splimp(); | |
487 | inq = &ipintrq; | |
488 | if (IF_QFULL(inq)){ | |
489 | DEBUGF(undebug & 0x2, printf(" qfull\n");) | |
490 | IF_DROP(inq); | |
491 | m_freem(m); | |
492 | } else { | |
493 | IF_ENQUEUE(inq, m); | |
494 | DEBUGF(undebug & 0x2, printf(" queued\n");) | |
495 | } | |
496 | splx(s); | |
497 | break; | |
498 | } | |
499 | ||
500 | case ETHERTYPE_ARP: | |
501 | DEBUGF(undebug & 0x2, printf("arp packet\n");) | |
502 | arpinput(&us->us_ac, m); /* arpinput frees m */ | |
503 | break; | |
504 | #endif INET | |
505 | #ifdef NS | |
506 | case ETHERTYPE_NS: | |
507 | DEBUGF(undebug & 0x2, printf("ns packet\n");) | |
508 | schednetisr(NETISR_NS); | |
509 | inq = &nsintrq; | |
510 | break; | |
511 | #endif NS | |
512 | #ifndef IEEELLC | |
513 | #ifdef ISO | |
514 | case ETHERTYPE_CLNP: /* should be CLNL */ | |
515 | DEBUGF(undebug & 0x2, printf("clnl packet\n");) | |
516 | ||
517 | /* IFF_EAVESDROP can not be turned off for Ethernet */ | |
518 | ||
519 | schednetisr(NETISR_CLNP); | |
520 | inq = &clnlintrq; | |
521 | if (IF_QFULL(inq)){ | |
522 | DEBUGF(undebug & 0x2, printf(" qfull\n");) | |
523 | IF_DROP(inq); | |
524 | m_freem(m); | |
525 | } else { | |
526 | IF_ENQUEUE(inq, m); | |
527 | DEBUGF(undebug & 0x2, printf(" queued\n");) | |
528 | } | |
529 | break; | |
530 | #endif ISO | |
531 | default: | |
532 | DEBUGF(undebug & 0x2, printf("unknown packet\n");) | |
533 | m_freem(m); | |
534 | break; | |
535 | #else | |
536 | default: { | |
537 | struct llc *l; | |
538 | caddr_t pkt_start; | |
539 | #ifdef ISO | |
540 | #define PREPENDED_SIZE sizeof(struct snpa_hdr) | |
541 | #else | |
542 | #define PREPENDED_SIZE sizeof(struct ifnet *) | |
543 | #endif ISO | |
544 | if (type > ETHERMTU) | |
545 | goto not802; | |
546 | ||
547 | /* | |
548 | * This assumes that the snpa header is in the same mbuf | |
549 | * as the llc header. Currently this is ok, but if | |
550 | * unget allocates a cluster, this will not be the case | |
551 | */ | |
552 | pkt_start = mtod(m, caddr_t); | |
553 | l = (struct llc *) (pkt_start + PREPENDED_SIZE); | |
554 | ||
555 | IFDEBUG(D_ETHER) | |
556 | printf("unrint: llc: length %d, control x%x:\n", type, | |
557 | l->llc_control); | |
558 | ENDDEBUG | |
559 | ||
560 | switch (l->llc_control) { | |
561 | case LLC_UI: | |
562 | /* LLC_UI_P forbidden in class 1 service */ | |
563 | #ifdef ISO | |
564 | if (l->llc_dsap == LLC_ISO_LSAP) { | |
565 | if ((IS_MULTICAST(ehbuf.ether_dhost)) && | |
566 | ((us->us_if.if_flags & IFF_EAVESDROP) == 0) && | |
567 | (!snpac_ownmulti(ehbuf.ether_dhost, 6))) { | |
568 | m_freem(m); | |
569 | return; | |
570 | } | |
571 | ||
572 | /* move struct snpa_header over the llc header */ | |
573 | clnp_ypocb(pkt_start, pkt_start + 3, | |
574 | PREPENDED_SIZE); | |
575 | m->m_off += 3; | |
576 | m->m_len -= 3; | |
577 | ||
578 | DEBUGF(undebug & 0x2, printf("clnp packet\n");) | |
579 | schednetisr(NETISR_CLNP); | |
580 | inq = &clnlintrq; | |
581 | if (IF_QFULL(inq)){ | |
582 | DEBUGF(undebug & 0x2, printf(" qfull\n");) | |
583 | IF_DROP(inq); | |
584 | m_freem(m); | |
585 | } else { | |
586 | IF_ENQUEUE(inq, m); | |
587 | DEBUGF(undebug & 0x2, printf(" queued\n");) | |
588 | } | |
589 | return; | |
590 | } else { | |
591 | IFDEBUG(D_ETHER) | |
592 | printf("unrint: unknown llc sap\n"); | |
593 | ENDDEBUG | |
594 | m_freem(m); | |
595 | return; | |
596 | } | |
597 | #endif ISO | |
598 | break; | |
599 | /* LLC_XID, LLC_XID_P, LLC_TEST, and LLC_TEST_P are untested */ | |
600 | case LLC_XID: | |
601 | case LLC_XID_P: /* control field is untouched for resp */ | |
602 | if(m->m_len < 6) | |
603 | goto not802; | |
604 | l->llc_fid = LLC_IEEE_basic_format; | |
605 | l->llc_class = LLC_CLASS1; | |
606 | l->llc_window = 0; | |
607 | l->llc_dsap = l->llc_ssap = 0; | |
608 | /* FALL THROUGH */ | |
609 | case LLC_TEST: | |
610 | case LLC_TEST_P: { | |
611 | struct ifnet *ifp = &us->us_if; | |
612 | struct sockaddr_iso siso; | |
613 | u_char c = l->llc_dsap; | |
614 | l->llc_dsap = l->llc_ssap; | |
615 | l->llc_ssap = c; | |
616 | ||
617 | /* Do not TEST or XID to multicasts */ | |
618 | if (IS_MULTICAST(ehbuf.ether_dhost)) { | |
619 | m_freem(m); | |
620 | break; | |
621 | } | |
622 | ||
623 | siso.siso_family = AF_ISO; | |
624 | bcopy(ehbuf.ether_shost, siso.siso_addr.sna_idi, 6); | |
625 | siso.siso_addr.isoa_afi = AFI_SNA; | |
626 | siso.siso_addr.isoa_len = 7; | |
627 | ||
628 | /* trim off prepended snpa_hdr or ifp */ | |
629 | m->m_off += PREPENDED_SIZE; | |
630 | m->m_len -= PREPENDED_SIZE; | |
631 | ||
632 | unoutput(ifp, m, &siso); | |
633 | return; | |
634 | } | |
635 | not802: | |
636 | default: | |
637 | DEBUGF(undebug & 0x2, printf("unknown packet\n");) | |
638 | m_freem(m); | |
639 | break; | |
640 | } | |
641 | } | |
642 | #endif IEEELLC | |
643 | } | |
644 | } | |
645 | return; | |
646 | chuckit: | |
647 | DEBUGF(undebug, printf("unrint: packet dropped\n");) | |
648 | unupdatefpp(addr, us->us_nextpage); | |
649 | } | |
650 | ||
651 | /* | |
652 | * unxint - interrupt handler for transmit ready | |
653 | */ | |
654 | unxint(unit, us, addr) | |
655 | register int unit; | |
656 | register struct un_softc *us; | |
657 | register struct undevice *addr; | |
658 | { | |
659 | register char status; | |
660 | register int next_buf; | |
661 | ||
662 | /* | |
663 | * collect stats on last packet | |
664 | */ | |
665 | status = MM_IN(&addr->un_edlc.xstat); | |
666 | MM_OUT(&addr->un_edlc.xstat, status); /* clear status bits */ | |
667 | DEBUGF(undebug & 0x2, printf(" unxint: xstat = %b\n", | |
668 | status & 0xff, XS_BITS);) | |
669 | if (status & XS_16CL){ | |
670 | us->us_if.if_collisions += 16; | |
671 | us->us_if.if_oerrors++; | |
672 | printf("un%d: ethernet jammed\n", unit); | |
673 | } | |
674 | else if (status & XS_SHRT){ | |
675 | us->us_if.if_oerrors++; | |
676 | printf( "un%d: ethernet not responding (is it connected?)\n", | |
677 | unit); | |
678 | } | |
679 | else { | |
680 | us->us_if.if_opackets++; | |
681 | us->us_if.if_collisions += UN_NCOLL(addr); | |
682 | } | |
683 | DEBUGF(undebug & 0x2, | |
684 | printf(" ipkt = %d ierr = %d okt = %d oerr = %d coll = %d\n", | |
685 | us->us_if.if_ipackets, us->us_if.if_ierrors, | |
686 | us->us_if.if_opackets, us->us_if.if_oerrors, | |
687 | us->us_if.if_collisions);) | |
688 | /* mark the current transmit buffer empty */ | |
689 | us->us_xfull[us->us_xbuf] = 0; | |
690 | /* switch to the other transmit buffer */ | |
691 | next_buf = 1 - us->us_xbuf; | |
692 | if (us->us_xfull[next_buf]){ /* if it's full */ | |
693 | unstart(us, addr, next_buf); /* start output from it */ | |
694 | if (us->us_if.if_snd.ifq_head){ /* if more on out queue */ | |
695 | struct mbuf *m; | |
696 | ||
697 | IF_DEQUEUE(&us->us_if.if_snd, m); /* fill empty buf */ | |
698 | unput(us, addr, m, 1 - next_buf); | |
699 | } | |
700 | } | |
701 | else { /* the other transmit buffer is empty */ | |
702 | us->us_oactive = 0; | |
703 | MM_OUT(&addr->un_csr, UN_PAVIENB); /* Turn off TxRIENB */ | |
704 | } | |
705 | } | |
706 | ||
707 | /* | |
708 | * unoutput - ethernet output routine. encapsulate a packet of type | |
709 | * family for the local net. use trailer local net encapsulation if | |
710 | * the number of bytes in the mbufs after the first is a multiple of | |
711 | * 512. | |
712 | */ | |
713 | unoutput(ifp, m0, dst) | |
714 | register struct ifnet *ifp; | |
715 | register struct mbuf *m0; | |
716 | register struct sockaddr *dst; | |
717 | { | |
718 | u_short type; | |
719 | int s; | |
720 | int error; | |
721 | char edst[ETH_ADDR_SIZE]; | |
722 | struct in_addr idst; | |
723 | register struct un_softc *us = &un_softc[ifp->if_unit]; | |
724 | register struct mbuf *m = m0; | |
725 | register struct ether_header *eh; | |
726 | int off; | |
727 | struct mbuf *m_get(); | |
728 | int usetrailers; | |
729 | ||
730 | if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)){ | |
731 | error = ENETDOWN; | |
732 | goto bad; | |
733 | } | |
734 | switch (dst->sa_family){ | |
735 | ||
736 | #ifdef INET | |
737 | case AF_INET: | |
738 | idst = ((struct sockaddr_in *)dst)->sin_addr; | |
739 | if (!arpresolve(&us->us_ac, m, &idst, edst, &usetrailers)){ | |
740 | /* not resolved */ | |
741 | return(0); | |
742 | } | |
743 | off = ntohs((u_short)mtod(m, struct ip *)->ip_len) - m->m_len; | |
744 | if (usetrailers && off > 0 && (off & 0x1ff) == 0 && | |
745 | m->m_off >= MMINOFF + 2 * sizeof(u_short)){ | |
746 | type = ETHERTYPE_TRAIL + (off>>9); | |
747 | m->m_off -= 2 * sizeof(u_short); | |
748 | m->m_len += 2 * sizeof(u_short); | |
749 | *mtod(m, u_short *) = htons((u_short)ETHERTYPE_IP); | |
750 | *(mtod(m, u_short *) + 1) = htons((u_short)m->m_len); | |
751 | /* | |
752 | * Packet to be sent with trailer, move first packet | |
753 | * (control information) to end of chain. | |
754 | */ | |
755 | while (m->m_next) | |
756 | m = m->m_next; | |
757 | m->m_next = m0; | |
758 | m = m0->m_next; | |
759 | m0->m_next = 0; | |
760 | m0 = m; | |
761 | } | |
762 | else { | |
763 | type = ETHERTYPE_IP; | |
764 | } | |
765 | break; | |
766 | #endif INET | |
767 | #ifdef NS | |
768 | case AF_NS: | |
769 | bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), | |
770 | (caddr_t)edst, sizeof(edst)); | |
771 | type = ETHERTYPE_NS; | |
772 | off = 0; | |
773 | break; | |
774 | #endif NS | |
775 | #ifdef ISO | |
776 | case AF_ISO: { | |
777 | int ret; | |
778 | int len; | |
779 | struct iso_addr *dst_nsap = &((struct sockaddr_iso *)dst)->siso_addr; | |
780 | ||
781 | if ((ret = iso_tryloopback(m, dst)) >= 0) | |
782 | return (ret); | |
783 | else if (ret = iso_snparesolve(&us->us_ac.ac_if, dst_nsap, edst, &len)){ | |
784 | /* not resolved */ | |
785 | IFDEBUG(D_ETHER) | |
786 | printf("unoutput: clnp packet dropped\n"); | |
787 | ENDDEBUG | |
788 | m_freem(m); | |
789 | return(ret); | |
790 | } else if (len != 6) { | |
791 | printf("unoutput: snpa len is not 6 (%d)\n", len); | |
792 | m_freem(m); | |
793 | return(ENETUNREACH); | |
794 | } | |
795 | ||
796 | #ifndef IEEELLC | |
797 | type = ETHERTYPE_CLNP; | |
798 | #else | |
799 | /* check for enough space for LLC header */ | |
800 | { | |
801 | struct mbuf *llcm; | |
802 | char *cp; | |
803 | if (m->m_off >= MMAXOFF || m->m_off < MMINOFF + 3) { | |
804 | MGET(llcm, M_DONTWAIT, MT_DATA); | |
805 | if (llcm == NULL) { | |
806 | m_freem(m); | |
807 | return(0); | |
808 | } | |
809 | llcm->m_off = MMAXOFF - 3; | |
810 | llcm->m_len = 3; | |
811 | llcm->m_next = m; | |
812 | m = llcm; | |
813 | } else { | |
814 | m->m_off -= 3; | |
815 | m->m_len += 3; | |
816 | } | |
817 | type = m_datalen(m); | |
818 | ||
819 | cp = mtod(m, u_char *); | |
820 | cp[0] = cp[1] = LLC_ISO_LSAP; cp[2] = LLC_UI; | |
821 | off = 0; | |
822 | } | |
823 | #endif IEEELLC | |
824 | off = 0; | |
825 | IFDEBUG(D_ETHER) | |
826 | int i; | |
827 | printf("unoutput: sending pkt to: "); | |
828 | for (i=0; i<6; i++) | |
829 | printf("%x ", edst[i] & 0xff); | |
830 | #ifdef IEEELLC | |
831 | printf(" llc len %d", type); | |
832 | #endif IEEELLC | |
833 | printf("\n"); | |
834 | ENDDEBUG | |
835 | } break; | |
836 | #endif ISO | |
837 | case AF_UNSPEC: | |
838 | eh = (struct ether_header *)dst->sa_data; | |
839 | bcopy((char *)eh->ether_dhost, (caddr_t)edst, sizeof(edst)); | |
840 | type = eh->ether_type; | |
841 | break; | |
842 | default: | |
843 | printf("un%d: can't handle af%d\n", ifp->if_unit, | |
844 | dst->sa_family); | |
845 | error = EAFNOSUPPORT; | |
846 | goto bad; | |
847 | } | |
848 | /* | |
849 | * Add local net header. If no space in first mbuf, | |
850 | * allocate another. | |
851 | */ | |
852 | if (m->m_off > MMAXOFF || | |
853 | MMINOFF + sizeof(struct ether_header) > m->m_off){ | |
854 | m = m_get(M_DONTWAIT, MT_HEADER); | |
855 | /* | |
856 | * Note: m_get, m_freem etc. guard against concurrent | |
857 | * updates to the list of free mbufs. | |
858 | */ | |
859 | if (m == 0){ | |
860 | error = ENOBUFS; | |
861 | goto bad; | |
862 | } | |
863 | m->m_next = m0; | |
864 | m->m_off = MMINOFF; | |
865 | m->m_len = sizeof(struct ether_header); | |
866 | } else { | |
867 | m->m_off -= sizeof(struct ether_header); | |
868 | m->m_len += sizeof(struct ether_header); | |
869 | } | |
870 | eh = mtod(m, struct ether_header *); | |
871 | bcopy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof(edst)); | |
872 | bcopy((caddr_t)us->us_addr, (caddr_t)eh->ether_shost, | |
873 | sizeof(eh->ether_shost)); | |
874 | bcopy((caddr_t)&type, (caddr_t)&eh->ether_type, sizeof(u_short)); | |
875 | ||
876 | /* | |
877 | * queue packet for transmission. if there is an empty | |
878 | * transmit buffer on the adapter, use it. | |
879 | */ | |
880 | s = splimp(); | |
881 | if (IF_QFULL(&ifp->if_snd)){ | |
882 | IF_DROP(&ifp->if_snd); | |
883 | error = ENOBUFS; | |
884 | goto qfull; | |
885 | } | |
886 | if (us->us_xfull[0] == 0 || us->us_xfull[1] == 0){ /* empty xmt buf */ | |
887 | struct undevice *addr = (struct undevice *) | |
888 | uninfo[ifp->if_unit]->iod_addr; | |
889 | int next_buf; | |
890 | #ifdef ATR | |
891 | int old_window; | |
892 | move_window(old_window, addr); | |
893 | #endif ATR | |
894 | if (us->us_xfull[0] == 0){ | |
895 | next_buf = 0; | |
896 | } | |
897 | else { | |
898 | next_buf = 1; | |
899 | } | |
900 | unput(us, addr, m, next_buf); | |
901 | if (us->us_oactive == 0){ | |
902 | unstart(us, addr, next_buf); | |
903 | } | |
904 | #ifdef ATR | |
905 | restore_window(old_window); | |
906 | #endif ATR | |
907 | } | |
908 | else { | |
909 | IF_ENQUEUE(&ifp->if_snd, m); | |
910 | } | |
911 | splx(s); | |
912 | return(0); | |
913 | qfull: | |
914 | m0 = m; | |
915 | splx(s); | |
916 | bad: | |
917 | m_freem(m0); | |
918 | return(error); | |
919 | } | |
920 | ||
921 | /* | |
922 | * unput - copy packet from an mbuf chain to one of the adapter's | |
923 | * transmit buffers. the packet is extended to the minimum legal | |
924 | * size if necessary. the extra bytes could be zeroed out to improve | |
925 | * security but are not to maximize performance. | |
926 | */ | |
927 | unput(us, addr, m, xbuf) | |
928 | struct un_softc *us; | |
929 | struct undevice *addr; | |
930 | register struct mbuf *m; | |
931 | register int xbuf; | |
932 | { | |
933 | register unsigned off; | |
934 | register struct mbuf *mp; | |
935 | register char *bp; | |
936 | ||
937 | /* | |
938 | * compute starting address in transmit buffer. packets must be | |
939 | * "end_aligned". | |
940 | */ | |
941 | for (off = UN_XBSIZE, mp = m; mp; mp = mp->m_next){ | |
942 | off -= mp->m_len; | |
943 | } | |
944 | if (UN_XBSIZE - off < ETHERMIN + sizeof(struct ether_header)){ | |
945 | /* packet too short => extend it */ | |
946 | off = UN_XBSIZE - ETHERMIN - sizeof(struct ether_header); | |
947 | } | |
948 | if (xbuf == 1){ /* use the second buffer */ | |
949 | off += UN_XBSIZE; /* the 2 buffers are adjacent */ | |
950 | } | |
951 | bp = ((char *)(addr->un_xmtbuf)) + off; | |
952 | for (mp = m; mp; mp = mp->m_next){ | |
953 | register unsigned len = mp->m_len; | |
954 | ||
955 | bcopyout(mtod(mp, char *), bp, len); | |
956 | bp += len; | |
957 | } | |
958 | /* save starting address so interrupt handler can find it */ | |
959 | us->us_xstart[xbuf] = off; /* start address to be passed to adapter */ | |
960 | us->us_xfull[xbuf] = 1; /* mark buffer full */ | |
961 | m_freem(m); | |
962 | } | |
963 | ||
964 | /* | |
965 | * unget - copy packet from adapter's receive buffers into a chain of mbufs | |
966 | * | |
967 | */ | |
968 | struct mbuf * | |
969 | unget(addr, unbuf, totlen, off0, ifp) | |
970 | struct undevice *addr; | |
971 | char *unbuf; | |
972 | register int totlen; | |
973 | int off0; | |
974 | struct ifnet *ifp; | |
975 | { | |
976 | register struct mbuf *m; | |
977 | struct mbuf *top = 0; | |
978 | register struct mbuf **mp = ⊤ | |
979 | register int off = off0; | |
980 | register int len; | |
981 | register char *cp; | |
982 | #ifdef ISO | |
983 | int copied_snpa = 0; | |
984 | #endif ISO | |
985 | ||
986 | cp = unbuf + sizeof(struct ether_header); | |
987 | while (totlen > 0){ | |
988 | char *mcp; | |
989 | ||
990 | MGET(m, M_DONTWAIT, MT_DATA); | |
991 | if (m == 0) | |
992 | goto bad; | |
993 | if (off){ /* trailer exists */ | |
994 | len = totlen - off; | |
995 | cp = unbuf + sizeof(struct ether_header) + off; | |
996 | } else | |
997 | len = totlen; | |
998 | #ifdef ISO | |
999 | if (!copied_snpa) | |
1000 | len += sizeof(struct snpa_hdr); | |
1001 | #else ISO | |
1002 | if (ifp) | |
1003 | len += sizeof(ifp); | |
1004 | #endif ISO | |
1005 | if (len >= NBPG){ | |
1006 | MCLGET(m); | |
1007 | if (m->m_len == CLBYTES) | |
1008 | m->m_len = len = MIN(len, CLBYTES); | |
1009 | else | |
1010 | m->m_len = len = MIN(MLEN, len); | |
1011 | } else { | |
1012 | m->m_len = len = MIN(MLEN, len); | |
1013 | m->m_off = MMINOFF; | |
1014 | } | |
1015 | mcp = mtod(m, char *); | |
1016 | #ifdef ISO | |
1017 | if (!copied_snpa) { | |
1018 | /* | |
1019 | * Prepend snpa_hdr to first mbuf | |
1020 | * The hardcoded 12 below refers to the length of the dhost | |
1021 | * and shost fields. We recklessly assume | |
1022 | * the order of dhost,shost in the snpa_hdr is the same | |
1023 | * as the order in the ether_header. | |
1024 | */ | |
1025 | struct snpa_hdr *sh = (struct snpa_hdr *)mcp; | |
1026 | struct ether_header *eh = (struct ether_header *)unbuf; | |
1027 | ||
1028 | bcopy((char *) &ifp, (caddr_t)&sh->snh_ifp, sizeof(ifp)); | |
1029 | bcopy((caddr_t)eh, (caddr_t)sh->snh_dhost, 12); | |
1030 | mcp += sizeof(struct snpa_hdr); | |
1031 | len -= sizeof(struct snpa_hdr); | |
1032 | copied_snpa = 1; | |
1033 | } | |
1034 | #else ISO | |
1035 | if (ifp){ | |
1036 | /* prepend ifp to first mbuf */ | |
1037 | /* | |
1038 | * bcopy is used since since word moves must | |
1039 | * be on 4 byte boundaries on the RT PC | |
1040 | */ | |
1041 | bcopy((char *) &ifp, mcp, sizeof(ifp)); | |
1042 | mcp += sizeof(ifp); | |
1043 | len -= sizeof(ifp); | |
1044 | ifp = (struct ifnet *) 0; | |
1045 | } | |
1046 | #endif ISO | |
1047 | unbcopy(addr, cp, mcp, len); | |
1048 | cp += len; | |
1049 | *mp = m; | |
1050 | mp = &m->m_next; | |
1051 | if (off == 0){ | |
1052 | totlen -= len; | |
1053 | continue; | |
1054 | } | |
1055 | off += len; | |
1056 | if (off == totlen){ | |
1057 | cp = unbuf + sizeof(struct ether_header); | |
1058 | off = 0; | |
1059 | totlen = off0; | |
1060 | } | |
1061 | } | |
1062 | return(top); | |
1063 | bad: | |
1064 | m_freem(top); | |
1065 | return(0); | |
1066 | } | |
1067 | ||
1068 | ||
1069 | /* | |
1070 | * ioctl - process an ioctl request. | |
1071 | */ | |
1072 | unioctl(ifp, cmd, data) | |
1073 | register struct ifnet *ifp; | |
1074 | register int cmd; | |
1075 | register caddr_t data; | |
1076 | { | |
1077 | register struct ifaddr *ifa = (struct ifaddr *)data; | |
1078 | register int s = splimp(); | |
1079 | register int error = 0; | |
1080 | ||
1081 | switch (cmd){ | |
1082 | case SIOCSIFADDR: | |
1083 | ifp->if_flags |= IFF_UP; | |
1084 | ||
1085 | switch (ifa->ifa_addr.sa_family){ | |
1086 | #ifdef INET | |
1087 | case AF_INET: | |
1088 | uninit(ifp->if_unit); /* before arpwhohas */ | |
1089 | ((struct arpcom *) ifp)->ac_ipaddr = | |
1090 | IA_SIN(ifa)->sin_addr; | |
1091 | arpwhohas((struct arpcom *)ifp, &IA_SIN(ifa)->sin_addr); | |
1092 | break; | |
1093 | #endif INET | |
1094 | #ifdef NS | |
1095 | case AF_NS: | |
1096 | { | |
1097 | struct ns_addr *ina = &(IA_SNS(ifa)->sns_addr); | |
1098 | struct un_softc *us = &un_softc[ifp->if_unit]; | |
1099 | ||
1100 | if (ns_nullhost(*ina)) | |
1101 | ina->x_host = *(union ns_host *)(us->us_addr); | |
1102 | else { | |
1103 | ifp->if_flags &= ~IFF_RUNNING; | |
1104 | bcopy((caddr_t) ina->x_host.c_host, | |
1105 | (caddr_t) us->us_addr, sizeof(us->us_addr)); | |
1106 | /* | |
1107 | * the uninit will set the hardware address | |
1108 | * since the IFF_RUNNING flag is off | |
1109 | */ | |
1110 | } | |
1111 | uninit(ifp->if_unit); | |
1112 | break; | |
1113 | } | |
1114 | #endif NS | |
1115 | default: | |
1116 | uninit(ifp->if_unit); | |
1117 | break; | |
1118 | } | |
1119 | break; | |
1120 | case SIOCSIFFLAGS: | |
1121 | if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & | |
1122 | IFF_RUNNING){ | |
1123 | #ifdef ATR | |
1124 | int old_window; | |
1125 | #endif ATR | |
1126 | struct undevice *addr; | |
1127 | ||
1128 | addr = (struct undevice *) uninfo[ifp->if_unit]-> | |
1129 | iod_addr; | |
1130 | #ifdef ATR | |
1131 | move_window(old_window, addr); | |
1132 | #endif ATR | |
1133 | (void) unzap((struct undevice *) addr); | |
1134 | ifp->if_flags &= ~IFF_RUNNING; | |
1135 | #ifdef ATR | |
1136 | restore_window(old_window); | |
1137 | #endif ATR | |
1138 | } else if (ifp->if_flags & IFF_UP && (ifp->if_flags & | |
1139 | IFF_RUNNING) == 0) | |
1140 | uninit(ifp->if_unit); | |
1141 | break; | |
1142 | default: | |
1143 | error = EINVAL; | |
1144 | } | |
1145 | splx(s); | |
1146 | return(error); | |
1147 | } | |
1148 | ||
1149 | /* | |
1150 | * unzap - initialize adapter but don't enable it. | |
1151 | * returns page number of next receive page to be used. | |
1152 | */ | |
1153 | unzap(addr) | |
1154 | register struct undevice *addr; | |
1155 | { | |
1156 | register int next; | |
1157 | ||
1158 | MM_OUT(&addr->un_csr, 0); /* disable interrupts */ | |
1159 | MM_OUT(&addr->un_edlc.reset, RESET_ON); | |
1160 | /* set reset bit while init'ing */ | |
1161 | MM_OUT(&addr->un_edlc.rstat, RS_CLEAR); | |
1162 | MM_OUT(&addr->un_edlc.xstat, XS_CLEAR); | |
1163 | MM_OUT(&addr->un_edlc.rmask, 0); | |
1164 | MM_OUT(&addr->un_edlc.xmask, 0); | |
1165 | MM_OUT(&addr->un_edlc.rmode, RM_NORMAL); | |
1166 | /* | |
1167 | * the next line puts the transmitter in loopback mode so | |
1168 | * that a spurious packet is not sent when the reset bit is | |
1169 | * cleared. | |
1170 | */ | |
1171 | MM_OUT(&addr->un_edlc.tmode, TM_NORMAL - TM_LBC); | |
1172 | MM_OUT(&addr->un_edlc.reset, RESET_OFF); /* clear reset bit */ | |
1173 | /* | |
1174 | * clear the receive buffers. assign the value in the empty | |
1175 | * page pointer to the full page pointer and clear the packet | |
1176 | * available flag. | |
1177 | */ | |
1178 | next = MM_IN(&addr->un_fppepp) & UN_PAGE_MASK; | |
1179 | /* clears the IKSYDK flag */ | |
1180 | MM_OUT(&addr->un_fppepp, next); /* fpp = epp */ | |
1181 | UN_CLRPAV(addr); /* clear the PAV flag */ | |
1182 | MM_OUT(&addr->un_edlc.tmode, TM_NORMAL); | |
1183 | /* put transmitter in normal mode */ | |
1184 | DEBUGF(undebug & 0x2, printf("unzap: zzzzapped!\n");) | |
1185 | return(next); | |
1186 | } | |
1187 | ||
1188 | /* | |
1189 | * unupdatefpp - update adapter's full page pointer and clear packet available | |
1190 | * flag if appropriate | |
1191 | */ | |
1192 | unupdatefpp(addr, nextpage) | |
1193 | register struct undevice *addr; | |
1194 | register int nextpage; | |
1195 | { | |
1196 | if (nextpage == /* EPP */ (MM_IN(&addr->un_fppepp) & UN_PAGE_MASK)) | |
1197 | UN_CLRPAV(addr); | |
1198 | MM_OUT(&addr->un_fppepp, nextpage); /* set FPP */ | |
1199 | } | |
1200 | ||
1201 | /* | |
1202 | * unbcopy - similar to bcopy but can deal with packets that wrap | |
1203 | * around from the high end of the adapter's receive buffer to the | |
1204 | * low end | |
1205 | */ | |
1206 | unbcopy(addr, from, to, len) | |
1207 | register struct undevice *addr; | |
1208 | register char *from; | |
1209 | register char *to; | |
1210 | register int len; | |
1211 | { | |
1212 | register char *high_end = &addr->un_rcvbuf[UN_LASTRBUF][UN_RBUFSIZE]; | |
1213 | register int n; | |
1214 | ||
1215 | if (from + len <= high_end){ | |
1216 | bcopyin(from, to, len); | |
1217 | } | |
1218 | else if (from >= high_end){ | |
1219 | from -= sizeof(addr->un_rcvbuf); | |
1220 | bcopyin(from, to, len); | |
1221 | } else { | |
1222 | n = high_end - from; | |
1223 | bcopyin(from, to, n); | |
1224 | to += n; | |
1225 | bcopyin((char *)addr->un_rcvbuf, to, len - n); | |
1226 | } | |
1227 | } | |
1228 | ||
1229 | /* | |
1230 | * ungetushortatoff - return the u_short at offset in the received packet, | |
1231 | * handling wrap-around in the receive buffer and conversion between network | |
1232 | * and host formats as necessary. | |
1233 | */ | |
1234 | u_short ungetushortatoff(addr, eh, off) | |
1235 | register struct undevice *addr; | |
1236 | register struct ether_header *eh; | |
1237 | register int off; | |
1238 | { | |
1239 | register char *high_end = &addr->un_rcvbuf[UN_LASTRBUF][UN_RBUFSIZE]; | |
1240 | register char *p; | |
1241 | ||
1242 | p = (caddr_t)(eh + 1) + off; | |
1243 | if (p >= high_end){ | |
1244 | p -= sizeof(addr->un_rcvbuf); | |
1245 | } | |
1246 | return(ntohs((u_short) MM_INW(p))); | |
1247 | } | |
1248 | ||
1249 | /* | |
1250 | * unprintethaddr - print an ethernet address | |
1251 | */ | |
1252 | unprintethaddr(p) | |
1253 | register char *p; | |
1254 | { | |
1255 | register int i; | |
1256 | ||
1257 | for (i = 0; i < ETH_ADDR_SIZE; i++){ | |
1258 | if (i != 0) printf(":"); | |
1259 | printf("%x", *p++); | |
1260 | } | |
1261 | } | |
1262 | ||
1263 | #endif NUN > 0 |