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