FreeBSD/Linux Kernel Cross Reference
sys/netiso/if_cons.c
1 /* $NetBSD: if_cons.c,v 1.15 2003/08/07 16:33:35 agc Exp $ */
2
3 /*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
31 * @(#)if_cons.c 8.1 (Berkeley) 6/10/93
32 */
33
34 /***********************************************************
35 Copyright IBM Corporation 1987
36
37 All Rights Reserved
38
39 Permission to use, copy, modify, and distribute this software and its
40 documentation for any purpose and without fee is hereby granted,
41 provided that the above copyright notice appear in all copies and that
42 both that copyright notice and this permission notice appear in
43 supporting documentation, and that the name of IBM not be
44 used in advertising or publicity pertaining to distribution of the
45 software without specific, written prior permission.
46
47 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
48 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
49 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
50 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
51 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
52 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
53 SOFTWARE.
54
55 ******************************************************************/
56
57 /*
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
59 */
60 /*
61 * cons.c - Connection Oriented Network Service:
62 * including support for a) user transport-level service,
63 * b) COSNS below CLNP, and c) CONS below TP.
64 */
65
66 #include <sys/cdefs.h>
67 __KERNEL_RCSID(1, "$NetBSD: if_cons.c,v 1.15 2003/08/07 16:33:35 agc Exp $");
68
69 #ifdef TPCONS
70 #ifdef _KERNEL
71 #ifdef ARGO_DEBUG
72 #define Static
73 unsigned LAST_CALL_PCB;
74 #else /* ARGO_DEBUG */
75 #define Static static
76 #endif /* ARGO_DEBUG */
77
78 #ifndef SOCK_STREAM
79 #include <sys/param.h>
80 #include <sys/systm.h>
81 #include <sys/mbuf.h>
82 #include <sys/protosw.h>
83 #include <sys/socket.h>
84 #include <sys/socketvar.h>
85 #include <sys/errno.h>
86 #include <sys/ioctl.h>
87
88 #include <net/if.h>
89 #include <net/netisr.h>
90 #include <net/route.h>
91
92 #include <netiso/iso_errno.h>
93 #include <netiso/argo_debug.h>
94 #include <netiso/tp_trace.h>
95 #include <netiso/iso.h>
96 #include <netiso/cons.h>
97 #include <netiso/iso_pcb.h>
98 #include <netiso/iso_var.h>
99 #include <netiso/tp_var.h>
100 #include <netiso/clnp.h>
101
102 #include <netccitt/x25.h>
103 #include <netccitt/pk.h>
104 #include <netccitt/pk_var.h>
105 #include <netccitt/pk_extern.h>
106 #endif
107
108 #ifdef ARGO_DEBUG
109 #define MT_XCONN 0x50
110 #define MT_XCLOSE 0x51
111 #define MT_XCONFIRM 0x52
112 #define MT_XDATA 0x53
113 #define MT_XHEADER 0x54
114 #else
115 #define MT_XCONN MT_DATA
116 #define MT_XCLOSE MT_DATA
117 #define MT_XCONFIRM MT_DATA
118 #define MT_XDATA MT_DATA
119 #define MT_XHEADER MT_HEADER
120 #endif /* ARGO_DEBUG */
121
122 #define DONTCLEAR -1
123
124 /*********************************************************************
125 * cons.c - CONS interface to the x.25 layer
126 *
127 * TODO: figure out what resources we might run out of besides mbufs.
128 * If we run out of any of them (including mbufs) close and recycle
129 * lru x% of the connections, for some parameter x.
130 *
131 * There are 2 interfaces from above:
132 * 1) from TP0:
133 * cons CO network service
134 * TP associates a transport connection with a network connection.
135 * cons_output( isop, m, len, isdgm==0 )
136 * co_flags == 0
137 * 2) from TP4:
138 * It's a datagram service, like clnp is. - even though it calls
139 * cons_output( isop, m, len, isdgm==1 )
140 * it eventually goes through
141 * cosns_output(ifp, m, dst).
142 * TP4 permits multiplexing (reuse, possibly simultaneously) of the
143 * network connections.
144 * This means that many sockets (many tpcbs) may be associated with
145 * this pklcd, hence cannot have a back ptr from pklcd to a tpcb.
146 * co_flags & CONSF_DGM
147 * co_socket is null since there may be many sockets that use this pklcd.
148 * NOTE:
149 * streams would really be nice. sigh.
150 * NOTE:
151 * PVCs could be handled by config-ing a cons with an address and with the
152 * IFF_POINTTOPOINT flag on. This code would then have to skip the
153 * connection setup stuff for pt-to-pt links.
154 *
155 *********************************************************************/
156
157
158 #define CONS_IFQMAXLEN 5
159
160 Static int make_partial_x25_packet __P((struct isopcb *, struct pklcd *));
161 Static int NSAPtoDTE __P((struct sockaddr_iso *, struct sockaddr_x25 *));
162 Static int FACILtoNSAP __P((struct sockaddr_iso *, u_char *));
163 Static void init_siso __P((struct sockaddr_iso *));
164 Static int DTEtoNSAP __P((struct sockaddr_iso *, struct sockaddr_x25 *));
165 Static int parse_facil __P((struct pklcd *, struct isopcb *, caddr_t, u_char));
166
167 /* protosw pointers for getting to higher layer */
168 Static struct protosw *CLNP_proto;
169 Static struct protosw *TP_proto;
170 Static struct protosw *X25_proto;
171
172 extern struct isopcb tp_isopcb; /* chain of all TP pcbs */
173
174
175 #define HIGH_NIBBLE 1
176 #define LOW_NIBBLE 0
177
178 /*
179 * NAME: nibble_copy()
180 * FUNCTION and ARGUMENTS:
181 * copies (len) nibbles from (src_octet), high or low nibble
182 * to (dst_octet), high or low nibble,
183 * src_nibble & dst_nibble should be:
184 * HIGH_NIBBLE (1) if leftmost 4 bits/ most significant nibble
185 * LOW_NIBBLE (0) if rightmost 4 bits/ least significant nibble
186 * RETURNS: VOID
187 */
188 void
189 nibble_copy(src_octet, src_nibble, dst_octet, dst_nibble, len)
190 char *src_octet;
191 char *dst_octet;
192 unsigned src_nibble;
193 unsigned dst_nibble;
194 int len;
195 {
196
197 int i;
198 unsigned dshift, sshift;
199
200 #ifdef ARGO_DEBUG
201 if (argo_debug[D_CADDR]) {
202 printf("nibble_copy ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
203 src_octet, src_nibble, dst_octet, dst_nibble, len);
204 }
205 #endif
206 #define SHIFT 0x4
207
208 dshift = dst_nibble << 2;
209 sshift = src_nibble << 2;
210
211 for (i = 0; i < len; i++) {
212 /* clear dst_nibble */
213 *dst_octet &= ~(0xf << dshift);
214
215 /* set dst nibble */
216 *dst_octet |= (0xf & (*src_octet >> sshift)) << dshift;
217
218 dshift ^= SHIFT;
219 sshift ^= SHIFT;
220 src_nibble = 1 - src_nibble;
221 dst_nibble = 1 - dst_nibble;
222 src_octet += src_nibble;
223 dst_octet += dst_nibble;
224 }
225 #ifdef ARGO_DEBUG
226 if (argo_debug[D_CADDR]) {
227 printf("nibble_copy DONE\n");
228 }
229 #endif
230 }
231
232 /*
233 * NAME: nibble_match()
234 * FUNCTION and ARGUMENTS:
235 * compares src_octet/src_nibble and dst_octet/dst_nibble for len nibbles.
236 * RETURNS: 0 if they differ, 1 if they are the same.
237 */
238 int
239 nibble_match(src_octet, src_nibble, dst_octet, dst_nibble, len)
240 char *src_octet;
241 char *dst_octet;
242 unsigned src_nibble;
243 unsigned dst_nibble;
244 int len;
245 {
246
247 int i;
248 unsigned dshift, sshift;
249 u_char nibble_a, nibble_b;
250
251 #ifdef ARGO_DEBUG
252 if (argo_debug[D_CADDR]) {
253 printf("nibble_match ( 0x%x, 0x%x, 0x%x, 0x%x 0x%x)\n",
254 src_octet, src_nibble, dst_octet, dst_nibble, len);
255 }
256 #endif
257 #define SHIFT 0x4
258
259 dshift = dst_nibble << 2;
260 sshift = src_nibble << 2;
261
262 for (i = 0; i < len; i++) {
263 nibble_b = ((*dst_octet) >> dshift) & 0xf;
264 nibble_a = (0xf & (*src_octet >> sshift));
265 if (nibble_b != nibble_a)
266 return 0;
267
268 dshift ^= SHIFT;
269 sshift ^= SHIFT;
270 src_nibble = 1 - src_nibble;
271 dst_nibble = 1 - dst_nibble;
272 src_octet += src_nibble;
273 dst_octet += dst_nibble;
274 }
275 #ifdef ARGO_DEBUG
276 if (argo_debug[D_CADDR]) {
277 printf("nibble_match DONE\n");
278 }
279 #endif
280 return 1;
281 }
282
283 /*
284 **************************** NET PROTOCOL cons ***************************
285 */
286 /*
287 * NAME: cons_init()
288 * CALLED FROM:
289 * autoconf
290 * FUNCTION:
291 * initialize the protocol
292 */
293 void
294 cons_init()
295 {
296 CLNP_proto = pffindproto(AF_ISO, ISOPROTO_CLNP, SOCK_DGRAM);
297 X25_proto = pffindproto(AF_ISO, ISOPROTO_X25, SOCK_STREAM);
298 TP_proto = pffindproto(AF_ISO, ISOPROTO_TP0, SOCK_SEQPACKET);
299 #ifdef ARGO_DEBUG
300 if (argo_debug[D_CCONS]) {
301 printf("cons_init end : cnlp_proto 0x%x cons proto 0x%x tp proto 0x%x\n",
302 CLNP_proto, X25_proto, TP_proto);
303 }
304 #endif
305 #ifdef notdef
306 pk_protolisten(0x81, 0, clnp_incoming);
307 pk_protolisten(0x82, 0, esis_incoming);
308 pk_protolisten(0x84, 0, tp8878_A_incoming);
309 pk_protolisten(0, 0, tp_incoming);
310 #endif
311 }
312
313 int
314 tp_incoming(m, v)
315 struct mbuf *m;
316 void *v;
317 {
318 struct pklcd *lcp = v;
319 struct isopcb *isop;
320
321 if (iso_pcballoc(NULL, &tp_isopcb)) {
322 pk_close(lcp);
323 return 0;
324 }
325 isop = tp_isopcb.isop_next;
326 lcp->lcd_upper = cons_tpinput;
327 lcp->lcd_upnext = (caddr_t) isop;
328 lcp->lcd_send(lcp); /* Confirms call */
329 isop->isop_chan = (caddr_t) lcp;
330 isop->isop_laddr = &isop->isop_sladdr;
331 isop->isop_faddr = &isop->isop_sfaddr;
332 DTEtoNSAP(isop->isop_laddr, &lcp->lcd_laddr);
333 DTEtoNSAP(isop->isop_faddr, &lcp->lcd_faddr);
334 parse_facil(lcp, isop, &(mtod(m, struct x25_packet *)->packet_data),
335 m->m_pkthdr.len - PKHEADERLN);
336 return 0;
337 }
338
339 int
340 cons_tpinput(m0, v)
341 struct mbuf *m0;
342 void *v;
343 {
344 struct pklcd *lcp = v;
345 struct isopcb *isop = (struct isopcb *) lcp->lcd_upnext;
346 int cmd, ptype = PK_CLEAR;
347
348 if (isop == 0)
349 return 0;
350 if (m0 == 0)
351 goto dead;
352 switch (m0->m_type) {
353 case MT_DATA:
354 case MT_OOBDATA:
355 tpcons_input(m0, isop->isop_faddr, isop->isop_laddr,
356 (caddr_t) lcp);
357 return 0;
358
359 case MT_CONTROL:
360 switch (ptype = pk_decode(mtod(m0, struct x25_packet *))) {
361
362 case PK_RR:
363 cmd = PRC_CONS_SEND_DONE;
364 break;
365
366 case PK_CALL_ACCEPTED:
367 if (lcp->lcd_sb.sb_mb)
368 lcp->lcd_send(lcp); /* XXX - fix this */
369 /* FALLTHROUGH */
370 default:
371 return 0;
372
373 dead:
374 case PK_CLEAR:
375 case PK_CLEAR_CONF:
376 lcp->lcd_upper = 0;
377 lcp->lcd_upnext = 0;
378 isop->isop_chan = 0;
379 case PK_RESET:
380 cmd = PRC_ROUTEDEAD;
381 }
382 tpcons_ctlinput(cmd, (struct sockaddr *) isop->isop_faddr,
383 isop);
384 if (cmd == PRC_ROUTEDEAD && isop->isop_refcnt == 0)
385 iso_pcbdetach(isop);
386 }
387 return 0;
388 }
389
390 /*
391 * NAME: cons_connect()
392 * CALLED FROM:
393 * tpcons_pcbconnect() when opening a new connection.
394 * FUNCTION anD ARGUMENTS:
395 * Figures out which device to use, finding a route if one doesn't
396 * already exist.
397 * RETURN VALUE:
398 * returns E*
399 */
400 int
401 cons_connect(isop)
402 struct isopcb *isop;
403 {
404 struct pklcd *lcp = (struct pklcd *) isop->isop_chan;
405 int error;
406
407 #ifdef ARGO_DEBUG
408 if (argo_debug[D_CCONN]) {
409 printf("cons_connect(0x%x): ", isop);
410 dump_isoaddr(isop->isop_faddr);
411 printf("myaddr: ");
412 dump_isoaddr(isop->isop_laddr);
413 printf("\n");
414 }
415 #endif
416 NSAPtoDTE(isop->isop_faddr, &lcp->lcd_faddr);
417 lcp->lcd_upper = cons_tpinput;
418 lcp->lcd_upnext = (caddr_t) isop;
419 #ifdef ARGO_DEBUG
420 if (argo_debug[D_CCONN]) {
421 printf(
422 "calling make_partial_x25_packet( 0x%x, 0x%x, 0x%x)\n",
423 &lcp->lcd_faddr, &lcp->lcd_laddr,
424 isop->isop_socket->so_proto->pr_protocol);
425 }
426 #endif
427 if ((error = make_partial_x25_packet(isop, lcp)) == 0)
428 error = pk_connect(lcp, &lcp->lcd_faddr);
429 return error;
430 }
431
432 /*
433 **************************** DEVICE cons ***************************
434 */
435
436
437 /*
438 * NAME: cons_ctlinput() CALLED FROM: lower layer when ECN_CLEAR
439 * occurs : this routine is here for consistency - cons subnet service calls
440 * its higher layer through the protosw entry. FUNCTION & ARGUMENTS: cmd is a
441 * PRC_* command, list found in ../sys/protosw.h copcb is the obvious. This
442 * serves the higher-layer cons service. NOTE: this takes 3rd arg. because
443 * cons uses it to inform itself of things (timeouts, etc) but has a pcb
444 * instead of an address.
445 */
446 void *
447 cons_ctlinput(cmd, sa, v)
448 int cmd;
449 struct sockaddr *sa;
450 void *v;
451 {
452 return NULL;
453 }
454
455
456 int
457 find_error_reason(xp)
458 struct x25_packet *xp;
459 {
460 int error, cause = 0;
461
462 if (xp) {
463 cause = 4[(char *) xp];
464 switch (cause) {
465 case 0x00:
466 case 0x80:
467 /* DTE originated; look at the diagnostic */
468 error = (CONL_ERROR_MASK | cause);
469 goto done;
470
471 case 0x01: /* number busy */
472 case 0x81:
473 case 0x09: /* Out of order */
474 case 0x89:
475 case 0x11: /* Remot Procedure Error */
476 case 0x91:
477 case 0x19: /* reverse charging accept not subscribed */
478 case 0x99:
479 case 0x21: /* Incampat destination */
480 case 0xa1:
481 case 0x29: /* fast select accept not subscribed */
482 case 0xa9:
483 case 0x39: /* ship absent */
484 case 0xb9:
485 case 0x03: /* invalid facil request */
486 case 0x83:
487 case 0x0b: /* access barred */
488 case 0x8b:
489 case 0x13: /* local procedure error */
490 case 0x93:
491 case 0x05: /* network congestion */
492 case 0x85:
493 case 0x8d: /* not obtainable */
494 case 0x0d:
495 case 0x95: /* RPOA out of order */
496 case 0x15:
497 /*
498 * take out bit 8 so we don't have to have so many
499 * perror entries
500 */
501 error = (CONL_ERROR_MASK | 0x100 | (cause & ~0x80));
502 goto done;
503
504 case 0xc1: /* gateway-detected proc error */
505 case 0xc3: /* gateway congestion */
506
507 error = (CONL_ERROR_MASK | 0x100 | cause);
508 goto done;
509 }
510 }
511 /* otherwise, a *hopefully* valid perror exists in the e_reason field */
512 error = xp->packet_data;
513 if (error == 0) {
514 printf("Incoming PKT TYPE 0x%x with reason 0x%x\n",
515 pk_decode(xp), cause);
516 error = E_CO_HLI_DISCA;
517 }
518 done:
519 return error;
520 }
521
522
523
524 #endif /* _KERNEL */
525
526 /*
527 * NAME: make_partial_x25_packet()
528 *
529 * FUNCTION and ARGUMENTS:
530 * Makes part of an X.25 call packet, for use by x25.
531 * (src) and (dst) are the NSAP-addresses of source and destination.
532 * (buf) is a ptr to a buffer into which to write this partial header.
533 *
534 * 0 Facility length (in octets)
535 * 1 Facility field, which is a set of:
536 * m facil code
537 * m+1 facil param len (for >2-byte facilities) in octets
538 * m+2..p facil param field
539 * q user data (protocol identification octet)
540 *
541 *
542 * RETURNS:
543 * 0 if OK
544 * E* if failed.
545 *
546 * SIDE EFFECTS:
547 * Stores facilites mbuf in X.25 control block, where the connect
548 * routine knows where to look for it.
549 */
550
551 #ifdef X25_1984
552 int cons_use_facils = 1;
553 #else /* X25_1984 */
554 int cons_use_facils = 0;
555 #endif /* X25_1984 */
556
557 int cons_use_udata = 1; /* KLUDGE FOR DEBUGGING */
558
559 Static int
560 make_partial_x25_packet(isop, lcp)
561 struct isopcb *isop;
562 struct pklcd *lcp;
563 {
564 u_int proto = 0;
565 int flag = 0;
566 caddr_t buf;
567 caddr_t ptr;
568 int len = 0;
569 int buflen = 0;
570 caddr_t facil_len;
571 struct mbuf *m = NULL;
572
573
574 #ifdef ARGO_DEBUG
575 if (argo_debug[D_CCONN]) {
576 printf("make_partial_x25_packet(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
577 isop->isop_laddr, isop->isop_faddr, proto, m, flag);
578 }
579 #endif
580 if (cons_use_udata) {
581 if (isop->isop_x25crud_len > 0) {
582 /*
583 * The user specified something. Stick it in
584 */
585 bcopy(isop->isop_x25crud, lcp->lcd_faddr.x25_udata,
586 isop->isop_x25crud_len);
587 lcp->lcd_faddr.x25_udlen = isop->isop_x25crud_len;
588 }
589 }
590 if (cons_use_facils == 0) {
591 lcp->lcd_facilities = 0;
592 return 0;
593 }
594 m = m_gethdr(M_WAIT, MT_DATA);
595 buf = mtod(m, caddr_t);
596 ptr = buf;
597
598 /* ptr now points to facil length (len of whole facil field in OCTETS */
599 facil_len = ptr++;
600 m->m_len = 0;
601 pk_build_facilities(m, &lcp->lcd_faddr, 0);
602
603 #ifdef ARGO_DEBUG
604 if (argo_debug[D_CADDR]) {
605 printf("make_partial calling: ptr 0x%x, len 0x%x\n", ptr,
606 isop->isop_laddr->siso_addr.isoa_len);
607 }
608 #endif
609 if (cons_use_facils) {
610 *ptr++ = 0; /* Marker to separate X.25 facitilies from
611 * CCITT ones */
612 *ptr++ = 0x0f;
613 *ptr = 0xcb; /* calling facility code */
614 ptr++;
615 ptr++; /* leave room for facil param len (in OCTETS
616 * + 1) */
617 ptr++; /* leave room for the facil param len (in
618 * nibbles), high two bits of which indicate
619 * full/partial NSAP */
620 len = isop->isop_laddr->siso_addr.isoa_len;
621 bcopy(isop->isop_laddr->siso_data, ptr, len);
622 *(ptr - 2) = len + 1; /* facil param len in octets */
623 *(ptr - 1) = len << 1; /* facil param len in nibbles */
624 ptr += len;
625
626 #ifdef ARGO_DEBUG
627 if (argo_debug[D_CADDR]) {
628 printf("make_partial called: ptr 0x%x, len 0x%x\n", ptr,
629 isop->isop_faddr->siso_addr.isoa_len);
630 }
631 #endif
632 *ptr = 0xc9; /* called facility code */
633 ptr++;
634 ptr++; /* leave room for facil param len (in OCTETS
635 * + 1) */
636 ptr++; /* leave room for the facil param len (in
637 * nibbles), high two bits of which indicate
638 * full/partial NSAP */
639 len = isop->isop_faddr->siso_nlen;
640 bcopy(isop->isop_faddr->siso_data, ptr, len);
641 *(ptr - 2) = len + 1; /* facil param len = addr len + 1 for
642 * each of these two length fields,
643 * in octets */
644 *(ptr - 1) = len << 1; /* facil param len in nibbles */
645 ptr += len;
646
647 }
648 *facil_len = ptr - facil_len - 1;
649 if (*facil_len > MAX_FACILITIES)
650 return E_CO_PNA_LONG;
651
652 buflen = (int) (ptr - buf);
653
654 #ifdef ARGO_DEBUG
655 if (argo_debug[D_CDUMP_REQ]) {
656 int i;
657
658 printf("ECN_CONNECT DATA buf 0x%x len %d (0x%x)\n",
659 buf, buflen, buflen);
660 for (i = 0; i < buflen;) {
661 printf("+%d: %x %x %x %x %x %x %x %x\n",
662 i,
663 *(buf + i), *(buf + i + 1), *(buf + i + 2), *(buf + i + 3),
664 *(buf + i + 4), *(buf + i + 5), *(buf + i + 6), *(buf + i + 7));
665 i += 8;
666 }
667 }
668 #endif
669 #ifdef ARGO_DEBUG
670 if (argo_debug[D_CADDR]) {
671 printf("make_partial returns buf 0x%x size 0x%x bytes\n",
672 mtod(m, caddr_t), buflen);
673 }
674 #endif
675
676 if (buflen > MHLEN)
677 return E_CO_PNA_LONG;
678
679 m->m_pkthdr.len = m->m_len = buflen;
680 lcp->lcd_facilities = m;
681 return 0;
682 }
683
684 /*
685 * NAME: NSAPtoDTE()
686 * CALLED FROM:
687 * make_partial_x25_packet()
688 * FUNCTION and ARGUMENTS:
689 * get a DTE address from an NSAP-address (struct sockaddr_iso)
690 * (dst_octet) is the octet into which to begin stashing the DTE addr
691 * (dst_nibble) takes 0 or 1. 1 means begin filling in the DTE addr
692 * in the high-order nibble of dst_octet. 0 means low-order nibble.
693 * (addr) is the NSAP-address
694 * (flag) is true if the transport suffix is to become the
695 * last two digits of the DTE address
696 * A DTE address is a series of ASCII digits
697 *
698 * A DTE address may have leading zeros. The are significant.
699 * 1 digit per nibble, may be an odd number of nibbles.
700 *
701 * An NSAP-address has the DTE address in the IDI. Leading zeros are
702 * significant. Trailing hex f indicates the end of the DTE address.
703 * The IDI is a series of BCD digits, one per nibble.
704 *
705 * RETURNS
706 * # significant digits in the DTE address, -1 if error.
707 */
708
709 Static int
710 NSAPtoDTE(siso, sx25)
711 struct sockaddr_iso *siso;
712 struct sockaddr_x25 *sx25;
713 {
714 int dtelen = -1;
715
716 #ifdef ARGO_DEBUG
717 if (argo_debug[D_CADDR]) {
718 printf("NSAPtoDTE: nsap: %s\n",
719 clnp_iso_addrp(&siso->siso_addr));
720 }
721 #endif
722
723 if (siso->siso_data[0] == AFI_37) {
724 char *out = sx25->x25_addr;
725 char *in = siso->siso_data + 1;
726 int nibble;
727 char *lim = siso->siso_data + siso->siso_nlen;
728 char *olim = out + 15;
729 int lowNibble = 0;
730
731 while (in < lim) {
732 nibble = ((lowNibble ? *in++ : (*in >> 4)) & 0xf) | 0x30;
733 lowNibble ^= 1;
734 if (nibble != 0x3f && out < olim)
735 *out++ = nibble;
736 }
737 dtelen = out - sx25->x25_addr;
738 *out++ = 0;
739 } else {
740 /*
741 * error = iso_8208snparesolve(addr, x121string,
742 * &x121strlen);
743 */
744 struct rtentry *rt;
745 extern struct sockaddr_iso blank_siso;
746 struct sockaddr_iso nsiso;
747
748 nsiso = blank_siso;
749 bcopy(nsiso.siso_data, siso->siso_data,
750 nsiso.siso_nlen = siso->siso_nlen);
751 if ((rt = rtalloc1((struct sockaddr *) &nsiso, 1)) != NULL) {
752 struct sockaddr_x25 *sxx =
753 (struct sockaddr_x25 *) rt->rt_gateway;
754 char *in = sxx->x25_addr;
755
756 rt->rt_use--;
757 if (sxx && sxx->x25_family == AF_CCITT) {
758 bcopy(sx25->x25_addr, sxx->x25_addr, sizeof(sx25->x25_addr));
759 while (*in++) {
760 }
761 dtelen = in - sxx->x25_addr;
762 }
763 }
764 }
765 return dtelen;
766 }
767
768 /*
769 * NAME: FACILtoNSAP()
770 * CALLED FROM:
771 * parse_facil()
772 * FUNCTION and ARGUMENTS:
773 * Creates and NSAP in the sockaddr_iso (addr) from the
774 * x.25 facility found at buf - 1.
775 * RETURNS:
776 * 0 if ok, -1 if error.
777 */
778
779 Static int
780 FACILtoNSAP(addr, buf)
781 u_char *buf;
782 struct sockaddr_iso *addr;
783 {
784 int len_in_nibbles = *++buf & 0x3f;
785 u_char buf_len = (len_in_nibbles + 1) >> 1;; /* in bytes */
786
787 #ifdef ARGO_DEBUG
788 if (argo_debug[D_CADDR]) {
789 printf("FACILtoNSAP( 0x%x, 0x%x, 0x%x )\n",
790 buf, buf_len, addr);
791 }
792 #endif
793
794 len_in_nibbles = *buf & 0x3f;
795 /*
796 * despite the fact that X.25 makes us put a length in nibbles here,
797 * the NSAP-addrs are always in full octets
798 */
799 switch (*buf++ & 0xc0) {
800 case 0:
801 /* Entire OSI NSAP address */
802 bcopy((caddr_t) buf, addr->siso_data, addr->siso_nlen = buf_len);
803 break;
804
805 case 40:
806 /* Partial OSI NSAP address, assume trailing */
807 if (buf_len + addr->siso_nlen > sizeof(addr->siso_addr))
808 return -1;
809 bcopy((caddr_t) buf, TSEL(addr), buf_len);
810 addr->siso_nlen += buf_len;
811 break;
812
813 default:
814 /*
815 * Rather than blow away the connection, just ignore and use
816 * NSAP from DTE
817 */ ;
818 }
819 return 0;
820 }
821
822 Static void
823 init_siso(siso)
824 struct sockaddr_iso *siso;
825 {
826 siso->siso_len = sizeof(*siso);
827 siso->siso_family = AF_ISO;
828 siso->siso_data[0] = AFI_37;
829 siso->siso_nlen = 8;
830 }
831
832 /*
833 * NAME: DTEtoNSAP()
834 * CALLED FROM:
835 * parse_facil()
836 * FUNCTION and ARGUMENTS:
837 * Creates a type 37 NSAP in the sockaddr_iso (addr)
838 * from a DTE address found in a sockaddr_x25.
839 *
840 * RETURNS:
841 * 0 if ok; E* otherwise.
842 */
843
844 Static int
845 DTEtoNSAP(addr, sx)
846 struct sockaddr_iso *addr;
847 struct sockaddr_x25 *sx;
848 {
849 char *in, *out;
850 int first;
851 int pad_tail = 0;
852 int src_len;
853
854
855 init_siso(addr);
856 in = sx->x25_addr;
857 src_len = strlen(in);
858 addr->siso_nlen = (src_len + 3) / 2;
859 out = addr->siso_data;
860 *out++ = 0x37;
861 if (src_len & 1) {
862 pad_tail = 0xf;
863 src_len++;
864 }
865 for (first = 0; src_len > 0; src_len--) {
866 first |= 0xf & *in++;
867 if (src_len & 1) {
868 *out++ = first;
869 first = 0;
870 } else
871 first <<= 4;
872 }
873 if (pad_tail)
874 out[-1] |= 0xf;
875 return 0; /* ok */
876 }
877
878 /*
879 * FUNCTION and ARGUMENTS:
880 * parses (buf_len) bytes beginning at (buf) and finds
881 * a called nsap, a calling nsap, and protocol identifier.
882 * RETURNS:
883 * 0 if ok, E* otherwise.
884 */
885
886 Static int
887 parse_facil(lcp, isop, buf, buf_len)
888 caddr_t buf;
889 u_char buf_len;/* in bytes */
890 struct isopcb *isop;
891 struct pklcd *lcp;
892 {
893 int i;
894 u_char *ptr = (u_char *) buf;
895 u_char *facil_lim;
896 int facil_param_len = 0, facil_len;
897
898 #ifdef ARGO_DEBUG
899 if (argo_debug[D_CADDR]) {
900 printf("parse_facil(0x%x, 0x%x, 0x%x, 0x%x)\n",
901 lcp, isop, buf, buf_len);
902 dump_buf(buf, buf_len);
903 }
904 #endif
905
906 /*
907 * find the beginnings of the facility fields in buf by skipping over
908 * the called & calling DTE addresses i <- # nibbles in called + #
909 * nibbles in calling i += 1 so that an odd nibble gets rounded up to
910 * even before dividing by 2, then divide by two to get # octets
911 */
912 i = (int) (*ptr >> 4) + (int) (*ptr & 0xf);
913 i++;
914 ptr += i >> 1;
915 ptr++; /* plus one for the DTE lengths byte */
916
917 /* ptr now is at facil_length field */
918 facil_len = *ptr++;
919 facil_lim = ptr + facil_len;
920 #ifdef ARGO_DEBUG
921 if (argo_debug[D_CADDR]) {
922 printf("parse_facils: facil length is 0x%x\n", (int) facil_len);
923 }
924 #endif
925
926 while (ptr < facil_lim) {
927 /* get NSAP addresses from facilities */
928 switch (*ptr++) {
929 case 0xcb:
930 /* calling NSAP */
931 facil_param_len = FACILtoNSAP(isop->isop_faddr, ptr);
932 break;
933 case 0xc9:
934 /* called NSAP */
935 facil_param_len = FACILtoNSAP(isop->isop_laddr, ptr);
936 break;
937
938 /* from here to default are legit cases that I ignore */
939 /* variable length */
940 case 0xca: /* end-to-end transit delay negot */
941 case 0xc6: /* network user id */
942 case 0xc5: /* charging info : indicating monetary unit */
943 case 0xc2: /* charging info : indicating segment count */
944 case 0xc1: /* charging info : indicating call duration */
945 case 0xc4: /* RPOA extended format */
946 case 0xc3: /* call redirection notification */
947 facil_param_len = 0;
948 break;
949
950 /* 1 octet */
951 case 0x0a: /* min. throughput class negot */
952 case 0x02: /* throughput class */
953 case 0x03:
954 case 0x47: /* CUG shit */
955 case 0x0b: /* expedited data negot */
956 case 0x01: /* Fast select or reverse charging (example
957 * of intelligent protocol design) */
958 case 0x04: /* charging info : requesting service */
959 case 0x08: /* called line addr modified notification */
960 case 0x00: /* marker to indicate beginning of CCITT
961 * facils */
962 facil_param_len = 1;
963 break;
964
965 /* any 2 octets */
966 case 0x42: /* pkt size */
967 case 0x43: /* win size */
968 case 0x44: /* RPOA basic format */
969 case 0x41: /* bilateral CUG shit */
970 case 0x49: /* transit delay selection and indication */
971 facil_param_len = 2;
972 break;
973
974 default:
975 printf(
976 "BOGUS FACILITY CODE facil_lim 0x%x facil_len %d, ptr 0x%x *ptr 0x%x\n",
977 facil_lim, facil_len, ptr - 1, ptr[-1]);
978 /*
979 * facil that we don't handle return E_CO_HLI_REJI;
980 */
981 switch (ptr[-1] & 0xc0) {
982 case 0x00:
983 facil_param_len = 1;
984 break;
985 case 0x40:
986 facil_param_len = 2;
987 break;
988 case 0x80:
989 facil_param_len = 3;
990 break;
991 case 0xc0:
992 facil_param_len = 0;
993 break;
994 }
995 }
996 if (facil_param_len == -1)
997 return E_CO_REG_ICDA;
998 if (facil_param_len == 0) /* variable length */
999 facil_param_len = (int) *ptr++; /* 1 + the real facil
1000 * param */
1001 ptr += facil_param_len;
1002 }
1003 return 0;
1004 }
1005
1006 #endif /* TPCONS */
Cache object: fd52d8826d761a3f39b29030b97b02b4
|