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