|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*-
23: * Copyright (c) 1991, 1993
24: * The Regents of the University of California. All rights reserved.
25: *
26: * Redistribution and use in source and binary forms, with or without
27: * modification, are permitted provided that the following conditions
28: * are met:
29: * 1. Redistributions of source code must retain the above copyright
30: * notice, this list of conditions and the following disclaimer.
31: * 2. Redistributions in binary form must reproduce the above copyright
32: * notice, this list of conditions and the following disclaimer in the
33: * documentation and/or other materials provided with the distribution.
34: * 3. All advertising materials mentioning features or use of this software
35: * must display the following acknowledgement:
36: * This product includes software developed by the University of
37: * California, Berkeley and its contributors.
38: * 4. Neither the name of the University nor the names of its contributors
39: * may be used to endorse or promote products derived from this software
40: * without specific prior written permission.
41: *
42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
52: * SUCH DAMAGE.
53: *
54: * @(#)esis.c 8.1 (Berkeley) 6/10/93
55: */
56:
57: /***********************************************************
58: Copyright IBM Corporation 1987
59:
60: All Rights Reserved
61:
62: Permission to use, copy, modify, and distribute this software and its
63: documentation for any purpose and without fee is hereby granted,
64: provided that the above copyright notice appear in all copies and that
65: both that copyright notice and this permission notice appear in
66: supporting documentation, and that the name of IBM not be
67: used in advertising or publicity pertaining to distribution of the
68: software without specific, written prior permission.
69:
70: IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
71: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
72: IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
73: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
74: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
75: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
76: SOFTWARE.
77:
78: ******************************************************************/
79:
80: /*
81: * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
82: */
83:
84: #if ISO
85:
86: #include <sys/param.h>
87: #include <sys/systm.h>
88: #include <sys/mbuf.h>
89: #include <sys/domain.h>
90: #include <sys/protosw.h>
91: #include <sys/socket.h>
92: #include <sys/socketvar.h>
93: #include <sys/errno.h>
94: #include <sys/kernel.h>
95:
96: #include <net/if.h>
97: #include <net/if_dl.h>
98: #include <net/route.h>
99: #include <net/raw_cb.h>
100:
101: #include <netiso/iso.h>
102: #include <netiso/iso_pcb.h>
103: #include <netiso/iso_var.h>
104: #include <netiso/iso_snpac.h>
105: #include <netiso/clnl.h>
106: #include <netiso/clnp.h>
107: #include <netiso/clnp_stat.h>
108: #include <netiso/esis.h>
109: #include <netiso/argo_debug.h>
110:
111: /*
112: * Global variables to esis implementation
113: *
114: * esis_holding_time - the holding time (sec) parameter for outgoing pdus
115: * esis_config_time - the frequency (sec) that hellos are generated
116: * esis_esconfig_time - suggested es configuration time placed in the
117: * ish.
118: *
119: */
120: struct rawcb esis_pcb;
121: void esis_config(), snpac_age();
122: int esis_sendspace = 2048;
123: int esis_recvspace = 2048;
124: short esis_holding_time = ESIS_HT;
125: short esis_config_time = ESIS_CONFIG;
126: short esis_esconfig_time = ESIS_CONFIG;
127: extern int iso_systype;
128: struct sockaddr_dl esis_dl = { sizeof(esis_dl), AF_LINK };
129: extern char all_es_snpa[], all_is_snpa[];
130:
131: #define EXTEND_PACKET(m, mhdr, cp)\
132: if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
133: esis_stat.es_nomem++;\
134: m_freem(mhdr);\
135: return;\
136: } else {\
137: (m) = (m)->m_next;\
138: (cp) = mtod((m), caddr_t);\
139: }
140: /*
141: * FUNCTION: esis_init
142: *
143: * PURPOSE: Initialize the kernel portion of esis protocol
144: *
145: * RETURNS: nothing
146: *
147: * SIDE EFFECTS:
148: *
149: * NOTES:
150: */
151: esis_init()
152: {
153: extern struct clnl_protosw clnl_protox[256];
154: int esis_input(), isis_input();
155: #ifdef ISO_X25ESIS
156: int x25esis_input();
157: #endif /* ISO_X25ESIS */
158:
159: esis_pcb.rcb_next = esis_pcb.rcb_prev = &esis_pcb;
160: llinfo_llc.lc_next = llinfo_llc.lc_prev = &llinfo_llc;
161:
162: timeout(snpac_age, (caddr_t)0, hz);
163: timeout(esis_config, (caddr_t)0, hz);
164:
165: clnl_protox[ISO9542_ESIS].clnl_input = esis_input;
166: clnl_protox[ISO10589_ISIS].clnl_input = isis_input;
167: #ifdef ISO_X25ESIS
168: clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input;
169: #endif /* ISO_X25ESIS */
170: }
171:
172: /*
173: * FUNCTION: esis_usrreq
174: *
175: * PURPOSE: Handle user level esis requests
176: *
177: * RETURNS: 0 or appropriate errno
178: *
179: * SIDE EFFECTS:
180: *
181: */
182: /*ARGSUSED*/
183: esis_usrreq(so, req, m, nam, control)
184: struct socket *so; /* socket: used only to get to this code */
185: int req; /* request */
186: struct mbuf *m; /* data for request */
187: struct mbuf *nam; /* optional name */
188: struct mbuf *control; /* optional control */
189: {
190: struct rawcb *rp = sotorawcb(so);
191: int error = 0;
192:
193: if ((so->so_state & SS_PRIV) == 0) {
194: error = EACCES;
195: goto release;
196: }
197: if (rp == NULL && req != PRU_ATTACH) {
198: error = EINVAL;
199: goto release;
200: }
201:
202: switch (req) {
203: case PRU_ATTACH:
204: if (rp != NULL) {
205: error = EINVAL;
206: break;
207: }
208: MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
209: if (so->so_pcb = (caddr_t)rp) {
210: bzero(so->so_pcb, sizeof(*rp));
211: insque(rp, &esis_pcb);
212: rp->rcb_socket = so;
213: error = soreserve(so, esis_sendspace, esis_recvspace);
214: } else
215: error = ENOBUFS;
216: break;
217:
218: case PRU_SEND:
219: if (nam == NULL) {
220: error = EINVAL;
221: break;
222: }
223: /* error checking here */
224: error = isis_output(mtod(nam,struct sockaddr_dl *), m);
225: m = NULL;
226: break;
227:
228: case PRU_DETACH:
229: raw_detach(rp);
230: break;
231:
232: case PRU_SHUTDOWN:
233: socantsendmore(so);
234: break;
235:
236: case PRU_ABORT:
237: soisdisconnected(so);
238: raw_detach(rp);
239: break;
240:
241: case PRU_SENSE:
242: return (0);
243:
244: default:
245: return (EOPNOTSUPP);
246: }
247: release:
248: if (m != NULL)
249: m_freem(m);
250:
251: return (error);
252: }
253:
254: /*
255: * FUNCTION: esis_input
256: *
257: * PURPOSE: Process an incoming esis packet
258: *
259: * RETURNS: nothing
260: *
261: * SIDE EFFECTS:
262: *
263: * NOTES:
264: */
265: esis_input(m0, shp)
266: struct mbuf *m0; /* ptr to first mbuf of pkt */
267: struct snpa_hdr *shp; /* subnetwork header */
268: {
269: register struct esis_fixed *pdu = mtod(m0, struct esis_fixed *);
270: register int type;
271:
272: /*
273: * check checksum if necessary
274: */
275: if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) {
276: esis_stat.es_badcsum++;
277: goto bad;
278: }
279:
280: /* check version */
281: if (pdu->esis_vers != ESIS_VERSION) {
282: esis_stat.es_badvers++;
283: goto bad;
284: }
285: type = pdu->esis_type & 0x1f;
286: switch (type) {
287: case ESIS_ESH:
288: esis_eshinput(m0, shp);
289: break;
290:
291: case ESIS_ISH:
292: esis_ishinput(m0, shp);
293: break;
294:
295: case ESIS_RD:
296: esis_rdinput(m0, shp);
297: break;
298:
299: default:
300: esis_stat.es_badtype++;
301: }
302:
303: bad:
304: if (esis_pcb.rcb_next != &esis_pcb)
305: isis_input(m0, shp);
306: else
307: m_freem(m0);
308: }
309:
310: /*
311: * FUNCTION: esis_rdoutput
312: *
313: * PURPOSE: Transmit a redirect pdu
314: *
315: * RETURNS: nothing
316: *
317: * SIDE EFFECTS:
318: *
319: * NOTES: Assumes there is enough space for fixed part of header,
320: * DA, BSNPA and NET in first mbuf.
321: */
322: esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt)
323: struct snpa_hdr *inbound_shp; /* snpa hdr from incoming packet */
324: struct mbuf *inbound_m; /* incoming pkt itself */
325: struct clnp_optidx *inbound_oidx; /* clnp options assoc with incoming pkt */
326: struct iso_addr *rd_dstnsap; /* ultimate destination of pkt */
327: struct rtentry *rt; /* snpa cache info regarding next hop of
328: pkt */
329: {
330: struct mbuf *m, *m0;
331: caddr_t cp;
332: struct esis_fixed *pdu;
333: int len, total_len = 0;
334: struct sockaddr_iso siso;
335: struct ifnet *ifp = inbound_shp->snh_ifp;
336: struct sockaddr_dl *sdl;
337: struct iso_addr *rd_gwnsap;
338:
339: if (rt->rt_flags & RTF_GATEWAY) {
340: rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr;
341: rt = rtalloc1(rt->rt_gateway, 0);
342: } else
343: rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr;
344: if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 ||
345: sdl->sdl_family != AF_LINK) {
346: /* maybe we should have a function that you
347: could put in the iso_ifaddr structure
348: which could translate iso_addrs into snpa's
349: where there is a known mapping for that address type */
350: esis_stat.es_badtype++;
351: return;
352: }
353: esis_stat.es_rdsent++;
354: IFDEBUG(D_ESISOUTPUT)
355: printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n",
356: ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m,
357: inbound_oidx);
358: printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
359: printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap));
360: ENDDEBUG
361:
362: if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
363: esis_stat.es_nomem++;
364: return;
365: }
366: bzero(mtod(m, caddr_t), MHLEN);
367:
368: pdu = mtod(m, struct esis_fixed *);
369: cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */
370: len = sizeof(struct esis_fixed);
371:
372: /*
373: * Build fixed part of header
374: */
375: pdu->esis_proto_id = ISO9542_ESIS;
376: pdu->esis_vers = ESIS_VERSION;
377: pdu->esis_type = ESIS_RD;
378: HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
379:
380: /* Insert destination address */
381: (void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0);
382:
383: /* Insert the snpa of better next hop */
384: *cp++ = sdl->sdl_alen;
385: bcopy(LLADDR(sdl), cp, sdl->sdl_alen);
386: cp += sdl->sdl_alen;
387: len += (sdl->sdl_alen + 1);
388:
389: /*
390: * If the next hop is not the destination, then it ought to be
391: * an IS and it should be inserted next. Else, set the
392: * NETL to 0
393: */
394: /* PHASE2 use mask from ifp of outgoing interface */
395: if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) {
396: /* this should not happen:
397: if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
398: printf("esis_rdoutput: next hop is not dst and not an IS\n");
399: m_freem(m0);
400: return;
401: } */
402: (void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0);
403: } else {
404: *cp++ = 0; /* NETL */
405: len++;
406: }
407: m->m_len = len;
408:
409: /*
410: * PHASE2
411: * If redirect is to an IS, add an address mask. The mask to be
412: * used should be the mask present in the routing entry used to
413: * forward the original data packet.
414: */
415:
416: /*
417: * Copy Qos, priority, or security options present in original npdu
418: */
419: if (inbound_oidx) {
420: /* THIS CODE IS CURRENTLY (mostly) UNTESTED */
421: int optlen = 0;
422: if (inbound_oidx->cni_qos_formatp)
423: optlen += (inbound_oidx->cni_qos_len + 2);
424: if (inbound_oidx->cni_priorp) /* priority option is 1 byte long */
425: optlen += 3;
426: if (inbound_oidx->cni_securep)
427: optlen += (inbound_oidx->cni_secure_len + 2);
428: if (M_TRAILINGSPACE(m) < optlen) {
429: EXTEND_PACKET(m, m0, cp);
430: m->m_len = 0;
431: /* assumes MLEN > optlen */
432: }
433: /* assume MLEN-len > optlen */
434: /*
435: * When copying options, copy from ptr - 2 in order to grab
436: * the option code and length
437: */
438: if (inbound_oidx->cni_qos_formatp) {
439: bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2,
440: cp, (unsigned)(inbound_oidx->cni_qos_len + 2));
441: cp += inbound_oidx->cni_qos_len + 2;
442: }
443: if (inbound_oidx->cni_priorp) {
444: bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2,
445: cp, 3);
446: cp += 3;
447: }
448: if (inbound_oidx->cni_securep) {
449: bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp,
450: (unsigned)(inbound_oidx->cni_secure_len + 2));
451: cp += inbound_oidx->cni_secure_len + 2;
452: }
453: m->m_len += optlen;
454: len += optlen;
455: }
456:
457: pdu->esis_hdr_len = m0->m_pkthdr.len = len;
458: iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
459:
460: bzero((caddr_t)&siso, sizeof(siso));
461: siso.siso_family = AF_ISO;
462: siso.siso_data[0] = AFI_SNA;
463: siso.siso_nlen = 6 + 1; /* should be taken from snpa_hdr */
464: /* +1 is for AFI */
465: bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6);
466: (ifp->if_output)(ifp, m0, (struct sockaddr *)&siso, 0);
467: }
468:
469: /*
470: * FUNCTION: esis_insert_addr
471: *
472: * PURPOSE: Insert an iso_addr into a buffer
473: *
474: * RETURNS: true if buffer was big enough, else false
475: *
476: * SIDE EFFECTS: Increment buf & len according to size of iso_addr
477: *
478: * NOTES: Plus 1 here is for length byte
479: */
480: esis_insert_addr(buf, len, isoa, m, nsellen)
481: register caddr_t *buf; /* ptr to buffer to put address into */
482: int *len; /* ptr to length of buffer so far */
483: register struct iso_addr *isoa; /* ptr to address */
484: register struct mbuf *m; /* determine if there remains space */
485: int nsellen;
486: {
487: register int newlen, result = 0;
488:
489: isoa->isoa_len -= nsellen;
490: newlen = isoa->isoa_len + 1;
491: if (newlen <= M_TRAILINGSPACE(m)) {
492: bcopy((caddr_t)isoa, *buf, newlen);
493: *len += newlen;
494: *buf += newlen;
495: m->m_len += newlen;
496: result = 1;
497: }
498: isoa->isoa_len += nsellen;
499: return (result);
500: }
501:
502: #define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \
503: if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
504: #define ESIS_NEXT_OPTION(b) { b += (2 + b[1]); \
505: if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
506: int ESHonly = 0;
507: /*
508:
509: /*
510: * FUNCTION: esis_eshinput
511: *
512: * PURPOSE: Process an incoming ESH pdu
513: *
514: * RETURNS: nothing
515: *
516: * SIDE EFFECTS:
517: *
518: * NOTES:
519: */
520: esis_eshinput(m, shp)
521: struct mbuf *m; /* esh pdu */
522: struct snpa_hdr *shp; /* subnetwork header */
523: {
524: struct esis_fixed *pdu = mtod(m, struct esis_fixed *);
525: u_short ht; /* holding time */
526: struct iso_addr *nsap;
527: int naddr;
528: u_char *buf = (u_char *)(pdu + 1);
529: u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu;
530: int new_entry = 0;
531:
532: esis_stat.es_eshrcvd++;
533:
534: CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
535:
536: naddr = *buf++;
537: if (buf >= buflim)
538: goto bad;
539: if (naddr == 1) {
540: ESIS_EXTRACT_ADDR(nsap, buf);
541: new_entry = snpac_add(shp->snh_ifp,
542: nsap, shp->snh_shost, SNPA_ES, ht, 0);
543: } else {
544: int nsellength = 0, nlen = 0;
545: {
546: /* See if we want to compress out multiple nsaps differing
547: only by nsel */
548: register struct ifaddr *ifa = shp->snh_ifp->if_addrlist;
549: for (; ifa; ifa = ifa->ifa_next)
550: if (ifa->ifa_addr->sa_family == AF_ISO) {
551: nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen;
552: break;
553: }
554: }
555: IFDEBUG(D_ESISINPUT)
556: printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n",
557: ht, naddr, nsellength);
558: ENDDEBUG
559: while (naddr-- > 0) {
560: struct iso_addr *nsap2; u_char *buf2;
561: ESIS_EXTRACT_ADDR(nsap, buf);
562: /* see if there is at least one more nsap in ESH differing
563: only by nsel */
564: if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) {
565: ESIS_EXTRACT_ADDR(nsap2, buf2);
566: IFDEBUG(D_ESISINPUT)
567: printf("esis_eshinput: comparing %s ",
568: clnp_iso_addrp(nsap));
569: printf("and %s\n", clnp_iso_addrp(nsap2));
570: ENDDEBUG
571: if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr,
572: nsap->isoa_len - nsellength) == 0) {
573: nlen = nsellength;
574: break;
575: }
576: }
577: new_entry |= snpac_add(shp->snh_ifp,
578: nsap, shp->snh_shost, SNPA_ES, ht, nlen);
579: nlen = 0;
580: }
581: }
582: IFDEBUG(D_ESISINPUT)
583: printf("esis_eshinput: nsap %s is %s\n",
584: clnp_iso_addrp(nsap), new_entry ? "new" : "old");
585: ENDDEBUG
586: if (new_entry && (iso_systype & SNPA_IS))
587: esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time,
588: shp->snh_shost, 6, (struct iso_addr *)0);
589: bad:
590: return;
591: }
592:
593: /*
594: * FUNCTION: esis_ishinput
595: *
596: * PURPOSE: process an incoming ISH pdu
597: *
598: * RETURNS:
599: *
600: * SIDE EFFECTS:
601: *
602: * NOTES:
603: */
604: esis_ishinput(m, shp)
605: struct mbuf *m; /* esh pdu */
606: struct snpa_hdr *shp; /* subnetwork header */
607: {
608: struct esis_fixed *pdu = mtod(m, struct esis_fixed *);
609: u_short ht, newct; /* holding time */
610: struct iso_addr *nsap; /* Network Entity Title */
611: register u_char *buf = (u_char *) (pdu + 1);
612: register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu;
613: int new_entry;
614:
615: esis_stat.es_ishrcvd++;
616: CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
617:
618: IFDEBUG(D_ESISINPUT)
619: printf("esis_ishinput: ish: ht %d\n", ht);
620: ENDDEBUG
621: if (ESHonly)
622: goto bad;
623:
624: ESIS_EXTRACT_ADDR(nsap, buf);
625:
626: while (buf < buflim) {
627: switch (*buf) {
628: case ESISOVAL_ESCT:
629: if (iso_systype & SNPA_IS)
630: break;
631: if (buf[1] != 2)
632: goto bad;
633: CTOH(buf[2], buf[3], newct);
634: if (esis_config_time != newct) {
635: untimeout(esis_config,0);
636: esis_config_time = newct;
637: esis_config();
638: }
639: break;
640:
641: default:
642: printf("Unknown ISH option: %x\n", *buf);
643: }
644: ESIS_NEXT_OPTION(buf);
645: }
646: new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0);
647: IFDEBUG(D_ESISINPUT)
648: printf("esis_ishinput: nsap %s is %s\n",
649: clnp_iso_addrp(nsap), new_entry ? "new" : "old");
650: ENDDEBUG
651:
652: if (new_entry)
653: esis_shoutput(shp->snh_ifp,
654: iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
655: esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0);
656: bad:
657: return;
658: }
659:
660: /*
661: * FUNCTION: esis_rdinput
662: *
663: * PURPOSE: Process an incoming RD pdu
664: *
665: * RETURNS:
666: *
667: * SIDE EFFECTS:
668: *
669: * NOTES:
670: */
671: esis_rdinput(m0, shp)
672: struct mbuf *m0; /* esh pdu */
673: struct snpa_hdr *shp; /* subnetwork header */
674: {
675: struct esis_fixed *pdu = mtod(m0, struct esis_fixed *);
676: u_short ht; /* holding time */
677: struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0;
678: register struct iso_addr *bsnpa;
679: register u_char *buf = (u_char *)(pdu + 1);
680: register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu;
681:
682: esis_stat.es_rdrcvd++;
683:
684: /* intermediate systems ignore redirects */
685: if (iso_systype & SNPA_IS)
686: return;
687: if (ESHonly)
688: return;
689:
690: CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
691: if (buf >= buflim)
692: return;
693:
694: /* Extract DA */
695: ESIS_EXTRACT_ADDR(da, buf);
696:
697: /* Extract better snpa */
698: ESIS_EXTRACT_ADDR(bsnpa, buf);
699:
700: /* Extract NET if present */
701: if (buf < buflim) {
702: if (*buf == 0)
703: buf++; /* no NET present, skip NETL anyway */
704: else
705: ESIS_EXTRACT_ADDR(net, buf);
706: }
707:
708: /* process options */
709: while (buf < buflim) {
710: switch (*buf) {
711: case ESISOVAL_SNPAMASK:
712: if (snpamask) /* duplicate */
713: return;
714: snpamask = (struct iso_addr *)(buf + 1);
715: break;
716:
717: case ESISOVAL_NETMASK:
718: if (netmask) /* duplicate */
719: return;
720: netmask = (struct iso_addr *)(buf + 1);
721: break;
722:
723: default:
724: printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]);
725: }
726: ESIS_NEXT_OPTION(buf);
727: }
728:
729: IFDEBUG(D_ESISINPUT)
730: printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da));
731: if (net)
732: printf("\t: net %s\n", clnp_iso_addrp(net));
733: ENDDEBUG
734: /*
735: * If netl is zero, then redirect is to an ES. We need to add an entry
736: * to the snpa cache for (destination, better snpa).
737: * If netl is not zero, then the redirect is to an IS. In this
738: * case, add an snpa cache entry for (net, better snpa).
739: *
740: * If the redirect is to an IS, add a route entry towards that
741: * IS.
742: */
743: if (net == 0 || net->isoa_len == 0 || snpamask) {
744: /* redirect to an ES */
745: snpac_add(shp->snh_ifp, da,
746: bsnpa->isoa_genaddr, SNPA_ES, ht, 0);
747: } else {
748: snpac_add(shp->snh_ifp, net,
749: bsnpa->isoa_genaddr, SNPA_IS, ht, 0);
750: snpac_addrt(shp->snh_ifp, da, net, netmask);
751: }
752: bad: ; /* Needed by ESIS_NEXT_OPTION */
753: }
754:
755: /*
756: * FUNCTION: esis_config
757: *
758: * PURPOSE: Report configuration
759: *
760: * RETURNS:
761: *
762: * SIDE EFFECTS:
763: *
764: * NOTES: Called every esis_config_time seconds
765: */
766: void
767: esis_config()
768: {
769: register struct ifnet *ifp;
770:
771: timeout(esis_config, (caddr_t)0, hz * esis_config_time);
772:
773: /*
774: * Report configuration for each interface that
775: * - is UP
776: * - has BROADCAST capability
777: * - has an ISO address
778: */
779: /* Todo: a better way would be to construct the esh or ish
780: * once and copy it out for all devices, possibly calling
781: * a method in the iso_ifaddr structure to encapsulate and
782: * transmit it. This could work to advantage for non-broadcast media
783: */
784:
785: for (ifp = ifnet; ifp; ifp = ifp->if_next) {
786: if ((ifp->if_flags & IFF_UP) &&
787: (ifp->if_flags & IFF_BROADCAST)) {
788: /* search for an ISO address family */
789: struct ifaddr *ia;
790:
791: for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
792: if (ia->ifa_addr->sa_family == AF_ISO) {
793: esis_shoutput(ifp,
794: iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
795: esis_holding_time,
796: (caddr_t)(iso_systype & SNPA_ES ? all_is_snpa :
797: all_es_snpa), 6, (struct iso_addr *)0);
798: break;
799: }
800: }
801: }
802: }
803: }
804:
805: /*
806: * FUNCTION: esis_shoutput
807: *
808: * PURPOSE: Transmit an esh or ish pdu
809: *
810: * RETURNS: nothing
811: *
812: * SIDE EFFECTS:
813: *
814: * NOTES:
815: */
816: esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa)
817: struct ifnet *ifp;
818: int type;
819: short ht;
820: caddr_t sn_addr;
821: int sn_len;
822: struct iso_addr *isoa;
823: {
824: struct mbuf *m, *m0;
825: caddr_t cp, naddrp;
826: int naddr = 0;
827: struct esis_fixed *pdu;
828: struct iso_ifaddr *ia;
829: int len;
830: struct sockaddr_iso siso;
831:
832: if (type == ESIS_ESH)
833: esis_stat.es_eshsent++;
834: else if (type == ESIS_ISH)
835: esis_stat.es_ishsent++;
836: else {
837: printf("esis_shoutput: bad pdu type\n");
838: return;
839: }
840:
841: IFDEBUG(D_ESISOUTPUT)
842: int i;
843: printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ",
844: ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish",
845: ht, sn_len);
846: for (i=0; i<sn_len; i++)
847: printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' ');
848: printf("\n");
849: ENDDEBUG
850:
851: if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
852: esis_stat.es_nomem++;
853: return;
854: }
855: bzero(mtod(m, caddr_t), MHLEN);
856:
857: pdu = mtod(m, struct esis_fixed *);
858: naddrp = cp = (caddr_t)(pdu + 1);
859: len = sizeof(struct esis_fixed);
860:
861: /*
862: * Build fixed part of header
863: */
864: pdu->esis_proto_id = ISO9542_ESIS;
865: pdu->esis_vers = ESIS_VERSION;
866: pdu->esis_type = type;
867: HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
868:
869: if (type == ESIS_ESH) {
870: cp++;
871: len++;
872: }
873:
874: m->m_len = len;
875: if (isoa) {
876: /*
877: * Here we are responding to a clnp packet sent to an NSAP
878: * that is ours which was sent to the MAC addr all_es's.
879: * It is possible that we did not specifically advertise this
880: * NSAP, even though it is ours, so we will respond
881: * directly to the sender that we are here. If we do have
882: * multiple NSEL's we'll tack them on so he can compress them out.
883: */
884: (void) esis_insert_addr(&cp, &len, isoa, m, 0);
885: naddr = 1;
886: }
887: for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
888: int nsellen = (type == ESIS_ISH ? ia->ia_addr.siso_tlen : 0);
889: int n = ia->ia_addr.siso_nlen;
890: register struct iso_ifaddr *ia2;
891:
892: if (type == ESIS_ISH && naddr > 0)
893: break;
894: for (ia2 = iso_ifaddr; ia2 != ia; ia2 = ia2->ia_next)
895: if (Bcmp(ia->ia_addr.siso_data, ia2->ia_addr.siso_data, n) == 0)
896: break;
897: if (ia2 != ia)
898: continue; /* Means we have previously copied this nsap */
899: if (isoa && Bcmp(ia->ia_addr.siso_data, isoa->isoa_genaddr, n) == 0) {
900: isoa = 0;
901: continue; /* Ditto */
902: }
903: IFDEBUG(D_ESISOUTPUT)
904: printf("esis_shoutput: adding NSAP %s\n",
905: clnp_iso_addrp(&ia->ia_addr.siso_addr));
906: ENDDEBUG
907: if (!esis_insert_addr(&cp, &len,
908: &ia->ia_addr.siso_addr, m, nsellen)) {
909: EXTEND_PACKET(m, m0, cp);
910: (void) esis_insert_addr(&cp, &len, &ia->ia_addr.siso_addr, m,
911: nsellen);
912: }
913: naddr++;
914: }
915:
916: if (type == ESIS_ESH)
917: *naddrp = naddr;
918: else {
919: /* add suggested es config timer option to ISH */
920: if (M_TRAILINGSPACE(m) < 4) {
921: printf("esis_shoutput: extending packet\n");
922: EXTEND_PACKET(m, m0, cp);
923: }
924: *cp++ = ESISOVAL_ESCT;
925: *cp++ = 2;
926: HTOC(*cp, *(cp+1), esis_esconfig_time);
927: len += 4;
928: m->m_len += 4;
929: IFDEBUG(D_ESISOUTPUT)
930: printf("m0 0x%x, m 0x%x, data 0x%x, len %d, cp 0x%x\n",
931: m0, m, m->m_data, m->m_len, cp);
932: ENDDEBUG
933: }
934:
935: m0->m_pkthdr.len = len;
936: pdu->esis_hdr_len = len;
937: iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
938:
939: bzero((caddr_t)&siso, sizeof(siso));
940: siso.siso_family = AF_ISO;
941: siso.siso_data[0] = AFI_SNA;
942: siso.siso_nlen = sn_len + 1;
943: bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len);
944: (ifp->if_output)(ifp, m0, (struct sockaddr *)&siso, 0);
945: }
946:
947: /*
948: * FUNCTION: isis_input
949: *
950: * PURPOSE: Process an incoming isis packet
951: *
952: * RETURNS: nothing
953: *
954: * SIDE EFFECTS:
955: *
956: * NOTES:
957: */
958: isis_input(m0, shp)
959: struct mbuf *m0; /* ptr to first mbuf of pkt */
960: struct snpa_hdr *shp; /* subnetwork header */
961: {
962: register int type;
963: register struct rawcb *rp, *first_rp = 0;
964: struct ifnet *ifp = shp->snh_ifp;
965: char workbuf[16];
966: struct mbuf *mm;
967:
968: IFDEBUG(D_ISISINPUT)
969: int i;
970:
971: printf("isis_input: pkt on ifp x%x (%s%d): from:", ifp,
972: ifp->if_name, ifp->if_unit);
973: for (i=0; i<6; i++)
974: printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' ');
975: printf(" to:");
976: for (i=0; i<6; i++)
977: printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' ');
978: printf("\n");
979: ENDDEBUG
980: esis_dl.sdl_alen = ifp->if_addrlen;
981: esis_dl.sdl_index = ifp->if_index;
982: bcopy(shp->snh_shost, (caddr_t)esis_dl.sdl_data, esis_dl.sdl_alen);
983: for (rp = esis_pcb.rcb_next; rp != &esis_pcb; rp = rp->rcb_next) {
984: if (first_rp == 0) {
985: first_rp = rp;
986: continue;
987: }
988: if (mm = m_copy(m0, 0, M_COPYALL)) { /*can't block at interrupt level */
989: if (sbappendaddr(&rp->rcb_socket->so_rcv,
990: &esis_dl, mm, (struct mbuf *)0) != 0) {
991: sorwakeup(rp->rcb_socket);
992: } else {
993: IFDEBUG(D_ISISINPUT)
994: printf("Error in sbappenaddr, mm = 0x%x\n", mm);
995: ENDDEBUG
996: m_freem(mm);
997: }
998: }
999: }
1000: if (first_rp && sbappendaddr(&first_rp->rcb_socket->so_rcv,
1001: &esis_dl, m0, (struct mbuf *)0) != 0) {
1002: sorwakeup(first_rp->rcb_socket);
1003: return;
1004: }
1005: m_freem(m0);
1006: }
1007:
1008: isis_output(sdl, m)
1009: register struct sockaddr_dl *sdl;
1010: struct mbuf *m;
1011: {
1012: register struct ifnet *ifp;
1013: struct ifaddr *ifa, *ifa_ifwithnet();
1014: struct sockaddr_iso siso;
1015: int error = 0;
1016: unsigned sn_len;
1017:
1018: ifa = ifa_ifwithnet((struct sockaddr *)sdl); /* get ifp from sdl */
1019: if (ifa == 0) {
1020: IFDEBUG(D_ISISOUTPUT)
1021: printf("isis_output: interface not found\n");
1022: ENDDEBUG
1023: error = EINVAL;
1024: goto release;
1025: }
1026: ifp = ifa->ifa_ifp;
1027: sn_len = sdl->sdl_alen;
1028: IFDEBUG(D_ISISOUTPUT)
1029: u_char *cp = (u_char *)LLADDR(sdl), *cplim = cp + sn_len;
1030: printf("isis_output: ifp 0x%x (%s%d), to: ",
1031: ifp, ifp->if_name, ifp->if_unit);
1032: while (cp < cplim) {
1033: printf("%x", *cp++);
1034: printf("%c", (cp < cplim) ? ':' : ' ');
1035: }
1036: printf("\n");
1037: ENDDEBUG
1038: bzero((caddr_t)&siso, sizeof(siso));
1039: siso.siso_family = AF_ISO; /* This convention may be useful for X.25 */
1040: siso.siso_data[0] = AFI_SNA;
1041: siso.siso_nlen = sn_len + 1;
1042: bcopy(LLADDR(sdl), siso.siso_data + 1, sn_len);
1043: error = (ifp->if_output)(ifp, m, (struct sockaddr *)&siso, 0);
1044: if (error) {
1045: IFDEBUG(D_ISISOUTPUT)
1046: printf("isis_output: error from ether_output is %d\n", error);
1047: ENDDEBUG
1048: }
1049: return (error);
1050:
1051: release:
1052: if (m != NULL)
1053: m_freem(m);
1054: return(error);
1055: }
1056:
1057:
1058: /*
1059: * FUNCTION: esis_ctlinput
1060: *
1061: * PURPOSE: Handle the PRC_IFDOWN transition
1062: *
1063: * RETURNS: nothing
1064: *
1065: * SIDE EFFECTS:
1066: *
1067: * NOTES: Calls snpac_flush for interface specified.
1068: * The loop through iso_ifaddr is stupid because
1069: * back in if_down, we knew the ifp...
1070: */
1071: esis_ctlinput(req, siso)
1072: int req; /* request: we handle only PRC_IFDOWN */
1073: struct sockaddr_iso *siso; /* address of ifp */
1074: {
1075: register struct iso_ifaddr *ia; /* scan through interface addresses */
1076:
1077: if (req == PRC_IFDOWN)
1078: for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
1079: if (iso_addrmatch(IA_SIS(ia), siso))
1080: snpac_flushifp(ia->ia_ifp);
1081: }
1082: }
1083:
1084: #endif /* ISO */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.