Commit | Line | Data |
---|---|---|
35cb309b KS |
1 | /*********************************************************** |
2 | Copyright IBM Corporation 1987 | |
3 | ||
4 | All Rights Reserved | |
5 | ||
6 | Permission to use, copy, modify, and distribute this software and its | |
7 | documentation for any purpose and without fee is hereby granted, | |
8 | provided that the above copyright notice appear in all copies and that | |
9 | both that copyright notice and this permission notice appear in | |
10 | supporting documentation, and that the name of IBM not be | |
11 | used in advertising or publicity pertaining to distribution of the | |
12 | software without specific, written prior permission. | |
13 | ||
14 | IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
15 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
16 | IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
17 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
18 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
19 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
20 | SOFTWARE. | |
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 |
29 | static 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 | */ | |
65 | struct isopcb esis_pcb; | |
66 | int esis_sendspace = 2048; | |
67 | int esis_recvspace = 2048; | |
68 | short esis_holding_time = ESIS_HT; | |
69 | short esis_config_time = ESIS_CONFIG; | |
70 | extern int iso_systype; | |
71 | extern 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 | */ | |
93 | esis_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 |
126 | esis_usrreq(so, req, m, nam, rights) |
127 | struct socket *so; /* socket: used only to get to this code */ | |
128 | int req; /* request */ | |
129 | struct mbuf *m; /* data for request */ | |
130 | struct mbuf *nam; /* optional name */ | |
131 | struct 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 | */ | |
150 | esis_input(m0, shp) | |
151 | struct mbuf *m0; /* ptr to first mbuf of pkt */ | |
152 | struct 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 | ||
204 | bad: | |
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 | */ | |
220 | esis_rdoutput(inbound_shp, inbound_m, inbound_oidx, rd_dstnsap, nhop_sc) | |
221 | struct snpa_hdr *inbound_shp; /* snpa hdr from incoming packet */ | |
222 | struct mbuf *inbound_m; /* incoming pkt itself */ | |
223 | struct clnp_optidx *inbound_oidx; /* clnp options assoc with incoming pkt */ | |
224 | struct iso_addr *rd_dstnsap; /* ultimate destination of pkt */ | |
225 | struct 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 | 361 | esis_insert_addr(buf, len, isoa, m) |
35cb309b KS |
362 | caddr_t *buf; /* ptr to buffer to put address into */ |
363 | int *len; /* ptr to length of buffer so far */ | |
364 | struct iso_addr *isoa; /* ptr to address */ | |
a50e2bc0 | 365 | register 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 | */ | |
391 | esis_eshinput(m, shp) | |
392 | struct mbuf *m; /* esh pdu */ | |
393 | struct 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 | 434 | bad: |
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 | */ | |
454 | esis_ishinput(m, shp) | |
455 | struct mbuf *m; /* esh pdu */ | |
456 | struct 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 | */ | |
519 | esis_rdinput(m0, shp) | |
520 | struct mbuf *m0; /* esh pdu */ | |
521 | struct 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 | } |
605 | bad: | |
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 | */ | |
620 | esis_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 | */ | |
666 | esis_shoutput(ifp, type, ht, sn_addr, sn_len) | |
667 | struct ifnet *ifp; | |
668 | int type; | |
669 | short ht; | |
670 | caddr_t sn_addr; | |
671 | int 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 | */ | |
769 | esis_ctlinput(req, siso) | |
770 | int req; /* request: we handle only PRC_IFDOWN */ | |
771 | struct 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 |