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