]> git.saurik.com Git - apple/xnu.git/blame_incremental - bsd/netiso/esis.c
xnu-201.42.3.tar.gz
[apple/xnu.git] / bsd / netiso / esis.c
... / ...
CommitLineData
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
62Permission to use, copy, modify, and distribute this software and its
63documentation for any purpose and without fee is hereby granted,
64provided that the above copyright notice appear in all copies and that
65both that copyright notice and this permission notice appear in
66supporting documentation, and that the name of IBM not be
67used in advertising or publicity pertaining to distribution of the
68software without specific, written prior permission.
69
70IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
71ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
72IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
73ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
74WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
75ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
76SOFTWARE.
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 */
120struct rawcb esis_pcb;
121void esis_config(), snpac_age();
122int esis_sendspace = 2048;
123int esis_recvspace = 2048;
124short esis_holding_time = ESIS_HT;
125short esis_config_time = ESIS_CONFIG;
126short esis_esconfig_time = ESIS_CONFIG;
127extern int iso_systype;
128struct sockaddr_dl esis_dl = { sizeof(esis_dl), AF_LINK };
129extern 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 */
151esis_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*/
183esis_usrreq(so, req, m, nam, control)
184struct socket *so; /* socket: used only to get to this code */
185int req; /* request */
186struct mbuf *m; /* data for request */
187struct mbuf *nam; /* optional name */
188struct 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 }
247release:
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 */
265esis_input(m0, shp)
266struct mbuf *m0; /* ptr to first mbuf of pkt */
267struct 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
303bad:
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 */
322esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt)
323struct snpa_hdr *inbound_shp; /* snpa hdr from incoming packet */
324struct mbuf *inbound_m; /* incoming pkt itself */
325struct clnp_optidx *inbound_oidx; /* clnp options assoc with incoming pkt */
326struct iso_addr *rd_dstnsap; /* ultimate destination of pkt */
327struct 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 */
480esis_insert_addr(buf, len, isoa, m, nsellen)
481register caddr_t *buf; /* ptr to buffer to put address into */
482int *len; /* ptr to length of buffer so far */
483register struct iso_addr *isoa; /* ptr to address */
484register struct mbuf *m; /* determine if there remains space */
485int 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;}}
506int 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 */
520esis_eshinput(m, shp)
521struct mbuf *m; /* esh pdu */
522struct 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);
589bad:
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 */
604esis_ishinput(m, shp)
605struct mbuf *m; /* esh pdu */
606struct 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);
656bad:
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 */
671esis_rdinput(m0, shp)
672struct mbuf *m0; /* esh pdu */
673struct 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 }
752bad: ; /* 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 */
766void
767esis_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 */
816esis_shoutput(ifp, type, ht, sn_addr, sn_len, isoa)
817struct ifnet *ifp;
818int type;
819short ht;
820caddr_t sn_addr;
821int sn_len;
822struct 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 */
958isis_input(m0, shp)
959struct mbuf *m0; /* ptr to first mbuf of pkt */
960struct 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
1008isis_output(sdl, m)
1009register struct sockaddr_dl *sdl;
1010struct 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
1051release:
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 */
1071esis_ctlinput(req, siso)
1072int req; /* request: we handle only PRC_IFDOWN */
1073struct 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 */