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