checkpoint for ``alpha tape''; tp is still a little broken.
[unix-history] / usr / src / sys / netiso / esis.c
CommitLineData
35cb309b
KS
1/***********************************************************
2 Copyright IBM Corporation 1987
3
4 All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of IBM not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22******************************************************************/
23
24/*
25 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26 */
44f52ea5 27/* @(#)esis.c 7.4 (Berkeley) %G% */
35cb309b
KS
28#ifndef lint
29static char *rcsid = "$Header: esis.c,v 4.10 88/09/15 18:57:03 hagens Exp $";
30#endif
31
32#ifdef ISO
33
a50e2bc0
KS
34#include "types.h"
35#include "param.h"
36#include "mbuf.h"
37#include "domain.h"
38#include "protosw.h"
a50e2bc0
KS
39#include "user.h"
40#include "socket.h"
41#include "socketvar.h"
42#include "errno.h"
43#include "kernel.h"
35cb309b
KS
44
45#include "../net/if.h"
46#include "../net/route.h"
47
a50e2bc0
KS
48#include "iso.h"
49#include "iso_pcb.h"
50#include "iso_var.h"
51#include "iso_snpac.h"
52#include "clnl.h"
53#include "clnp.h"
54#include "clnp_stat.h"
a50e2bc0 55#include "esis.h"
44f52ea5 56#include "argo_debug.h"
35cb309b
KS
57
58/*
59 * Global variables to esis implementation
60 *
61 * esis_holding_time - the holding time (sec) parameter for outgoing pdus
62 * esis_config_time - the frequency (sec) that hellos are generated
63 *
64 */
65struct isopcb esis_pcb;
66int esis_sendspace = 2048;
67int esis_recvspace = 2048;
68short esis_holding_time = ESIS_HT;
69short esis_config_time = ESIS_CONFIG;
70extern int iso_systype;
71extern struct snpa_cache all_es, all_is;
72
a50e2bc0 73#define EXTEND_PACKET(m, mhdr, cp)\
35cb309b
KS
74 if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
75 esis_stat.es_nomem++;\
76 m_freem(mhdr);\
77 return;\
78 } else {\
35cb309b 79 (m) = (m)->m_next;\
35cb309b
KS
80 (cp) = mtod((m), caddr_t);\
81 }
82/*
83 * FUNCTION: esis_init
84 *
85 * PURPOSE: Initialize the kernel portion of esis protocol
86 *
87 * RETURNS: nothing
88 *
89 * SIDE EFFECTS:
90 *
91 * NOTES:
92 */
93esis_init()
94{
95 extern struct clnl_protosw clnl_protox[256];
96 int esis_input();
97 int snpac_age();
98 int esis_config();
99#ifdef ISO_X25ESIS
100 x25esis_input();
101#endif ISO_X25ESIS
102
103 esis_pcb.isop_next = esis_pcb.isop_prev = &esis_pcb;
104
105 clnl_protox[ISO9542_ESIS].clnl_input = esis_input;
106 timeout(snpac_age, (caddr_t)0, hz);
107 timeout(esis_config, (caddr_t)0, hz);
108
109#ifdef ISO_X25ESIS
110 clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input;
111#endif ISO_X25ESIS
112}
113
114/*
115 * FUNCTION: esis_usrreq
116 *
117 * PURPOSE: Handle user level esis requests
118 *
119 * RETURNS: 0 or appropriate errno
120 *
121 * SIDE EFFECTS:
122 *
123 * NOTES: This is here only so esis gets initialized.
124 */
a50e2bc0 125/*ARGSUSED*/
35cb309b
KS
126esis_usrreq(so, req, m, nam, rights)
127struct socket *so; /* socket: used only to get to this code */
128int req; /* request */
129struct mbuf *m; /* data for request */
130struct mbuf *nam; /* optional name */
131struct mbuf *rights; /* optional rights */
132{
133 if (m != NULL)
134 m_freem(m);
135
136 return(EOPNOTSUPP);
137}
138
139/*
140 * FUNCTION: esis_input
141 *
142 * PURPOSE: Process an incoming esis packet
143 *
144 * RETURNS: nothing
145 *
146 * SIDE EFFECTS:
147 *
148 * NOTES:
149 */
150esis_input(m0, shp)
151struct mbuf *m0; /* ptr to first mbuf of pkt */
152struct snpa_hdr *shp; /* subnetwork header */
153{
35cb309b 154 struct esis_fixed *pdu = mtod(m0, struct esis_fixed *);
a50e2bc0 155 register int type;
35cb309b
KS
156
157 IFDEBUG(D_ESISINPUT)
158 int i;
159
160 printf("esis_input: pdu on ifp x%x (%s%d): from:", shp->snh_ifp,
161 shp->snh_ifp->if_name, shp->snh_ifp->if_unit);
162 for (i=0; i<6; i++)
163 printf("%x%c", shp->snh_shost[i]&0xff, (i<5) ? ':' : ' ');
164 printf(" to:");
165 for (i=0; i<6; i++)
166 printf("%x%c", shp->snh_dhost[i]&0xff, (i<5) ? ':' : ' ');
167 printf("\n");
168 ENDDEBUG
169
170 /*
171 * check checksum if necessary
172 */
a50e2bc0 173 if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) {
35cb309b
KS
174 esis_stat.es_badcsum++;
175 goto bad;
176 }
177
178 /* check version */
179 if (pdu->esis_vers != ESIS_VERSION) {
180 esis_stat.es_badvers++;
181 goto bad;
182 }
183
a50e2bc0
KS
184 type = pdu->esis_type & 0x1f;
185 switch (type) {
35cb309b
KS
186 case ESIS_ESH:
187 esis_eshinput(m0, shp);
188 return;
189
190 case ESIS_ISH:
191 esis_ishinput(m0, shp);
192 return;
193
194 case ESIS_RD:
195 esis_rdinput(m0, shp);
196 return;
197
198 default: {
199 esis_stat.es_badtype++;
200 goto bad;
201 }
202 }
203
204bad:
205 m_freem(m0);
206}
207
208/*
209 * FUNCTION: esis_rdoutput
210 *
211 * PURPOSE: Transmit a redirect pdu
212 *
213 * RETURNS: nothing
214 *
215 * SIDE EFFECTS:
216 *
217 * NOTES: Assumes there is enough space for fixed part of header,
218 * DA, BSNPA and NET in first mbuf.
219 */
220esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, nhop_sc)
221struct snpa_hdr *inbound_shp; /* snpa hdr from incoming packet */
222struct mbuf *inbound_m; /* incoming pkt itself */
223struct clnp_optidx *inbound_oidx; /* clnp options assoc with incoming pkt */
224struct iso_addr *rd_dstnsap; /* ultimate destination of pkt */
225struct snpa_cache *nhop_sc; /* snpa cache info regarding next hop of
226 pkt */
227{
228 struct mbuf *m, *m0;
229 caddr_t cp;
230 struct esis_fixed *pdu;
231 int len, total_len = 0;
232 struct sockaddr_iso siso;
233 struct ifnet *ifp = inbound_shp->snh_ifp;
234
235 esis_stat.es_rdsent++;
236
237 IFDEBUG(D_ESISOUTPUT)
35cb309b
KS
238 printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n",
239 ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m,
240 inbound_oidx);
241 printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
242 printf("\tredirected toward:%s\n", clnp_iso_addrp(&nhop_sc->sc_nsap));
243 ENDDEBUG
244
a50e2bc0 245 if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
35cb309b
KS
246 esis_stat.es_nomem++;
247 return;
248 }
a50e2bc0 249 bzero(mtod(m, caddr_t), MHLEN);
35cb309b
KS
250
251 pdu = mtod(m, struct esis_fixed *);
a50e2bc0 252 cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */
35cb309b
KS
253 len = sizeof(struct esis_fixed);
254
255 /*
256 * Build fixed part of header
257 */
258 pdu->esis_proto_id = ISO9542_ESIS;
259 pdu->esis_vers = ESIS_VERSION;
260 pdu->esis_type = ESIS_RD;
261 HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
262
263 /* Insert destination address */
a50e2bc0 264 (void) esis_insert_addr(&cp, &len, rd_dstnsap, m);
35cb309b
KS
265
266 /* Insert the snpa of better next hop */
267 *cp++ = nhop_sc->sc_len;
a50e2bc0 268 bcopy((caddr_t)nhop_sc->sc_snpa, cp, nhop_sc->sc_len);
35cb309b
KS
269 len += (nhop_sc->sc_len + 1);
270
271 /*
272 * If the next hop is not the destination, then it ought to be
273 * an IS and it should be inserted next. Else, set the
274 * NETL to 0
275 */
276 /* PHASE2 use mask from ifp of outgoing interface */
277 if (!iso_addrmatch1(rd_dstnsap, &nhop_sc->sc_nsap)) {
278 if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
279 /* this should not happen */
280 printf("esis_rdoutput: next hop is not dst and not an IS\n");
281 m_freem(m0);
282 return;
283 }
a50e2bc0 284 (void) esis_insert_addr(&cp, &len, &nhop_sc->sc_nsap, m);
35cb309b
KS
285 } else {
286 *cp++ = 0; /* NETL */
287 len++;
288 }
a50e2bc0 289 m->m_len = len;
35cb309b
KS
290
291 /*
292 * PHASE2
293 * If redirect is to an IS, add an address mask. The mask to be
294 * used should be the mask present in the routing entry used to
295 * forward the original data packet.
296 */
297
298 /*
299 * Copy Qos, priority, or security options present in original npdu
300 */
301 if (inbound_oidx) {
302 /* THIS CODE IS CURRENTLY UNTESTED */
303 int optlen = 0;
304 if (inbound_oidx->cni_qos_formatp)
305 optlen += (inbound_oidx->cni_qos_len + 2);
306 if (inbound_oidx->cni_priorp) /* priority option is 1 byte long */
307 optlen += 3;
308 if (inbound_oidx->cni_securep)
309 optlen += (inbound_oidx->cni_secure_len + 2);
a50e2bc0
KS
310 if (M_TRAILINGSPACE(m) < optlen) {
311 EXTEND_PACKET(m, m0, cp);
312 m->m_len = 0;
35cb309b
KS
313 /* assumes MLEN > optlen */
314 }
315 /* assume MLEN-len > optlen */
316 /*
317 * When copying options, copy from ptr - 2 in order to grab
318 * the option code and length
319 */
320 if (inbound_oidx->cni_qos_formatp) {
a50e2bc0
KS
321 bcopy((caddr_t)(inbound_m + inbound_oidx->cni_qos_formatp - 2), cp,
322 (unsigned)(inbound_oidx->cni_qos_len + 2));
35cb309b
KS
323 len += inbound_oidx->cni_qos_len + 2;
324 }
325 if (inbound_oidx->cni_priorp) {
a50e2bc0 326 bcopy((caddr_t)(inbound_m + inbound_oidx->cni_priorp - 2), cp, 3);
35cb309b
KS
327 len += 3;
328 }
329 if (inbound_oidx->cni_securep) {
a50e2bc0
KS
330 bcopy((caddr_t)(inbound_m + inbound_oidx->cni_securep - 2), cp,
331 (unsigned)(inbound_oidx->cni_secure_len + 2));
35cb309b
KS
332 len += inbound_oidx->cni_secure_len + 2;
333 }
a50e2bc0 334 m->m_len += optlen;
35cb309b
KS
335 }
336
a50e2bc0 337 pdu->esis_hdr_len = m0->m_pkthdr.len = len;
35cb309b
KS
338 iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
339
a50e2bc0
KS
340 bzero((caddr_t)&siso, sizeof(siso));
341 siso.siso_len = 12;
35cb309b 342 siso.siso_family = AF_ISO;
a50e2bc0
KS
343 siso.siso_data[0] = AFI_SNA;
344 siso.siso_nlen = 6 + 1; /* should be taken from snpa_hdr */
35cb309b 345 /* +1 is for AFI */
a50e2bc0 346 bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6);
35cb309b
KS
347 (ifp->if_output)(ifp, m0, &siso);
348}
349
35cb309b
KS
350/*
351 * FUNCTION: esis_insert_addr
352 *
353 * PURPOSE: Insert an iso_addr into a buffer
354 *
355 * RETURNS: true if buffer was big enough, else false
356 *
357 * SIDE EFFECTS: Increment buf & len according to size of iso_addr
358 *
359 * NOTES: Plus 1 here is for length byte
360 */
a50e2bc0 361esis_insert_addr(buf, len, isoa, m)
35cb309b
KS
362caddr_t *buf; /* ptr to buffer to put address into */
363int *len; /* ptr to length of buffer so far */
364struct iso_addr *isoa; /* ptr to address */
a50e2bc0 365register struct mbuf *m; /* determine if there remains space */
35cb309b 366{
a50e2bc0 367 register int newlen = isoa->isoa_len + 1;
35cb309b 368
a50e2bc0 369 if (newlen > M_TRAILINGSPACE(m))
35cb309b 370 return(0);
a50e2bc0
KS
371 bcopy((caddr_t)isoa, *buf, newlen);
372 *len += newlen;
373 *buf += newlen;
374 m->m_len += newlen;
35cb309b
KS
375 return(1);
376}
377
378/*
379
380/*
381 * FUNCTION: esis_eshinput
382 *
383 * PURPOSE: Process an incoming ESH pdu
384 *
385 * RETURNS: nothing
386 *
387 * SIDE EFFECTS:
388 *
389 * NOTES:
390 */
391esis_eshinput(m, shp)
392struct mbuf *m; /* esh pdu */
393struct snpa_hdr *shp; /* subnetwork header */
394{
395 struct esis_fixed *pdu = mtod(m, struct esis_fixed *);
396 u_short ht; /* holding time */
a50e2bc0
KS
397 struct iso_addr *nsap;
398 int naddr = 0;
399 u_char *buf = (u_char *)(pdu + 1);
35cb309b 400 int len = pdu->esis_hdr_len - sizeof(struct esis_fixed);
a50e2bc0 401 int optlen, new_entry;
35cb309b
KS
402
403 esis_stat.es_eshrcvd++;
404
405 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
406
407 if (len > 0) {
408 naddr = *buf++;
409 len--;
410 } else
411 goto bad;
412
413 IFDEBUG(D_ESISINPUT)
414 printf("esis_eshinput: esh: ht %d, naddr %d\n", ht, naddr);
415 ENDDEBUG
416
417 while (naddr-- > 0) {
a50e2bc0
KS
418 nsap = (struct iso_addr *)buf;
419 if ((len -= (optlen = *buf++)) >= 0) {
420 buf += optlen;
421 new_entry = (snpac_look(nsap) == NULL);
35cb309b
KS
422
423 IFDEBUG(D_ESISINPUT)
424 printf("esis_eshinput: nsap %s is %s\n",
a50e2bc0 425 clnp_iso_addrp(nsap), new_entry ? "new" : "old");
35cb309b
KS
426 ENDDEBUG
427
a50e2bc0 428 snpac_add(shp->snh_ifp, nsap, shp->snh_shost, 6, SNPA_ES, ht);
35cb309b
KS
429 if (new_entry)
430 esis_shoutput(shp->snh_ifp,
431 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
432 esis_holding_time, shp->snh_shost, 6);
433 } else {
a50e2bc0 434bad:
35cb309b
KS
435 esis_stat.es_toosmall++;
436 break;
437 }
438 }
439
35cb309b
KS
440 m_freem(m);
441}
442
443/*
444 * FUNCTION: esis_ishinput
445 *
446 * PURPOSE: process an incoming ISH pdu
447 *
448 * RETURNS:
449 *
450 * SIDE EFFECTS:
451 *
452 * NOTES:
453 */
454esis_ishinput(m, shp)
455struct mbuf *m; /* esh pdu */
456struct snpa_hdr *shp; /* subnetwork header */
457{
458 struct esis_fixed *pdu = mtod(m, struct esis_fixed *);
459 u_short ht; /* holding time */
a50e2bc0 460 struct iso_addr *nsap;
35cb309b
KS
461 caddr_t buf = (caddr_t)pdu + sizeof(struct esis_fixed);
462 int len = pdu->esis_hdr_len - sizeof(struct esis_fixed);
a50e2bc0 463 int optlen, new_entry;
35cb309b
KS
464
465 esis_stat.es_ishrcvd++;
466 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
467
468 IFDEBUG(D_ESISINPUT)
469 printf("esis_ishinput: ish: ht %d\n", ht);
470 ENDDEBUG
471
a50e2bc0
KS
472 nsap = (struct iso_addr *)buf;
473 if ((len -= (optlen = *buf++)) < 0)
474 goto bad;
475 buf += optlen;
476
477 /* process options */
478 while (len > 0) {
479 switch (*buf++) {
480 case ESISOVAL_ESCT:
481 if (*buf != 2)
482 goto bad;
483 CTOH(buf[0], buf[1], esis_config_time);
484 }
485 if ((len -= (optlen = *buf)) < 0) {
486 bad:
487 esis_stat.es_toosmall++;
488 m_freem(m);
489 return;
490 }
491 buf += 1 + optlen;
492 }
493 new_entry = (snpac_look(nsap) == NULL);
35cb309b 494
a50e2bc0
KS
495 IFDEBUG(D_ESISINPUT)
496 printf("esis_ishinput: nsap %s is %s\n",
497 clnp_iso_addrp(nsap), new_entry ? "new" : "old");
498 ENDDEBUG
35cb309b 499
a50e2bc0
KS
500 snpac_add(shp->snh_ifp, nsap, shp->snh_shost, 6, SNPA_IS, ht);
501 if (new_entry)
502 esis_shoutput(shp->snh_ifp,
503 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
504 esis_holding_time, shp->snh_shost, 6);
35cb309b
KS
505 m_freem(m);
506}
507
508/*
509 * FUNCTION: esis_rdinput
510 *
511 * PURPOSE: Process an incoming RD pdu
512 *
513 * RETURNS:
514 *
515 * SIDE EFFECTS:
516 *
517 * NOTES:
518 */
519esis_rdinput(m0, shp)
520struct mbuf *m0; /* esh pdu */
521struct snpa_hdr *shp; /* subnetwork header */
522{
523 struct esis_fixed *pdu = mtod(m0, struct esis_fixed *);
524 u_short ht; /* holding time */
a50e2bc0
KS
525 register struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0;
526 u_char *buf = (u_char *)(pdu + 1);
35cb309b 527 int len = pdu->esis_hdr_len - sizeof(struct esis_fixed);
a50e2bc0
KS
528 int optlen, bsnpalen;
529 caddr_t bsnpa;
35cb309b
KS
530
531 esis_stat.es_rdrcvd++;
532
533 /* intermediate systems ignore redirects */
534 if (iso_systype & SNPA_IS)
535 goto bad;
536
537 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
a50e2bc0
KS
538 if (len <= 0)
539 goto bad;
35cb309b
KS
540
541 /* Extract DA */
a50e2bc0
KS
542 da = (struct iso_addr *)buf;
543 if ((len -= (optlen = *buf++)) <= 0)
35cb309b 544 goto bad;
a50e2bc0
KS
545 buf += optlen;
546
35cb309b 547 /* Extract better snpa */
a50e2bc0 548 if ((len -= (bsnpalen = *buf++)) < 0)
35cb309b 549 goto bad;
a50e2bc0
KS
550 bsnpa = (caddr_t)buf;
551 buf += optlen;
552
35cb309b 553 /* Extract NET if present */
a50e2bc0
KS
554 if (len) {
555 net = (struct iso_addr *)buf;
556 if ((len -= (optlen = *buf++)) < 0)
35cb309b 557 goto bad;
a50e2bc0
KS
558 buf += optlen;
559 }
560
561 /* process options */
562 while (len > 0) {
563 switch (*buf++) {
564 case ESISOVAL_SNPAMASK:
565 if (snpamask) /* duplicate */
566 goto bad;
567 snpamask = (struct iso_addr *)buf;
568 break;
569
570 case ESISOVAL_NETMASK:
571 if (netmask) /* duplicate */
572 goto bad;
573 netmask = (struct iso_addr *)buf;
35cb309b 574 }
a50e2bc0
KS
575 if ((len -= (optlen = *buf)) < 0)
576 goto bad;
577 buf += 1 + optlen;
35cb309b
KS
578 }
579
580 IFDEBUG(D_ESISINPUT)
a50e2bc0
KS
581 printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da));
582 if (net)
583 printf("\t: net %s\n", clnp_iso_addrp(net));
35cb309b 584 ENDDEBUG
35cb309b
KS
585 /*
586 * If netl is zero, then redirect is to an ES. We need to add an entry
587 * to the snpa cache for (destination, better snpa).
588 * If netl is not zero, then the redirect is to an IS. In this
589 * case, add an snpa cache entry for (net, better snpa).
590 *
591 * If the redirect is to an IS, add a route entry towards that
592 * IS.
593 */
a50e2bc0 594 if ((net == 0) || (snpamask)) {
35cb309b 595 /* redirect to an ES */
a50e2bc0 596 snpac_add(shp->snh_ifp, da, bsnpa, bsnpalen, SNPA_ES, ht);
35cb309b 597 } else {
a50e2bc0
KS
598 struct iso_addr bsnpa_ia;
599
600 snpac_add(shp->snh_ifp, net, bsnpa, bsnpalen, SNPA_IS, ht);
601 bcopy(bsnpa, bsnpa_ia.isoa_genaddr, bsnpa_ia.isoa_len = 1 + bsnpalen);
602 bsnpa_ia.isoa_genaddr[0] = AFI_SNA;
603 snpac_addrt(da, &bsnpa_ia, net, netmask);
35cb309b
KS
604 }
605bad:
606 m_freem(m0);
607}
608
609/*
610 * FUNCTION: esis_config
611 *
612 * PURPOSE: Report configuration
613 *
614 * RETURNS:
615 *
616 * SIDE EFFECTS:
617 *
618 * NOTES: Called every esis_config_time seconds
619 */
620esis_config()
621{
622 register struct ifnet *ifp;
623
624 timeout(esis_config, (caddr_t)0, hz * esis_config_time);
625
626 /*
627 * Report configuration for each interface that
628 * - is UP
629 * - is not loopback
630 * - has broadcast capabilities
631 * - has an ISO address
632 */
633
634 for (ifp = ifnet; ifp; ifp = ifp->if_next) {
635 if ((ifp->if_flags & IFF_UP) &&
636 (ifp->if_flags & IFF_BROADCAST) &&
637 ((ifp->if_flags & IFF_LOOPBACK) == 0)) {
638 /* search for an ISO address family */
639 struct ifaddr *ia;
640
641 for (ia = ifp->if_addrlist; ia; ia = ia->ifa_next) {
a50e2bc0 642 if (ia->ifa_addr->sa_family == AF_ISO) {
35cb309b
KS
643 esis_shoutput(ifp,
644 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
645 esis_holding_time,
a50e2bc0
KS
646 (caddr_t)(iso_systype & SNPA_ES ? all_is.sc_snpa :
647 all_es.sc_snpa), 6);
35cb309b
KS
648 break;
649 }
650 }
651 }
652 }
653}
654
655/*
656 * FUNCTION: esis_shoutput
657 *
658 * PURPOSE: Transmit an esh or ish pdu
659 *
660 * RETURNS: nothing
661 *
662 * SIDE EFFECTS:
663 *
664 * NOTES:
665 */
666esis_shoutput(ifp, type, ht, sn_addr, sn_len)
667struct ifnet *ifp;
668int type;
669short ht;
670caddr_t sn_addr;
671int sn_len;
672{
673 struct mbuf *m, *m0;
674 caddr_t cp, naddrp;
675 int naddr = 0;
676 struct esis_fixed *pdu;
677 struct ifaddr *ifa;
a50e2bc0 678 int len;
35cb309b
KS
679 struct sockaddr_iso siso;
680
681 if (type == ESIS_ESH)
682 esis_stat.es_eshsent++;
683 else if (type == ESIS_ISH)
684 esis_stat.es_ishsent++;
685 else {
686 printf("esis_shoutput: bad pdu type\n");
687 return;
688 }
689
690 IFDEBUG(D_ESISOUTPUT)
691 int i;
692 printf("esis_shoutput: ifp x%x (%s%d), %s, ht %d, to: [%d] ",
693 ifp, ifp->if_name, ifp->if_unit, type == ESIS_ESH ? "esh" : "ish",
694 ht, sn_len);
695 for (i=0; i<sn_len; i++)
696 printf("%x%c", *(sn_addr+i), i < (sn_len-1) ? ':' : ' ');
697 printf("\n");
698 ENDDEBUG
699
a50e2bc0 700 if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
35cb309b
KS
701 esis_stat.es_nomem++;
702 return;
703 }
a50e2bc0 704 bzero(mtod(m, caddr_t), MHLEN);
35cb309b
KS
705
706 pdu = mtod(m, struct esis_fixed *);
a50e2bc0 707 naddrp = cp = (caddr_t)(pdu + 1);
35cb309b
KS
708 len = sizeof(struct esis_fixed);
709
710 /*
711 * Build fixed part of header
712 */
713 pdu->esis_proto_id = ISO9542_ESIS;
714 pdu->esis_vers = ESIS_VERSION;
715 pdu->esis_type = type;
716 HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
717
718 if (type == ESIS_ESH) {
719 cp++;
720 len++;
721 }
722
a50e2bc0 723 m->m_len = len;
35cb309b 724 for (ifa = ifp->if_addrlist; ifa; ifa=ifa->ifa_next) {
a50e2bc0 725 if (ifa->ifa_addr->sa_family == AF_ISO) {
35cb309b
KS
726 IFDEBUG(D_ESISOUTPUT)
727 printf("esis_shoutput: adding nsap %s\n",
728 clnp_iso_addrp(&IA_SIS(ifa)->siso_addr));
729 ENDDEBUG
a50e2bc0
KS
730 if (!esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr, m)) {
731 EXTEND_PACKET(m, m0, cp);
732 (void) esis_insert_addr(&cp, &len, &IA_SIS(ifa)->siso_addr, m);
35cb309b
KS
733 }
734 naddr++;
735 if (type == ESIS_ISH)
736 break;
737 }
738 }
739
740 if (type == ESIS_ESH)
741 *naddrp = naddr;
742
a50e2bc0
KS
743 m0->m_pkthdr.len = len;
744 pdu->esis_hdr_len = len;
35cb309b
KS
745 iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
746
a50e2bc0 747 bzero((caddr_t)&siso, sizeof(siso));
35cb309b 748 siso.siso_family = AF_ISO;
a50e2bc0
KS
749 siso.siso_data[0] = AFI_SNA;
750 siso.siso_nlen = sn_len + 1;
751 siso.siso_len = sn_len + 6;
752 bcopy(sn_addr, siso.siso_data + 1, (unsigned)sn_len);
35cb309b
KS
753 (ifp->if_output)(ifp, m0, &siso);
754}
755
756/*
757 * FUNCTION: esis_ctlinput
758 *
759 * PURPOSE: Handle the PRC_IFDOWN transition
760 *
761 * RETURNS: nothing
762 *
763 * SIDE EFFECTS:
764 *
765 * NOTES: Calls snpac_flush for interface specified.
766 * The loop through iso_ifaddr is stupid because
767 * back in if_down, we knew the ifp...
768 */
769esis_ctlinput(req, siso)
770int req; /* request: we handle only PRC_IFDOWN */
771struct sockaddr_iso *siso; /* address of ifp */
772{
773 register struct iso_ifaddr *ia; /* scan through interface addresses */
774
a50e2bc0
KS
775 if (req == PRC_IFDOWN)
776 for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
777 if (iso_addrmatch(IA_SIS(ia), siso))
778 snpac_flushifp(ia->ia_ifp);
779 }
35cb309b
KS
780}
781
782#endif ISO