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