expand parameters to functions; READDIR drops eofflag;
[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 *
02863b0e 7 * @(#)esis.c 7.21 (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
a50e2bc0
KS
39#include "types.h"
40#include "param.h"
45a574af 41#include "systm.h"
a50e2bc0
KS
42#include "mbuf.h"
43#include "domain.h"
44#include "protosw.h"
a50e2bc0
KS
45#include "socket.h"
46#include "socketvar.h"
47#include "errno.h"
35cb309b
KS
48
49#include "../net/if.h"
c2bb180a 50#include "../net/if_dl.h"
35cb309b 51#include "../net/route.h"
fc0b162f 52#include "../net/raw_cb.h"
35cb309b 53
a50e2bc0
KS
54#include "iso.h"
55#include "iso_pcb.h"
56#include "iso_var.h"
57#include "iso_snpac.h"
58#include "clnl.h"
59#include "clnp.h"
60#include "clnp_stat.h"
a50e2bc0 61#include "esis.h"
44f52ea5 62#include "argo_debug.h"
6929d5df 63#include "kernel.h"
35cb309b
KS
64
65/*
66 * Global variables to esis implementation
67 *
68 * esis_holding_time - the holding time (sec) parameter for outgoing pdus
69 * esis_config_time - the frequency (sec) that hellos are generated
fc0b162f
KS
70 * esis_esconfig_time - suggested es configuration time placed in the
71 * ish.
35cb309b
KS
72 *
73 */
fc0b162f 74struct rawcb esis_pcb;
6929d5df 75int esis_config(), snpac_age();
35cb309b
KS
76int esis_sendspace = 2048;
77int esis_recvspace = 2048;
78short esis_holding_time = ESIS_HT;
79short esis_config_time = ESIS_CONFIG;
fc0b162f 80short esis_esconfig_time = ESIS_CONFIG;
35cb309b 81extern int iso_systype;
fc0b162f 82struct sockaddr_dl esis_dl = { sizeof(esis_dl), AF_LINK };
c2bb180a 83extern char all_es_snpa[], all_is_snpa[];
35cb309b 84
a50e2bc0 85#define EXTEND_PACKET(m, mhdr, cp)\
35cb309b
KS
86 if (((m)->m_next = m_getclr(M_DONTWAIT, MT_HEADER)) == NULL) {\
87 esis_stat.es_nomem++;\
88 m_freem(mhdr);\
89 return;\
90 } else {\
35cb309b 91 (m) = (m)->m_next;\
35cb309b
KS
92 (cp) = mtod((m), caddr_t);\
93 }
94/*
95 * FUNCTION: esis_init
96 *
97 * PURPOSE: Initialize the kernel portion of esis protocol
98 *
99 * RETURNS: nothing
100 *
101 * SIDE EFFECTS:
102 *
103 * NOTES:
104 */
105esis_init()
106{
107 extern struct clnl_protosw clnl_protox[256];
85162407 108 int esis_input(), isis_input();
35cb309b 109#ifdef ISO_X25ESIS
85162407 110 int x25esis_input();
35cb309b
KS
111#endif ISO_X25ESIS
112
fc0b162f
KS
113 esis_pcb.rcb_next = esis_pcb.rcb_prev = &esis_pcb;
114 llinfo_llc.lc_next = llinfo_llc.lc_prev = &llinfo_llc;
35cb309b 115
35cb309b
KS
116 timeout(snpac_age, (caddr_t)0, hz);
117 timeout(esis_config, (caddr_t)0, hz);
118
85162407
KS
119 clnl_protox[ISO9542_ESIS].clnl_input = esis_input;
120 clnl_protox[ISO10589_ISIS].clnl_input = isis_input;
35cb309b
KS
121#ifdef ISO_X25ESIS
122 clnl_protox[ISO9542X25_ESIS].clnl_input = x25esis_input;
123#endif ISO_X25ESIS
124}
125
126/*
127 * FUNCTION: esis_usrreq
128 *
129 * PURPOSE: Handle user level esis requests
130 *
131 * RETURNS: 0 or appropriate errno
132 *
133 * SIDE EFFECTS:
134 *
35cb309b 135 */
a50e2bc0 136/*ARGSUSED*/
b7468604 137esis_usrreq(so, req, m, nam, control)
35cb309b
KS
138struct socket *so; /* socket: used only to get to this code */
139int req; /* request */
140struct mbuf *m; /* data for request */
141struct mbuf *nam; /* optional name */
b7468604 142struct mbuf *control; /* optional control */
35cb309b 143{
fc0b162f
KS
144 struct rawcb *rp = sotorawcb(so);
145 int error = 0;
146
6929d5df 147 if ((so->so_state & SS_PRIV) == 0) {
fc0b162f
KS
148 error = EACCES;
149 goto release;
150 }
151 if (rp == NULL && req != PRU_ATTACH) {
152 error = EINVAL;
153 goto release;
154 }
155
156 switch (req) {
157 case PRU_ATTACH:
158 if (rp != NULL) {
159 error = EINVAL;
160 break;
161 }
162 MALLOC(rp, struct rawcb *, sizeof(*rp), M_PCB, M_WAITOK);
163 if (so->so_pcb = (caddr_t)rp) {
164 bzero(so->so_pcb, sizeof(*rp));
165 insque(rp, &esis_pcb);
16c005e8 166 rp->rcb_socket = so;
fc0b162f
KS
167 error = soreserve(so, esis_sendspace, esis_recvspace);
168 } else
169 error = ENOBUFS;
170 break;
171
172 case PRU_SEND:
173 if (nam == NULL) {
174 error = EINVAL;
175 break;
176 }
177 /* error checking here */
178 error = isis_output(mtod(nam,struct sockaddr_dl *), m);
179 m = NULL;
180 break;
181
182 case PRU_DETACH:
183 raw_detach(rp);
184 break;
185
186 case PRU_SHUTDOWN:
187 socantsendmore(so);
188 break;
189
190 case PRU_ABORT:
191 soisdisconnected(so);
192 raw_detach(rp);
193 break;
194
195 case PRU_SENSE:
196 return (0);
197
198 default:
199 return (EOPNOTSUPP);
200 }
201release:
35cb309b
KS
202 if (m != NULL)
203 m_freem(m);
204
fc0b162f 205 return (error);
35cb309b
KS
206}
207
208/*
209 * FUNCTION: esis_input
210 *
211 * PURPOSE: Process an incoming esis packet
212 *
213 * RETURNS: nothing
214 *
215 * SIDE EFFECTS:
216 *
217 * NOTES:
218 */
219esis_input(m0, shp)
220struct mbuf *m0; /* ptr to first mbuf of pkt */
221struct snpa_hdr *shp; /* subnetwork header */
222{
fc0b162f 223 register struct esis_fixed *pdu = mtod(m0, struct esis_fixed *);
a50e2bc0 224 register int type;
35cb309b 225
35cb309b
KS
226 /*
227 * check checksum if necessary
228 */
a50e2bc0 229 if (ESIS_CKSUM_REQUIRED(pdu) && iso_check_csum(m0, (int)pdu->esis_hdr_len)) {
35cb309b
KS
230 esis_stat.es_badcsum++;
231 goto bad;
232 }
233
234 /* check version */
235 if (pdu->esis_vers != ESIS_VERSION) {
236 esis_stat.es_badvers++;
237 goto bad;
238 }
a50e2bc0
KS
239 type = pdu->esis_type & 0x1f;
240 switch (type) {
35cb309b
KS
241 case ESIS_ESH:
242 esis_eshinput(m0, shp);
fc0b162f 243 break;
35cb309b
KS
244
245 case ESIS_ISH:
246 esis_ishinput(m0, shp);
fc0b162f 247 break;
35cb309b
KS
248
249 case ESIS_RD:
250 esis_rdinput(m0, shp);
fc0b162f 251 break;
35cb309b 252
fc0b162f 253 default:
35cb309b 254 esis_stat.es_badtype++;
35cb309b
KS
255 }
256
257bad:
fc0b162f
KS
258 if (esis_pcb.rcb_next != &esis_pcb)
259 isis_input(m0, shp);
260 else
261 m_freem(m0);
35cb309b
KS
262}
263
264/*
265 * FUNCTION: esis_rdoutput
266 *
267 * PURPOSE: Transmit a redirect pdu
268 *
269 * RETURNS: nothing
270 *
271 * SIDE EFFECTS:
272 *
273 * NOTES: Assumes there is enough space for fixed part of header,
274 * DA, BSNPA and NET in first mbuf.
275 */
c2bb180a 276esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, rt)
35cb309b
KS
277struct snpa_hdr *inbound_shp; /* snpa hdr from incoming packet */
278struct mbuf *inbound_m; /* incoming pkt itself */
279struct clnp_optidx *inbound_oidx; /* clnp options assoc with incoming pkt */
280struct iso_addr *rd_dstnsap; /* ultimate destination of pkt */
c2bb180a 281struct rtentry *rt; /* snpa cache info regarding next hop of
35cb309b
KS
282 pkt */
283{
284 struct mbuf *m, *m0;
285 caddr_t cp;
286 struct esis_fixed *pdu;
287 int len, total_len = 0;
288 struct sockaddr_iso siso;
289 struct ifnet *ifp = inbound_shp->snh_ifp;
c2bb180a
KS
290 struct sockaddr_dl *sdl;
291 struct iso_addr *rd_gwnsap;
292
293 if (rt->rt_flags & RTF_GATEWAY) {
294 rd_gwnsap = &((struct sockaddr_iso *)rt->rt_gateway)->siso_addr;
295 rt = rtalloc1(rt->rt_gateway, 0);
296 } else
297 rd_gwnsap = &((struct sockaddr_iso *)rt_key(rt))->siso_addr;
298 if (rt == 0 || (sdl = (struct sockaddr_dl *)rt->rt_gateway) == 0 ||
299 sdl->sdl_family != AF_LINK) {
300 /* maybe we should have a function that you
301 could put in the iso_ifaddr structure
302 which could translate iso_addrs into snpa's
303 where there is a known mapping for that address type */
304 esis_stat.es_badtype++;
305 return;
306 }
35cb309b 307 esis_stat.es_rdsent++;
35cb309b 308 IFDEBUG(D_ESISOUTPUT)
35cb309b
KS
309 printf("esis_rdoutput: ifp x%x (%s%d), ht %d, m x%x, oidx x%x\n",
310 ifp, ifp->if_name, ifp->if_unit, esis_holding_time, inbound_m,
311 inbound_oidx);
312 printf("\tdestination: %s\n", clnp_iso_addrp(rd_dstnsap));
c2bb180a 313 printf("\tredirected toward:%s\n", clnp_iso_addrp(rd_gwnsap));
35cb309b
KS
314 ENDDEBUG
315
a50e2bc0 316 if ((m0 = m = m_gethdr(M_DONTWAIT, MT_HEADER)) == NULL) {
35cb309b
KS
317 esis_stat.es_nomem++;
318 return;
319 }
a50e2bc0 320 bzero(mtod(m, caddr_t), MHLEN);
35cb309b
KS
321
322 pdu = mtod(m, struct esis_fixed *);
a50e2bc0 323 cp = (caddr_t)(pdu + 1); /*pointer arith.; 1st byte after header */
35cb309b
KS
324 len = sizeof(struct esis_fixed);
325
326 /*
327 * Build fixed part of header
328 */
329 pdu->esis_proto_id = ISO9542_ESIS;
330 pdu->esis_vers = ESIS_VERSION;
331 pdu->esis_type = ESIS_RD;
332 HTOC(pdu->esis_ht_msb, pdu->esis_ht_lsb, esis_holding_time);
333
334 /* Insert destination address */
d910a5d6 335 (void) esis_insert_addr(&cp, &len, rd_dstnsap, m, 0);
35cb309b
KS
336
337 /* Insert the snpa of better next hop */
c2bb180a
KS
338 *cp++ = sdl->sdl_alen;
339 bcopy(LLADDR(sdl), cp, sdl->sdl_alen);
340 cp += sdl->sdl_alen;
341 len += (sdl->sdl_alen + 1);
35cb309b
KS
342
343 /*
344 * If the next hop is not the destination, then it ought to be
345 * an IS and it should be inserted next. Else, set the
346 * NETL to 0
347 */
348 /* PHASE2 use mask from ifp of outgoing interface */
c2bb180a
KS
349 if (!iso_addrmatch1(rd_dstnsap, rd_gwnsap)) {
350 /* this should not happen:
35cb309b 351 if ((nhop_sc->sc_flags & SNPA_IS) == 0) {
35cb309b
KS
352 printf("esis_rdoutput: next hop is not dst and not an IS\n");
353 m_freem(m0);
354 return;
c2bb180a
KS
355 } */
356 (void) esis_insert_addr(&cp, &len, rd_gwnsap, m, 0);
35cb309b
KS
357 } else {
358 *cp++ = 0; /* NETL */
359 len++;
360 }
a50e2bc0 361 m->m_len = len;
35cb309b
KS
362
363 /*
364 * PHASE2
365 * If redirect is to an IS, add an address mask. The mask to be
366 * used should be the mask present in the routing entry used to
367 * forward the original data packet.
368 */
369
370 /*
371 * Copy Qos, priority, or security options present in original npdu
372 */
373 if (inbound_oidx) {
c2bb180a 374 /* THIS CODE IS CURRENTLY (mostly) UNTESTED */
35cb309b
KS
375 int optlen = 0;
376 if (inbound_oidx->cni_qos_formatp)
377 optlen += (inbound_oidx->cni_qos_len + 2);
378 if (inbound_oidx->cni_priorp) /* priority option is 1 byte long */
379 optlen += 3;
380 if (inbound_oidx->cni_securep)
381 optlen += (inbound_oidx->cni_secure_len + 2);
a50e2bc0
KS
382 if (M_TRAILINGSPACE(m) < optlen) {
383 EXTEND_PACKET(m, m0, cp);
384 m->m_len = 0;
35cb309b
KS
385 /* assumes MLEN > optlen */
386 }
387 /* assume MLEN-len > optlen */
388 /*
389 * When copying options, copy from ptr - 2 in order to grab
390 * the option code and length
391 */
392 if (inbound_oidx->cni_qos_formatp) {
c2bb180a
KS
393 bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_qos_formatp - 2,
394 cp, (unsigned)(inbound_oidx->cni_qos_len + 2));
395 cp += inbound_oidx->cni_qos_len + 2;
35cb309b
KS
396 }
397 if (inbound_oidx->cni_priorp) {
c2bb180a
KS
398 bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_priorp - 2,
399 cp, 3);
400 cp += 3;
35cb309b
KS
401 }
402 if (inbound_oidx->cni_securep) {
c2bb180a 403 bcopy(mtod(inbound_m, caddr_t) + inbound_oidx->cni_securep - 2, cp,
a50e2bc0 404 (unsigned)(inbound_oidx->cni_secure_len + 2));
c2bb180a 405 cp += inbound_oidx->cni_secure_len + 2;
35cb309b 406 }
a50e2bc0 407 m->m_len += optlen;
c2bb180a 408 len += optlen;
35cb309b
KS
409 }
410
a50e2bc0 411 pdu->esis_hdr_len = m0->m_pkthdr.len = len;
35cb309b
KS
412 iso_gen_csum(m0, ESIS_CKSUM_OFF, (int)pdu->esis_hdr_len);
413
a50e2bc0 414 bzero((caddr_t)&siso, sizeof(siso));
35cb309b 415 siso.siso_family = AF_ISO;
a50e2bc0
KS
416 siso.siso_data[0] = AFI_SNA;
417 siso.siso_nlen = 6 + 1; /* should be taken from snpa_hdr */
35cb309b 418 /* +1 is for AFI */
a50e2bc0 419 bcopy(inbound_shp->snh_shost, siso.siso_data + 1, 6);
02863b0e 420 (ifp->if_output)(ifp, m0, (struct sockaddr *)&siso, 0);
35cb309b
KS
421}
422
35cb309b
KS
423/*
424 * FUNCTION: esis_insert_addr
425 *
426 * PURPOSE: Insert an iso_addr into a buffer
427 *
428 * RETURNS: true if buffer was big enough, else false
429 *
430 * SIDE EFFECTS: Increment buf & len according to size of iso_addr
431 *
432 * NOTES: Plus 1 here is for length byte
433 */
d910a5d6 434esis_insert_addr(buf, len, isoa, m, nsellen)
c2bb180a
KS
435register caddr_t *buf; /* ptr to buffer to put address into */
436int *len; /* ptr to length of buffer so far */
437register struct iso_addr *isoa; /* ptr to address */
438register struct mbuf *m; /* determine if there remains space */
439int nsellen;
35cb309b 440{
c2bb180a
KS
441 register int newlen, result = 0;
442
443 isoa->isoa_len -= nsellen;
444 newlen = isoa->isoa_len + 1;
445 if (newlen <= M_TRAILINGSPACE(m)) {
446 bcopy((caddr_t)isoa, *buf, newlen);
447 *len += newlen;
448 *buf += newlen;
449 m->m_len += newlen;
450 result = 1;
451 }
452 isoa->isoa_len += nsellen;
453 return (result);
35cb309b
KS
454}
455
af8f5eff
KS
456#define ESIS_EXTRACT_ADDR(d, b) { d = (struct iso_addr *)(b); b += (1 + *b); \
457 if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
458#define ESIS_NEXT_OPTION(b) { b += (2 + b[1]); \
459 if (b > buflim) {esis_stat.es_toosmall++; goto bad;}}
087ffc43 460int ESHonly = 0;
35cb309b
KS
461/*
462
463/*
464 * FUNCTION: esis_eshinput
465 *
466 * PURPOSE: Process an incoming ESH pdu
467 *
468 * RETURNS: nothing
469 *
470 * SIDE EFFECTS:
471 *
472 * NOTES:
473 */
474esis_eshinput(m, shp)
475struct mbuf *m; /* esh pdu */
476struct snpa_hdr *shp; /* subnetwork header */
477{
d910a5d6 478 struct esis_fixed *pdu = mtod(m, struct esis_fixed *);
35cb309b 479 u_short ht; /* holding time */
d910a5d6 480 struct iso_addr *nsap;
af8f5eff 481 int naddr;
a50e2bc0 482 u_char *buf = (u_char *)(pdu + 1);
af8f5eff 483 u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu;
c2bb180a 484 int new_entry = 0;
35cb309b
KS
485
486 esis_stat.es_eshrcvd++;
487
488 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
489
af8f5eff
KS
490 naddr = *buf++;
491 if (buf >= buflim)
35cb309b 492 goto bad;
c2bb180a 493 if (naddr == 1) {
af8f5eff 494 ESIS_EXTRACT_ADDR(nsap, buf);
c2bb180a
KS
495 new_entry = snpac_add(shp->snh_ifp,
496 nsap, shp->snh_shost, SNPA_ES, ht, 0);
497 } else {
498 int nsellength = 0, nlen = 0;
499 {
500 /* See if we want to compress out multiple nsaps differing
501 only by nsel */
502 register struct ifaddr *ifa = shp->snh_ifp->if_addrlist;
503 for (; ifa; ifa = ifa->ifa_next)
504 if (ifa->ifa_addr->sa_family == AF_ISO) {
505 nsellength = ((struct iso_ifaddr *)ifa)->ia_addr.siso_tlen;
506 break;
507 }
508 }
af8f5eff 509 IFDEBUG(D_ESISINPUT)
c2bb180a
KS
510 printf("esis_eshinput: esh: ht %d, naddr %d nsellength %d\n",
511 ht, naddr, nsellength);
af8f5eff 512 ENDDEBUG
c2bb180a
KS
513 while (naddr-- > 0) {
514 struct iso_addr *nsap2; u_char *buf2;
515 ESIS_EXTRACT_ADDR(nsap, buf);
516 /* see if there is at least one more nsap in ESH differing
517 only by nsel */
518 if (nsellength != 0) for (buf2 = buf; buf2 < buflim;) {
519 ESIS_EXTRACT_ADDR(nsap2, buf2);
520 IFDEBUG(D_ESISINPUT)
521 printf("esis_eshinput: comparing %s ",
522 clnp_iso_addrp(nsap));
523 printf("and %s\n", clnp_iso_addrp(nsap2));
524 ENDDEBUG
525 if (Bcmp(nsap->isoa_genaddr, nsap2->isoa_genaddr,
526 nsap->isoa_len - nsellength) == 0) {
527 nlen = nsellength;
528 break;
529 }
530 }
531 new_entry |= snpac_add(shp->snh_ifp,
532 nsap, shp->snh_shost, SNPA_ES, ht, nlen);
533 nlen = 0;
534 }
35cb309b 535 }
c2bb180a
KS
536 IFDEBUG(D_ESISINPUT)
537 printf("esis_eshinput: nsap %s is %s\n",
538 clnp_iso_addrp(nsap), new_entry ? "new" : "old");
539 ENDDEBUG
540 if (new_entry && (iso_systype & SNPA_IS))
541 esis_shoutput(shp->snh_ifp, ESIS_ISH, esis_holding_time,
542 shp->snh_shost, 6, (struct iso_addr *)0);
af8f5eff 543bad:
af8f5eff 544 return;
35cb309b
KS
545}
546
547/*
548 * FUNCTION: esis_ishinput
549 *
550 * PURPOSE: process an incoming ISH pdu
551 *
552 * RETURNS:
553 *
554 * SIDE EFFECTS:
555 *
556 * NOTES:
557 */
558esis_ishinput(m, shp)
559struct mbuf *m; /* esh pdu */
560struct snpa_hdr *shp; /* subnetwork header */
561{
562 struct esis_fixed *pdu = mtod(m, struct esis_fixed *);
087ffc43 563 u_short ht, newct; /* holding time */
af8f5eff
KS
564 struct iso_addr *nsap; /* Network Entity Title */
565 register u_char *buf = (u_char *) (pdu + 1);
566 register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu;
567 int new_entry;
35cb309b
KS
568
569 esis_stat.es_ishrcvd++;
570 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
571
572 IFDEBUG(D_ESISINPUT)
573 printf("esis_ishinput: ish: ht %d\n", ht);
574 ENDDEBUG
af8f5eff 575 if (ESHonly)
a50e2bc0 576 goto bad;
a50e2bc0 577
af8f5eff
KS
578 ESIS_EXTRACT_ADDR(nsap, buf);
579
580 while (buf < buflim) {
581 switch (*buf) {
a50e2bc0 582 case ESISOVAL_ESCT:
16c005e8
KS
583 if (iso_systype & SNPA_IS)
584 break;
af8f5eff 585 if (buf[1] != 2)
a50e2bc0 586 goto bad;
087ffc43
KS
587 CTOH(buf[2], buf[3], newct);
588 if (esis_config_time != newct) {
589 untimeout(esis_config,0);
590 esis_config_time = newct;
591 esis_config();
592 }
af8f5eff
KS
593 break;
594
595 default:
596 printf("Unknown ISH option: %x\n", *buf);
a50e2bc0 597 }
af8f5eff 598 ESIS_NEXT_OPTION(buf);
a50e2bc0 599 }
c2bb180a 600 new_entry = snpac_add(shp->snh_ifp, nsap, shp->snh_shost, SNPA_IS, ht, 0);
a50e2bc0
KS
601 IFDEBUG(D_ESISINPUT)
602 printf("esis_ishinput: nsap %s is %s\n",
603 clnp_iso_addrp(nsap), new_entry ? "new" : "old");
604 ENDDEBUG
35cb309b 605
a50e2bc0
KS
606 if (new_entry)
607 esis_shoutput(shp->snh_ifp,
608 iso_systype & SNPA_ES ? ESIS_ESH : ESIS_ISH,
c2bb180a 609 esis_holding_time, shp->snh_shost, 6, (struct iso_addr *)0);
af8f5eff 610bad:
af8f5eff 611 return;
35cb309b
KS
612}
613
614/*
615 * FUNCTION: esis_rdinput
616 *
617 * PURPOSE: Process an incoming RD pdu
618 *
619 * RETURNS:
620 *
621 * SIDE EFFECTS:
622 *
623 * NOTES:
624 */
625esis_rdinput(m0, shp)
626struct mbuf *m0; /* esh pdu */
627struct snpa_hdr *shp; /* subnetwork header */
628{
629 struct esis_fixed *pdu = mtod(m0, struct esis_fixed *);
630 u_short ht; /* holding time */
af8f5eff
KS
631 struct iso_addr *da, *net = 0, *netmask = 0, *snpamask = 0;
632 register struct iso_addr *bsnpa;
633 register u_char *buf = (u_char *)(pdu + 1);
634 register u_char *buflim = pdu->esis_hdr_len + (u_char *)pdu;
35cb309b
KS
635
636 esis_stat.es_rdrcvd++;
637
638 /* intermediate systems ignore redirects */
639 if (iso_systype & SNPA_IS)
fc0b162f 640 return;
af8f5eff 641 if (ESHonly)
fc0b162f 642 return;
35cb309b
KS
643
644 CTOH(pdu->esis_ht_msb, pdu->esis_ht_lsb, ht);
af8f5eff 645 if (buf >= buflim)
fc0b162f 646 return;
35cb309b
KS
647
648 /* Extract DA */
af8f5eff 649 ESIS_EXTRACT_ADDR(da, buf);
a50e2bc0 650
35cb309b 651 /* Extract better snpa */
af8f5eff
KS
652 ESIS_EXTRACT_ADDR(bsnpa, buf);
653
35cb309b 654 /* Extract NET if present */
af8f5eff 655 if (buf < buflim) {
c2bb180a
KS
656 if (*buf == 0)
657 buf++; /* no NET present, skip NETL anyway */
658 else
659 ESIS_EXTRACT_ADDR(net, buf);
a50e2bc0
KS
660 }
661
662 /* process options */
af8f5eff
KS
663 while (buf < buflim) {
664 switch (*buf) {
a50e2bc0
KS
665 case ESISOVAL_SNPAMASK:
666 if (snpamask) /* duplicate */
fc0b162f 667 return;
af8f5eff 668 snpamask = (struct iso_addr *)(buf + 1);
a50e2bc0
KS
669 break;
670
671 case ESISOVAL_NETMASK:
672 if (netmask) /* duplicate */
fc0b162f 673 return;
af8f5eff
KS
674 netmask = (struct iso_addr *)(buf + 1);
675 break;
676
677 default:
678 printf("Unknown option in ESIS RD (0x%x)\n", buf[-1]);
35cb309b 679 }
af8f5eff 680 ESIS_NEXT_OPTION(buf);
35cb309b
KS
681 }
682
683 IFDEBUG(D_ESISINPUT)
a50e2bc0
KS
684 printf("esis_rdinput: rd: ht %d, da %s\n", ht, clnp_iso_addrp(da));
685 if (net)
686 printf("\t: net %s\n", clnp_iso_addrp(net));
35cb309b 687 ENDDEBUG
35cb309b
KS
688 /*
689 * If netl is zero, then redirect is to an ES. We need to add an entry
690 * to the snpa cache for (destination, better snpa).
691 * If netl is not zero, then the redirect is to an IS. In this
692 * case, add an snpa cache entry for (net, better snpa).
693 *
694 * If the redirect is to an IS, add a route entry towards that
695 * IS.
696 */
af8f5eff 697 if (net == 0 || net->isoa_len == 0 || snpamask) {
35cb309b 698 /* redirect to an ES */
af8f5eff 699 snpac_add(shp->snh_ifp, da,
c2bb180a 700 bsnpa->isoa_genaddr, SNPA_ES, ht, 0);
35cb309b 701 } else {
af8f5eff 702 snpac_add(shp->snh_ifp, net,
c2bb180a 703 bsnpa->isoa_genaddr, SNPA_IS, ht, 0);
af8f5eff 704 snpac_addrt(shp->snh_ifp, da, net, netmask);
35cb309b 705 }
fc0b162f 706bad: ; /* Needed by ESIS_NEXT_OPTION */
35cb309b
KS
707}
708
709/*
710 * FUNCTION: esis_config
711 *
712 * PURPOSE: Report configuration
713 *
714 * RETURNS:
715 *
716 * SIDE EFFECTS:
717 *
718 * NOTES: Called every esis_config_time seconds
719 */
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
1037#endif ISO