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