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