Commit | Line | Data |
---|---|---|
109874b6 KS |
1 | /*********************************************************** |
2 | Copyright IBM Corporation 1987 | |
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, IN NO EVENT SHALL | |
16 | IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
17 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
18 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
19 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
20 | SOFTWARE. | |
21 | ||
22 | ******************************************************************/ | |
23 | ||
24 | /* | |
25 | * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison | |
26 | */ | |
27 | /* | |
28 | * $Header: if_eon.c,v 1.4 88/07/19 15:53:59 hagens Exp $ | |
29 | * $Source: /usr/argo/sys/netiso/RCS/if_eon.c,v $ | |
30 | * | |
31 | * EON rfc | |
32 | * Layer between IP and CLNL | |
33 | * | |
34 | * TODO: | |
35 | * Put together a current rfc986 address format and get the right offset | |
36 | * for the nsel | |
37 | */ | |
38 | #define RFC986_NSEL_OFFSET 5 | |
39 | ||
40 | #ifndef lint | |
41 | static char *rcsid = "$Header: if_eon.c,v 1.4 88/07/19 15:53:59 hagens Exp $"; | |
42 | #endif lint | |
43 | ||
44 | #include "eon.h" | |
45 | #if NEON>0 | |
46 | ||
47 | #include "param.h" | |
48 | #include "systm.h" | |
49 | #include "types.h" | |
50 | #include "mbuf.h" | |
51 | #include "buf.h" | |
52 | #include "protosw.h" | |
53 | #include "socket.h" | |
54 | #include "ioctl.h" | |
55 | #include "errno.h" | |
56 | #include "types.h" | |
57 | ||
58 | #include "../machine/io.h" | |
59 | #include "../machineio/ioccvar.h" | |
60 | ||
61 | #include "../net/if.h" | |
62 | #include "../net/netisr.h" | |
63 | #include "../net/route.h" | |
64 | ||
65 | #include "../netinet/in.h" | |
66 | #include "../netinet/in_systm.h" | |
67 | #include "../netinet/ip.h" | |
68 | #include "../netinet/ip_var.h" | |
69 | #include "../netinet/if_ether.h" | |
70 | ||
71 | #include "../netiso/iso.h" | |
72 | #include "../netiso/argo_debug.h" | |
73 | #include "../netiso/iso_errno.h" | |
74 | #include "../netiso/eonvar.h" | |
75 | ||
76 | #define EOK 0 | |
77 | ||
78 | int eoninput(); | |
79 | int eonint(); | |
80 | int eonoutput(); | |
81 | int eonioctl(); | |
82 | int eonprobe(); | |
83 | int eonattach(); | |
84 | int eoninit(); | |
85 | extern int ip_output(); | |
86 | struct ifnet eonif[NEON]; | |
87 | ||
88 | #define EON_FAKE_CSR 0 | |
89 | int eon_fakeautoconf[2]; /* need at least 2 ints */ | |
90 | ||
91 | caddr_t eonstd[] = { (caddr_t) eon_fakeautoconf, 0 }; | |
92 | struct iocc_device *eoninfo[NEON]; | |
93 | ||
94 | struct iocc_driver eondriver = { | |
95 | eonprobe, /* idr_probe */ | |
96 | 0, /* idr_slave */ | |
97 | eonattach, /* idr_attach */ | |
98 | 0, /* idr_dgo */ | |
99 | eonstd, /* idr_addr - list of standard addresses for device */ | |
100 | "eon", /* idr_dname */ | |
101 | eoninfo, /* idr_dinfo - backptrs to iodinit structs */ | |
102 | 0, /* idr_mname - controller name */ | |
103 | 0, /* idr_minfo -- backptrs to iominit structs */ | |
104 | eonint, /* idr_intr - interrupt rtn */ | |
105 | 0, /* idr_csr - offset to read/write csr */ | |
106 | EON_FAKE_CSR, /* idr_chanrelse */ | |
107 | 0, /* idr_flags */ | |
108 | }; | |
109 | ||
110 | ||
111 | /* | |
112 | * entry in the EON address cache (list) | |
113 | * (or pt-pt links list, however you view it) | |
114 | */ | |
115 | ||
116 | struct eon_centry { | |
117 | struct qhdr eonc_q_LINK; | |
118 | #define eonc_nextLINK eonc_q_LINK.link | |
119 | #define eonc_prevLINK eonc_q_LINK.flink | |
120 | ||
121 | struct qhdr eonc_q_IS; | |
122 | #define eonc_nextIS eonc_q_IS.link | |
123 | #define eonc_prevIS eonc_q_IS.flink | |
124 | ||
125 | struct qhdr eonc_q_ES; | |
126 | #define eonc_nextES eonc_q_ES.link | |
127 | #define eonc_prevES eonc_q_ES.flink | |
128 | ||
129 | struct in_addr eonc_addr; | |
130 | u_short eonc_status; | |
131 | }; | |
132 | ||
133 | /* kinda like mtod() but for eon_centries */ | |
134 | #define qtocentry(q, off) ((struct eon_centry *) (((caddr_t)(q)) - off)) | |
135 | #define centrytoq(c, off) ((struct qhdr *) (((caddr_t)(c)) + off)) | |
136 | ||
137 | struct qhdr eon_LINK_hdr = { | |
138 | (struct qhdr *)0, | |
139 | (struct qhdr *)0, | |
140 | }; | |
141 | static struct qhdr eon_IS_hdr = { | |
142 | (struct qhdr *)0, | |
143 | (struct qhdr *)0, | |
144 | }; | |
145 | static struct qhdr eon_ES_hdr = { | |
146 | (struct qhdr *)0, | |
147 | (struct qhdr *)0, | |
148 | }; | |
149 | static struct qhdr eon_FREE_hdr = { | |
150 | (struct qhdr *)0, | |
151 | (struct qhdr *)0, | |
152 | }; | |
153 | ||
154 | #define INITQ(q) (q)->rlink = (q)->link = (q) | |
155 | ||
156 | /* | |
157 | * FUNCTION: eon_dumpcache | |
158 | * | |
159 | * PURPOSE: dump the cache beginning with the argument given | |
160 | * | |
161 | * RETURNS: 0 | |
162 | */ | |
163 | ||
164 | eon_dumpcache(which) | |
165 | int which; | |
166 | { | |
167 | register int off; | |
168 | register struct eon_centry *ent; | |
169 | struct qhdr *hdr; | |
170 | ||
171 | switch (which) { | |
172 | case E_FREE: | |
173 | printf("FREE LIST\n"); | |
174 | off = _offsetof( struct eon_centry, eonc_q_LINK); | |
175 | hdr = &eon_FREE_hdr; | |
176 | ent = qtocentry( hdr->link, | |
177 | _offsetof( struct eon_centry, eonc_q_LINK)); | |
178 | break; | |
179 | case E_ES: | |
180 | printf("ES LIST\n"); | |
181 | off = _offsetof( struct eon_centry, eonc_q_ES); | |
182 | hdr = &eon_ES_hdr; | |
183 | ent = qtocentry( hdr->link, | |
184 | _offsetof( struct eon_centry, eonc_q_ES)); | |
185 | break; | |
186 | case E_IS: | |
187 | printf("IS LIST\n"); | |
188 | off = _offsetof( struct eon_centry, eonc_q_IS); | |
189 | hdr = &eon_IS_hdr; | |
190 | ent = qtocentry( hdr->link, | |
191 | _offsetof( struct eon_centry, eonc_q_IS)); | |
192 | break; | |
193 | case E_LINK: | |
194 | printf("LINK LIST\n"); | |
195 | off = _offsetof( struct eon_centry, eonc_q_LINK); | |
196 | hdr = &eon_LINK_hdr; | |
197 | ent = qtocentry( hdr->link, | |
198 | _offsetof( struct eon_centry, eonc_q_LINK)); | |
199 | break; | |
200 | } | |
201 | if(hdr == centrytoq(ent, off)->link ) | |
202 | printf("EMPTY\n"); | |
203 | else while(1) { | |
204 | printf("0x%x: %d.%d.%d.%d, %s %s\n", ent, | |
205 | (ent->eonc_addr.s_addr>>24)&0xff, | |
206 | (ent->eonc_addr.s_addr>>16)&0xff, | |
207 | (ent->eonc_addr.s_addr>>8)&0xff, | |
208 | (ent->eonc_addr.s_addr)&0xff, | |
209 | ((ent->eonc_status & EON_ESLINK_UP)?"ES^": | |
210 | (ent->eonc_status & EON_ESLINK_DOWN)?"es*": " "), | |
211 | ((ent->eonc_status & EON_ISLINK_UP)?"IS^": | |
212 | (ent->eonc_status & EON_ISLINK_DOWN)?"is*": " ") | |
213 | ); | |
214 | dump_buf(ent, sizeof(struct eon_centry) ); | |
215 | ||
216 | { /* ent = ent.next: */ | |
217 | register struct qhdr *q; | |
218 | ||
219 | q = centrytoq(ent, off)->link; | |
220 | if( q == hdr) | |
221 | break; | |
222 | if( q == (struct qhdr *)0) /* panic */ { | |
223 | printf("eon0: BAD Q HDR or CENTRY! q 0x%x ent 0x%x off 0x%x\n", | |
224 | q, ent, off); | |
225 | break; | |
226 | } | |
227 | ent = qtocentry( q, off ); | |
228 | } | |
229 | } | |
230 | } | |
231 | /* | |
232 | * FUNCTION: eon_initcache | |
233 | * | |
234 | * PURPOSE: allocs a bunch of free cache entries | |
235 | * | |
236 | * RETURNS: 0 | |
237 | */ | |
238 | ||
239 | eon_initcache() | |
240 | { | |
241 | static struct eon_centry eoncache[EON_CACHESIZE]; | |
242 | register int i; | |
243 | register struct eon_centry *ent; | |
244 | ||
245 | bzero( eoncache, EON_CACHESIZE*sizeof(struct eon_centry)); | |
246 | INITQ( &eon_FREE_hdr ); | |
247 | INITQ( &eon_LINK_hdr ); | |
248 | INITQ( &eon_IS_hdr ); | |
249 | INITQ( &eon_ES_hdr ); | |
250 | ||
251 | ent = eoncache; | |
252 | ||
253 | for(i=0; i< EON_CACHESIZE; i++,ent++) { | |
254 | _insque( centrytoq(ent, _offsetof( struct eon_centry, eonc_q_LINK)), | |
255 | &eon_FREE_hdr); | |
256 | } | |
257 | printf("eon0: cache initialized\n"); | |
258 | } | |
259 | ||
260 | /* | |
261 | * FUNCTION: eonprobe | |
262 | * | |
263 | * PURPOSE: filler for device configuration | |
264 | * | |
265 | * RETURNS: PROBE_OK | |
266 | */ | |
267 | ||
268 | eonprobe() | |
269 | { | |
270 | extern int int_level, int_irq; | |
271 | ||
272 | printf("eonprobe() \n"); | |
273 | int_level = int_irq = 0x3; /* pick something - anything but -1 */ | |
274 | return PROBE_OK; | |
275 | } | |
276 | ||
277 | /* | |
278 | * FUNCTION: eonattach | |
279 | * | |
280 | * PURPOSE: autoconf attach routine | |
281 | * | |
282 | * RETURNS: void | |
283 | */ | |
284 | ||
285 | eonattach(iod) | |
286 | register struct iocc_device *iod; | |
287 | { | |
288 | register struct ifnet *ifp = &eonif[iod->iod_unit]; | |
289 | ||
290 | IFDEBUG(D_EON) | |
291 | printf("eonattach()\n"); | |
292 | ENDDEBUG | |
293 | ifp->if_unit = iod->iod_unit; | |
294 | ifp->if_name = "eon"; | |
295 | ifp->if_mtu = ETHERMTU; | |
296 | /* since everything will go out over ether or token ring */ | |
297 | ||
298 | ifp->if_init = eoninit; | |
299 | ifp->if_ioctl = eonioctl; /* needed? */ | |
300 | ifp->if_output = eonoutput; | |
301 | ifp->if_reset = 0; | |
302 | ifp->if_flags = IFF_BROADCAST; | |
303 | if_attach(ifp); | |
304 | ||
305 | IFDEBUG(D_EON) | |
306 | printf("eonattach()\n"); | |
307 | ENDDEBUG | |
308 | eon_initcache(); | |
309 | IFDEBUG(D_EON) | |
310 | printf("eon%d: attached\n", iod->iod_unit); | |
311 | ENDDEBUG | |
312 | } | |
313 | ||
314 | static struct eon_centry * | |
315 | find_oldent( ea ) | |
316 | struct sockaddr_eon *ea; | |
317 | { | |
318 | register int offset = | |
319 | _offsetof( struct eon_centry, eonc_q_LINK); | |
320 | register struct eon_centry *ent = qtocentry(eon_LINK_hdr.link, offset); | |
321 | ||
322 | IFDEBUG(D_EON) | |
323 | printf("eon: find_oldent() ipaddr: %d.%d.%d.%d\n", | |
324 | (ea->seon_ipaddr>>24)&0xff, | |
325 | (ea->seon_ipaddr>>16)&0xff, | |
326 | (ea->seon_ipaddr>>8)&0xff, | |
327 | (ea->seon_ipaddr)&0xff ); | |
328 | ENDDEBUG | |
329 | for (; ent; ent = qtocentry(ent->eonc_nextLINK, offset) ) { | |
330 | if( ent->eonc_addr.s_addr == ea->seon_ipaddr ) | |
331 | return ent; | |
332 | } | |
333 | return (struct eon_centry *)0; | |
334 | } | |
335 | ||
336 | /* | |
337 | * FUNCTION: eonioctl | |
338 | * | |
339 | * PURPOSE: io controls - ifconfig | |
340 | * need commands to | |
341 | * link-UP (core addr) (flags: ES, IS) | |
342 | * link-DOWN (core addr) (flags: ES, IS) | |
343 | * must be callable from kernel or user | |
344 | * | |
345 | * RETURNS: nothing | |
346 | */ | |
347 | eonioctl(ifp, cmd, data) | |
348 | register struct ifnet *ifp; | |
349 | register int cmd; | |
350 | register caddr_t data; | |
351 | { | |
352 | struct ifreq *ifr = (struct ifreq *)data; | |
353 | register struct sockaddr_eon *eoa = | |
354 | (struct sockaddr_eon *)&(ifr->ifr_addr); | |
355 | register int s = splimp(); | |
356 | register int error = 0; | |
357 | ||
358 | IFDEBUG(D_EON) | |
359 | printf("eonioctl (cmd 0x%x) \n", cmd); | |
360 | ENDDEBUG | |
361 | ||
362 | switch (cmd){ | |
363 | case SIOCSIFDSTADDR: { | |
364 | /* add pt-pt link to the set of core addrs */ | |
365 | register struct eon_centry *ent, *oldent; | |
366 | register u_short which; | |
367 | ||
368 | /* "which" tells which lists to put these guys in - don't | |
369 | * want to insert something in a list if it's already there | |
370 | */ | |
371 | #define LEGIT_EONADDR(a)\ | |
372 | ((a->seon_family == AF_ISO) && (a->seon_afi == 0x47) &&\ | |
373 | (a->seon_idi[0] == 0) && (a->seon_idi[1] == 6) \ | |
374 | ) | |
375 | #ifdef notdef | |
376 | /* GET THESE RIGHT AND ADD THEM */ | |
377 | && (a->seon_vers == 3) && (a->seon_adrlen == 0xa) | |
378 | #endif notdef | |
379 | ||
380 | if( ! LEGIT_EONADDR(eoa) ) { | |
381 | error = EADDRNOTAVAIL; | |
382 | break; | |
383 | } | |
384 | ||
385 | oldent = find_oldent( eoa ); | |
386 | IFDEBUG(D_EON) | |
387 | printf("eonioctl legit seon_status 0x%x oldent %s\n", | |
388 | eoa->seon_status, oldent?"found":"not found"); | |
389 | ENDDEBUG | |
390 | ||
391 | if( eoa->seon_status & UPBITS ) { | |
392 | if (!oldent) { | |
393 | /* doesn't exist - need to create one */ | |
394 | /* TODO : check for null free list */ | |
395 | ent = qtocentry(eon_FREE_hdr.link, | |
396 | _offsetof( struct eon_centry, eonc_q_LINK)); | |
397 | remque( &(ent->eonc_q_LINK) ); | |
398 | ent->eonc_addr.s_addr = eoa->seon_ipaddr; | |
399 | insque( &oldent->eonc_q_LINK, (&eon_LINK_hdr)); | |
400 | oldent = ent; | |
401 | } | |
402 | ||
403 | which = (eoa->seon_status ^ oldent->eonc_status) & | |
404 | eoa->seon_status & UPBITS; | |
405 | ||
406 | oldent->eonc_status |= (eoa->seon_status & UPBITS); | |
407 | ||
408 | if( which & EON_ESLINK_UP ) | |
409 | insque( &oldent->eonc_q_ES, (&eon_ES_hdr)); | |
410 | if( which & EON_ISLINK_UP ) | |
411 | insque( &oldent->eonc_q_IS, (&eon_IS_hdr)); | |
412 | } | |
413 | ||
414 | if( eoa->seon_status & DOWNBITS ) { | |
415 | if(!oldent) { | |
416 | return ENOENT; /* no such entry */ | |
417 | } | |
418 | which = (eoa->seon_status ^ oldent->eonc_status) & | |
419 | eoa->seon_status & DOWNBITS; | |
420 | ||
421 | oldent->eonc_status |= (eoa->seon_status & DOWNBITS); | |
422 | ||
423 | if( which & EON_ESLINK_DOWN ) | |
424 | remque( &(oldent->eonc_q_ES) ); | |
425 | if( which & EON_ISLINK_DOWN ) | |
426 | remque( &(oldent->eonc_q_IS) ); | |
427 | } | |
428 | ||
429 | IFDEBUG(D_EON) | |
430 | printf("at end status 0x%x\n", oldent->eonc_status); | |
431 | ENDDEBUG | |
432 | break; | |
433 | } | |
434 | ||
435 | case SIOCGIFDSTADDR: | |
436 | { | |
437 | register struct eon_centry *oldent; | |
438 | ||
439 | oldent = find_oldent( eoa ); | |
440 | if( oldent == (struct eon_centry *)0 ) | |
441 | error = EADDRNOTAVAIL; | |
442 | else | |
443 | eoa->seon_status = oldent->eonc_status; | |
444 | } | |
445 | break; | |
446 | ||
447 | case SIOCSIFADDR: | |
448 | ifp->if_flags |= IFF_UP; | |
449 | break; | |
450 | ||
451 | case SIOCSIFFLAGS: | |
452 | if ((ifp->if_flags & IFF_UP) == 0 && ifp->if_flags & | |
453 | IFF_RUNNING){ | |
454 | ifp->if_flags &= ~IFF_RUNNING; | |
455 | } else if (ifp->if_flags & IFF_UP && (ifp->if_flags & | |
456 | IFF_RUNNING) == 0) | |
457 | eoninit(ifp->if_unit); | |
458 | break; | |
459 | default: | |
460 | error = EINVAL; | |
461 | } | |
462 | splx(s); | |
463 | return(error); | |
464 | } | |
465 | ||
466 | /* | |
467 | * FUNCTION: eoninit | |
468 | * | |
469 | * PURPOSE: initialization | |
470 | * | |
471 | * RETURNS: nothing | |
472 | */ | |
473 | ||
474 | eoninit(unit) | |
475 | int unit; | |
476 | { | |
477 | printf("eoninit ecn%d\n", unit); | |
478 | } | |
479 | ||
480 | ||
481 | /* | |
482 | * FUNCTION: eonint | |
483 | * | |
484 | * PURPOSE: filler for device configuration | |
485 | * | |
486 | * RETURNS: nothing | |
487 | * | |
488 | * NOTES: *should* never get called - for debugging it's here | |
489 | */ | |
490 | ||
491 | eonint() | |
492 | { | |
493 | /* silent - so no more stray interrupt messages from the aed! yay | |
494 | printf("eonint() called - BOGUS INTERRUPT\n"); | |
495 | */ | |
496 | } | |
497 | ||
498 | ||
499 | /* | |
500 | * FUNCTION: eonoutput | |
501 | * | |
502 | * PURPOSE: prepend an eon header and hand to IP | |
503 | * ARGUMENTS: (ifp) is points to the ifnet structure for this unit/device | |
504 | * (m) is an mbuf *, *m is a CLNL packet | |
505 | * (dst) is a destination address - have to interp. as | |
506 | * multicast or broadcast or real address. | |
507 | * | |
508 | * RETURNS: unix error code | |
509 | * | |
510 | * NOTES: | |
511 | * | |
512 | */ | |
513 | eonoutput(ifp, morig, dst) | |
514 | register struct ifnet *ifp; | |
515 | register struct mbuf *morig; /* packet */ | |
516 | struct sockaddr_iso *dst; /* destination addr */ | |
517 | { | |
518 | int s; | |
519 | struct eon_hdr *eonhdr; | |
520 | struct ip *iphdr; | |
521 | struct mbuf *mh; | |
522 | int error = 0; | |
523 | register int datalen; | |
524 | caddr_t dstipaddrloc; | |
525 | int single=0; | |
526 | int qoffset=0; | |
527 | register struct eon_centry *ent; | |
528 | struct qhdr *q; | |
529 | ||
530 | IFDEBUG(D_EON) | |
531 | printf("eonoutput \n" ); | |
532 | ENDDEBUG | |
533 | ||
534 | if( dst->siso_family != AF_ISO ) | |
535 | return EINVAL; | |
536 | if( dst->siso_addr.isoa_afi != AFI_RFC986 ) | |
537 | return EINVAL; | |
538 | ||
539 | s = splnet(); | |
540 | ||
541 | /* Nsel tells what type of multicast address, if multicast */ | |
542 | switch( dst->siso_addr.rfc986_dsp[RFC986_NSEL_OFFSET]) { | |
543 | case EON_NORMAL_ADDR: | |
544 | IncStat(es_out_normal); | |
545 | dstipaddrloc = (caddr_t)&(dst->siso_addr.rfc986_dsp[1]); | |
546 | single = 1; | |
547 | break; | |
548 | ||
549 | case EON_BROADCAST: | |
550 | IncStat(es_out_broad); | |
551 | if( eon_LINK_hdr.link == (struct qhdr *)0 ) { | |
552 | error = EADDRNOTAVAIL; | |
553 | } else { | |
554 | qoffset = _offsetof( struct eon_centry, eonc_q_LINK); | |
555 | ent = qtocentry(eon_LINK_hdr.link, qoffset); | |
556 | dstipaddrloc = (caddr_t) &(ent->eonc_addr); | |
557 | } | |
558 | break; | |
559 | case EON_MULTICAST_ES: | |
560 | IncStat(es_out_multi_es); | |
561 | if( eon_ES_hdr.link == (struct qhdr *)0 ) { | |
562 | error = EADDRNOTAVAIL; | |
563 | } else { | |
564 | qoffset = _offsetof( struct eon_centry, eonc_q_ES); | |
565 | ent = qtocentry(eon_ES_hdr.link, qoffset); | |
566 | dstipaddrloc = (caddr_t) &(ent->eonc_addr); | |
567 | } | |
568 | break; | |
569 | case EON_MULTICAST_IS: | |
570 | IncStat(es_out_multi_is); | |
571 | if( eon_IS_hdr.link == (struct qhdr *)0 ) { | |
572 | error = EADDRNOTAVAIL; | |
573 | } else { | |
574 | qoffset = _offsetof( struct eon_centry, eonc_q_LINK); | |
575 | ent = qtocentry(eon_IS_hdr.link, qoffset); | |
576 | dstipaddrloc = (caddr_t) &(ent->eonc_addr); | |
577 | } | |
578 | break; | |
579 | default: | |
580 | printf("NSEL bad value; treated as EON_NORMAL_ADDR\n"); | |
581 | dst->siso_addr.rfc986_dsp[RFC986_NSEL_OFFSET] = EON_NORMAL_ADDR; | |
582 | single = 1; | |
583 | break; | |
584 | } | |
585 | if( error ) | |
586 | goto done; | |
587 | ||
588 | /* get data length -- needed later */ | |
589 | datalen = m_datalen( morig ); | |
590 | IFDEBUG(D_EON) | |
591 | printf("eonoutput : m_datalen returns %d\n", datalen); | |
592 | ENDDEBUG | |
593 | ||
594 | mh = m_getclr( M_DONTWAIT, MT_HEADER); | |
595 | if(mh == (struct mbuf *)0) { | |
596 | goto done; | |
597 | } | |
598 | ||
599 | /* put an eon_hdr in the buffer, prepended by an ip header */ | |
600 | mh->m_act = (struct mbuf *)0; | |
601 | mh->m_len = sizeof(struct eon_hdr); | |
602 | mh->m_off = MMAXOFF - sizeof(struct eon_hdr); | |
603 | mh->m_next = morig; | |
604 | eonhdr = mtod(mh, struct eon_hdr *); | |
605 | eonhdr->eonh_class = | |
606 | dst->siso_addr.rfc986_dsp[RFC986_NSEL_OFFSET]; | |
607 | eonhdr->eonh_vers = EON_VERSION; | |
608 | ||
609 | IFDEBUG(D_EON) | |
610 | printf("eonoutput : gen csum (0x%x, offset %d, datalen %d)\n", | |
611 | mh, _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); | |
612 | ENDDEBUG | |
613 | iso_gen_csum(mh, | |
614 | _offsetof(struct eon_hdr, eonh_csum), sizeof(struct eon_hdr)); | |
615 | ||
616 | mh->m_len += sizeof(struct ip); | |
617 | mh->m_off -= sizeof(struct ip); | |
618 | iphdr = mtod(mh, struct ip *); | |
619 | ||
620 | iphdr->ip_p = IPPROTO_EON; | |
621 | iphdr->ip_len = (sizeof(struct eon_hdr) + sizeof(struct ip) + datalen); | |
622 | iphdr->ip_ttl = MAXTTL; | |
623 | iphdr->ip_src.s_addr = INADDR_ANY; | |
624 | ||
625 | IFDEBUG(D_EON) | |
626 | printf("eonoutput : after gen csum: ip_len %d/0x%x\n", | |
627 | (sizeof(struct eon_hdr) + sizeof(struct ip) + datalen), | |
628 | (sizeof(struct eon_hdr) + sizeof(struct ip) + datalen) | |
629 | ); | |
630 | ENDDEBUG | |
631 | ||
632 | morig = mh; | |
633 | ||
634 | for(;;) { | |
635 | ||
636 | if( !single ) { | |
637 | /* make a copy to send */ | |
638 | IFDEBUG(D_EON) | |
639 | printf("eonoutput : m_copy (0x%x, 0, 0x%x)\n", | |
640 | morig, iphdr->ip_len); | |
641 | ENDDEBUG | |
642 | mh = m_copy(morig, 0, iphdr->ip_len); | |
643 | mh = m_pullup(mh, sizeof(struct ip)); | |
644 | iphdr = mtod(mh, struct ip *); | |
645 | } | |
646 | IFDEBUG(D_EON) | |
647 | printf("eonoutput : bcopy 0x%x to 0x%x length %d\n", | |
648 | dstipaddrloc, | |
649 | (caddr_t)&(iphdr->ip_dst.s_addr), | |
650 | sizeof(iphdr->ip_dst.s_addr)); | |
651 | ENDDEBUG | |
652 | bcopy( | |
653 | dstipaddrloc, | |
654 | (caddr_t)&(iphdr->ip_dst.s_addr), sizeof(iphdr->ip_dst.s_addr)); | |
655 | IFDEBUG(D_EON) | |
656 | printf("eonoutput : dst ip addr : %d.%d.%d.%d", | |
657 | (iphdr->ip_dst.s_addr>>24)&0xff, | |
658 | (iphdr->ip_dst.s_addr>>16)&0xff, | |
659 | (iphdr->ip_dst.s_addr>>8)&0xff, | |
660 | (iphdr->ip_dst.s_addr)&0xff ); | |
661 | ENDDEBUG | |
662 | ||
663 | IFDEBUG(D_EON) | |
664 | printf("eonoutput ip_output : eon header:\n"); | |
665 | dump_buf(eonhdr, sizeof(struct eon_hdr)); | |
666 | printf("ip header:\n"); | |
667 | dump_buf(iphdr, sizeof(struct ip)); | |
668 | ENDDEBUG | |
669 | ||
670 | IncStat(es_ipout); | |
671 | if( error = ip_output(mh, (struct mbuf *)0, (struct route *)0, 0) ) | |
672 | break; | |
673 | ||
674 | IFDEBUG(D_EON) | |
675 | printf("eonoutput ip_output returns 0x%x; single %d\n", | |
676 | error, single); | |
677 | ENDDEBUG | |
678 | ||
679 | if(single) | |
680 | break; | |
681 | ||
682 | q = centrytoq(ent, qoffset)->link; | |
683 | if( q == (struct qhdr *)0) | |
684 | break; | |
685 | ent = qtocentry( q, qoffset ); | |
686 | IFDEBUG(D_EON) | |
687 | printf("eonoutput : get next entry: 0x%x\n", ent); | |
688 | ENDDEBUG | |
689 | dstipaddrloc = (caddr_t) &(ent->eonc_addr); | |
690 | IFDEBUG(D_EON) | |
691 | printf("eonoutput : dump of eon_centry 0x%x:\n", ent ); | |
692 | dump_buf(ent, sizeof(struct eon_centry) ); | |
693 | ENDDEBUG | |
694 | } | |
695 | done: | |
696 | if( !single ) { | |
697 | IFDEBUG(D_EON) | |
698 | printf("eonoutput : freeing morig 0x%x\n", morig); | |
699 | ENDDEBUG | |
700 | m_freem(morig); | |
701 | } | |
702 | splx(s); | |
703 | return error; | |
704 | } | |
705 | ||
706 | eoninput(m, ifp) | |
707 | register struct mbuf *m; | |
708 | struct ifnet *ifp; /* real ifp */ | |
709 | { | |
710 | int s; | |
711 | register struct eon_hdr *eonhdr; | |
712 | register struct ip *iphdr; | |
713 | struct ifnet *eonifp; | |
714 | register int datalen; | |
715 | ||
716 | s = splnet(); | |
717 | ||
718 | eonifp = &eonif[0]; /* kludge - really want to give CLNP | |
719 | * the ifp for eon, not for the real device | |
720 | */ | |
721 | ||
722 | IFDEBUG(D_EON) | |
723 | printf("eoninput() 0x%x m_off 0x%x m_len 0x%x dequeued\n", | |
724 | m, m?m->m_off:0, m?m->m_len:0); | |
725 | ENDDEBUG | |
726 | ||
727 | if (m == 0) { | |
728 | goto drop; | |
729 | } | |
730 | m = m_pullup(m, (sizeof(struct eon_hdr)+sizeof(struct ip))); | |
731 | if (m == 0) { | |
732 | IncStat(es_badhdr); | |
733 | goto drop; | |
734 | } | |
735 | ||
736 | iphdr = mtod(m, struct ip *); | |
737 | ||
738 | /* do a few checks for debugging */ | |
739 | if( iphdr->ip_p != IPPROTO_EON ) { | |
740 | IncStat(es_badhdr); | |
741 | goto drop; | |
742 | } | |
743 | ||
744 | /* drop ip header from the mbuf */ | |
745 | m->m_len -= sizeof(struct ip); | |
746 | m->m_off += sizeof(struct ip); | |
747 | ||
748 | eonhdr = mtod(m, struct eon_hdr *); | |
749 | ||
750 | IFDEBUG(D_EON) | |
751 | printf("eoninput: eon header:\n"); | |
752 | dump_buf(eonhdr, sizeof(struct eon_hdr)); | |
753 | ENDDEBUG | |
754 | ||
755 | /* checks for debugging */ | |
756 | if( eonhdr->eonh_vers != EON_VERSION) { | |
757 | IncStat(es_badhdr); | |
758 | goto drop; | |
759 | } | |
760 | ||
761 | datalen = m_datalen( m ); | |
762 | if( iso_check_csum( m, sizeof(struct eon_hdr) ) != EOK ) { | |
763 | IncStat(es_badcsum); | |
764 | goto drop; | |
765 | } | |
766 | ||
767 | IFDEBUG(D_EON) | |
768 | printf("eoninput csum ok class 0x%x\n", eonhdr->eonh_class ); | |
769 | ENDDEBUG | |
770 | switch( eonhdr->eonh_class) { | |
771 | case EON_BROADCAST: | |
772 | IncStat(es_in_broad); | |
773 | break; | |
774 | case EON_NORMAL_ADDR: | |
775 | IncStat(es_in_normal); | |
776 | break; | |
777 | case EON_MULTICAST_ES: | |
778 | if( ( eonifp->if_flags & IFF_ES) == 0 ) | |
779 | goto drop; | |
780 | IncStat(es_in_multi_es); | |
781 | break; | |
782 | case EON_MULTICAST_IS: | |
783 | if( ( eonifp->if_flags & IFF_IS) == 0 ) | |
784 | goto drop; | |
785 | IncStat(es_in_multi_is); | |
786 | break; | |
787 | } | |
788 | eonifp->if_ipackets ++; | |
789 | ||
790 | /* drop eonhdr from the mbuf */ | |
791 | m->m_len -= sizeof(struct eon_hdr); | |
792 | m->m_off += sizeof(struct eon_hdr); | |
793 | ||
794 | { | |
795 | /* put it on the CLNP queue and set soft interrupt */ | |
796 | struct ifqueue *ifq; | |
797 | extern struct ifqueue clnlintrq; | |
798 | int len; | |
799 | ||
800 | /* when acting as a subnet service, have to prepend a | |
801 | * pointer to the ifnet before handing this to clnp (GAG) | |
802 | */ | |
803 | len = sizeof(struct snpa_hdr); | |
804 | if( ( m->m_off > MMINOFF + len) && | |
805 | ( m->m_off <= MMAXOFF )) { | |
806 | m->m_off -= len; | |
807 | m->m_len += len; | |
808 | } | |
809 | ( mtod(m, struct snpa_hdr *) )->snh_ifp = eonifp; /* KLUDGE */ | |
810 | ||
811 | /* this is cutting it close */ | |
812 | bcopy( &iphdr->ip_src, ( mtod(m, struct snpa_hdr *))->snh_shost, | |
813 | sizeof(struct in_addr)); | |
814 | bcopy( &iphdr->ip_dst, ( mtod(m, struct snpa_hdr *))->snh_dhost, | |
815 | sizeof(struct in_addr)); | |
816 | ||
817 | IFDEBUG(D_EON) | |
818 | printf("eoninput to clnl IFQ\n"); | |
819 | ENDDEBUG | |
820 | ifq = &clnlintrq; | |
821 | splimp(); | |
822 | if (IF_QFULL(ifq)) { | |
823 | IF_DROP(ifq); | |
824 | m_freem(m); | |
825 | splx(s); | |
826 | eonifp->if_ierrors ++; | |
827 | return; | |
828 | } | |
829 | IF_ENQUEUE(ifq, m); | |
830 | IFDEBUG(D_EON) | |
831 | printf( | |
832 | "0x%x enqueued on clnp Q: m_len 0x%x m_type 0x%x m_off 0x%x\n", | |
833 | m, m->m_len, m->m_type, m->m_off); | |
834 | dump_buf(mtod(m, caddr_t), m->m_len); | |
835 | ENDDEBUG | |
836 | schednetisr(NETISR_CLNP); | |
837 | } | |
838 | done: | |
839 | splx(s); | |
840 | return 0; | |
841 | drop: | |
842 | IFDEBUG(D_EON) | |
843 | printf("eoninput: DROP \n" ); | |
844 | ENDDEBUG | |
845 | eonifp->if_ierrors ++; | |
846 | m_freem(m); | |
847 | goto done; | |
848 | } | |
849 | ||
850 | int | |
851 | eonctlinput(cmd, sin) | |
852 | int cmd; | |
853 | struct sockaddr_in *sin; | |
854 | { | |
855 | extern u_char inetctlerrmap[]; | |
856 | ||
857 | IFDEBUG(D_EON) | |
858 | printf("eonctlinput: cmd 0x%x addr: ", cmd); | |
859 | dump_isoaddr(sin); | |
860 | printf("\n"); | |
861 | ENDDEBUG | |
862 | ||
863 | if (cmd < 0 || cmd > PRC_NCMDS) | |
864 | return 0; | |
865 | ||
866 | IncStat(es_icmp[cmd]); | |
867 | switch (cmd) { | |
868 | ||
869 | case PRC_QUENCH2: | |
870 | case PRC_QUENCH: | |
871 | /* TODO: set the dec bit */ | |
872 | break; | |
873 | case PRC_TIMXCEED_REASS: | |
874 | case PRC_ROUTEDEAD: | |
875 | case PRC_HOSTUNREACH: | |
876 | case PRC_UNREACH_NET: | |
877 | case PRC_IFDOWN: | |
878 | case PRC_UNREACH_HOST: | |
879 | case PRC_HOSTDEAD: | |
880 | case PRC_TIMXCEED_INTRANS: | |
881 | /* TODO: mark the link down */ | |
882 | break; | |
883 | ||
884 | case PRC_UNREACH_PROTOCOL: | |
885 | case PRC_UNREACH_PORT: | |
886 | case PRC_UNREACH_NEEDFRAG: | |
887 | case PRC_UNREACH_SRCFAIL: | |
888 | case PRC_REDIRECT_NET: | |
889 | case PRC_REDIRECT_HOST: | |
890 | case PRC_REDIRECT_TOSNET: | |
891 | case PRC_REDIRECT_TOSHOST: | |
892 | case PRC_MSGSIZE: | |
893 | case PRC_PARAMPROB: | |
894 | printf("eonctlinput: ICMP cmd 0x%x\n", cmd ); | |
895 | break; | |
896 | } | |
897 | return 0; | |
898 | } | |
899 | ||
900 | #endif NEON>0 |