1 /* $NetBSD: tp_iso.c,v 1.33 2009/03/18 15:14:32 cegger Exp $ */
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
31 * @(#)tp_iso.c 8.2 (Berkeley) 9/22/94
34 /***********************************************************
35 Copyright IBM Corporation 1987
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.
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
55 ******************************************************************/
58 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
61 * Here is where you find the iso-dependent code. We've tried keep all
62 * net-level and (primarily) address-family-dependent stuff out of the tp
63 * source, and everthing here is reached indirectly through a switch table
64 * (struct nl_protosw *) tpcb->tp_nlproto (see tp_pcb.c). The routines here
65 * are: iso_getsufx: gets transport suffix out of an isopcb structure.
66 * iso_putsufx: put transport suffix into an isopcb structure.
67 * iso_putnetaddr: put a whole net addr into an isopcb. iso_getnetaddr: get a
68 * whole net addr from an isopcb. iso_cmpnetaddr: compare a whole net addr
69 * from an isopcb. iso_recycle_suffix: clear suffix for reuse in isopcb
70 * tpclnp_ctlinput: handle ER CNLPdu : icmp-like stuff tpclnp_mtu: figure out
71 * what size tpdu to use tpclnp_input: take a pkt from clnp, strip off its
72 * clnp header, give to tp tpclnp_output_dg: package a pkt for clnp given 2
73 * addresses & some data tpclnp_output: package a pkt for clnp given an
77 #include <sys/cdefs.h>
78 __KERNEL_RCSID(0, "$NetBSD: tp_iso.c,v 1.33 2009/03/18 15:14:32 cegger Exp $");
83 #include <sys/param.h>
84 #include <sys/socket.h>
85 #include <sys/socketvar.h>
86 #include <sys/domain.h>
87 #include <sys/malloc.h>
89 #include <sys/errno.h>
91 #include <sys/protosw.h>
92 #include <sys/systm.h>
93 #include <sys/kernel.h>
96 #include <net/route.h>
98 #include <netiso/argo_debug.h>
99 #include <netiso/tp_param.h>
100 #include <netiso/tp_stat.h>
101 #include <netiso/tp_pcb.h>
102 #include <netiso/tp_trace.h>
103 #include <netiso/tp_tpdu.h>
104 #include <netiso/tp_clnp.h>
105 #include <netiso/tp_var.h>
106 #include <netiso/cltp_var.h>
107 #include <netiso/idrp_var.h>
109 #include <machine/stdarg.h>
113 * pr_usrreq() on PRU_BIND, PRU_CONNECT, PRU_ACCEPT, and PRU_PEERADDR
114 * FUNCTION, ARGUMENTS:
115 * The argument (which) takes the value TP_LOCAL or TP_FOREIGN.
119 iso_getsufx(void *v
, u_short
*lenp
, void *data_out
, int which
)
121 struct isopcb
*isop
= v
;
122 struct sockaddr_iso
*addr
= 0;
126 addr
= isop
->isop_laddr
;
130 addr
= isop
->isop_faddr
;
133 bcopy(TSEL(addr
), data_out
, (*lenp
= addr
->siso_tlen
));
137 * CALLED FROM: tp_newsocket(); i.e., when a connection is being established
138 * by an incoming CR_TPDU.
140 * FUNCTION, ARGUMENTS: Put a transport suffix (found in name) into an isopcb
141 * structure (isop). The argument (which) takes the value TP_LOCAL or
145 iso_putsufx(void *v
, void *sufxloc
, int sufxlen
, int which
)
147 struct isopcb
*isop
= v
;
148 struct sockaddr_iso
**dst
, *backup
;
149 struct sockaddr_iso
*addr
;
158 dst
= &isop
->isop_laddr
;
159 backup
= &isop
->isop_sladdr
;
163 dst
= &isop
->isop_faddr
;
164 backup
= &isop
->isop_sfaddr
;
166 if ((addr
= *dst
) == 0) {
167 addr
= *dst
= backup
;
171 printf("iso_putsufx on un-initialized isopcb\n");
173 len
= sufxlen
+ addr
->siso_nlen
+
174 (sizeof(*addr
) - sizeof(addr
->siso_data
));
175 if (addr
== backup
) {
176 if (len
> sizeof(*addr
)) {
177 m
= m_getclr(M_DONTWAIT
, MT_SONAME
);
180 addr
= *dst
= mtod(m
, struct sockaddr_iso
*);
185 memcpy(WRITABLE_TSEL(addr
), sufxloc
, sufxlen
);
186 addr
->siso_tlen
= sufxlen
;
187 addr
->siso_len
= len
;
192 * tp.trans whenever we go into REFWAIT state.
193 * FUNCTION and ARGUMENT:
194 * Called when a ref is frozen, to allow the suffix to be reused.
195 * (isop) is the net level pcb. This really shouldn't have to be
196 * done in a NET level pcb but... for the internet world that just
197 * the way it is done in BSD...
198 * The alternative is to have the port unusable until the reference
202 iso_recycle_tsuffix(void *v
)
204 struct isopcb
*isop
= v
;
205 isop
->isop_laddr
->siso_tlen
= isop
->isop_faddr
->siso_tlen
= 0;
210 * tp_newsocket(); i.e., when a connection is being established by an
213 * FUNCTION and ARGUMENTS:
214 * Copy a whole net addr from a struct sockaddr (name).
215 * into an isopcb (isop).
216 * The argument (which) takes values TP_LOCAL or TP_FOREIGN
219 iso_putnetaddr(void *v
, struct sockaddr
*nm
, int which
)
221 struct isopcb
*isop
= v
;
222 struct sockaddr_iso
*name
= (struct sockaddr_iso
*) nm
;
223 struct sockaddr_iso
**sisop
, *backup
;
224 struct sockaddr_iso
*siso
;
228 printf("iso_putnetaddr: should panic\n");
231 sisop
= &isop
->isop_laddr
;
232 backup
= &isop
->isop_sladdr
;
235 sisop
= &isop
->isop_faddr
;
236 backup
= &isop
->isop_sfaddr
;
238 siso
= ((*sisop
== 0) ? (*sisop
= backup
) : *sisop
);
240 if (argo_debug
[D_TPISO
]) {
241 printf("ISO_PUTNETADDR\n");
242 dump_isoaddr(isop
->isop_faddr
);
245 siso
->siso_addr
= name
->siso_addr
;
250 * tp_input() when a connection is being established by an
251 * incoming CR_TPDU, and considered for interception.
253 * FUNCTION and ARGUMENTS:
254 * compare a whole net addr from a struct sockaddr (name),
255 * with that implicitly stored in an isopcb (isop).
256 * The argument (which) takes values TP_LOCAL or TP_FOREIGN.
259 iso_cmpnetaddr(void *v
, struct sockaddr
*nm
, int which
)
261 struct isopcb
*isop
= v
;
262 struct sockaddr_iso
*name
= (struct sockaddr_iso
*) nm
;
263 struct sockaddr_iso
**sisop
, *backup
;
264 struct sockaddr_iso
*siso
;
268 printf("iso_cmpnetaddr: should panic\n");
271 sisop
= &isop
->isop_laddr
;
272 backup
= &isop
->isop_sladdr
;
275 sisop
= &isop
->isop_faddr
;
276 backup
= &isop
->isop_sfaddr
;
278 siso
= ((*sisop
== 0) ? (*sisop
= backup
) : *sisop
);
280 if (argo_debug
[D_TPISO
]) {
281 printf("ISO_CMPNETADDR\n");
285 if (name
->siso_tlen
&& memcmp(TSEL(name
), TSEL(siso
), name
->siso_tlen
))
287 return (memcmp((void *) name
->siso_data
,
288 (void *) siso
->siso_data
, name
->siso_nlen
) == 0);
293 * pr_usrreq() PRU_SOCKADDR, PRU_ACCEPT, PRU_PEERADDR
294 * FUNCTION and ARGUMENTS:
295 * Copy a whole net addr from an isopcb (isop) into
296 * a struct sockaddr (name).
297 * The argument (which) takes values TP_LOCAL or TP_FOREIGN.
301 iso_getnetaddr(void *v
, struct mbuf
*name
, int which
)
303 struct inpcb
*inp
= v
;
304 struct isopcb
*isop
= (struct isopcb
*) inp
;
305 struct sockaddr_iso
*siso
=
306 (which
== TP_LOCAL
? isop
->isop_laddr
: isop
->isop_faddr
);
308 bcopy((void *) siso
, mtod(name
, void *),
309 (unsigned) (name
->m_len
= siso
->siso_len
));
317 * tp_route_to() on incoming CR, CC, and pr_usrreq() for PRU_CONNECT
319 * FUNCTION, ARGUMENTS, and RETURN VALUE:
321 * Perform subnetwork dependent part of determining MTU information.
322 * It appears that setting a double pointer to the rtentry associated with
323 * the destination, and returning the header size for the network protocol
327 * Sets tp_routep pointer in pcb.
334 struct tp_pcb
*tpcb
= v
;
335 struct isopcb
*isop
= (struct isopcb
*) tpcb
->tp_npcb
;
338 if (argo_debug
[D_CONN
]) {
339 printf("tpclnp_mtu(tpcb %p)\n", tpcb
);
342 tpcb
->tp_routep
= &isop
->isop_route
;
343 if (tpcb
->tp_netservice
== ISO_CONS
)
345 return (sizeof(struct clnp_fixed
) + sizeof(struct clnp_segment
) +
346 2 * sizeof(struct iso_addr
));
352 * FUNCTION and ARGUMENTS:
353 * Take a packet(m0) from tp and package it so that clnp will accept it.
354 * This means prepending space for the clnp header and filling in a few
356 * isop is the isopcb structure; datalen is the length of the data in the
359 * whatever (E*) is returned form the net layer output routine.
363 tpclnp_output(struct mbuf
*m0
, ...)
371 datalen
= va_arg(ap
, int);
372 isop
= va_arg(ap
, struct isopcb
*);
373 nochksum
= va_arg(ap
, int);
376 IncStat(ts_tpdu_sent
);
379 if (argo_debug
[D_TPISO
]) {
380 struct tpdu
*hdr
= mtod(m0
, struct tpdu
*);
383 "abt to call clnp_output: datalen 0x%x, hdr.li 0x%x, hdr.dutype 0x%x nocsum x%x dst addr:\n",
385 (int) hdr
->tpdu_li
, (int) hdr
->tpdu_type
, nochksum
);
386 dump_isoaddr(isop
->isop_faddr
);
387 printf("\nsrc addr:\n");
388 dump_isoaddr(isop
->isop_laddr
);
389 dump_mbuf(m0
, "at tpclnp_output");
394 clnp_output(m0
, isop
, datalen
, /* flags */ nochksum
? CLNP_NO_CKSUM
: 0);
400 * FUNCTION and ARGUMENTS:
401 * This is a copy of tpclnp_output that takes the addresses
402 * instead of a pcb. It's used by the tp_error_emit, when we
403 * don't have an iso_pcb with which to call the normal output rtn.
406 * whatever (E*) is returned form the net layer output routine.
410 tpclnp_output_dg(struct mbuf
*m0
, ...)
412 struct isopcb tmppcb
;
416 struct iso_addr
*laddr
, *faddr
;
422 datalen
= va_arg(ap
, int);
423 laddr
= va_arg(ap
, struct iso_addr
*);
424 faddr
= va_arg(ap
, struct iso_addr
*);
425 ro
= va_arg(ap
, struct route
*);
426 nochksum
= va_arg(ap
, int);
430 if (argo_debug
[D_TPISO
]) {
431 printf("tpclnp_output_dg datalen 0x%x m0 %p\n", datalen
, m0
);
436 * Fill in minimal portion of isopcb so that clnp can send the
439 memset((void *) & tmppcb
, 0, sizeof(tmppcb
));
440 tmppcb
.isop_laddr
= &tmppcb
.isop_sladdr
;
441 tmppcb
.isop_laddr
->siso_addr
= *laddr
;
442 tmppcb
.isop_faddr
= &tmppcb
.isop_sfaddr
;
443 tmppcb
.isop_faddr
->siso_addr
= *faddr
;
446 if (argo_debug
[D_TPISO
]) {
447 printf("tpclnp_output_dg faddr: \n");
448 dump_isoaddr(&tmppcb
.isop_sfaddr
);
449 printf("\ntpclnp_output_dg laddr: \n");
450 dump_isoaddr(&tmppcb
.isop_sladdr
);
456 * Do not use packet cache since this is a one shot error packet
458 flags
= (CLNP_NOCACHE
| (nochksum
? CLNP_NO_CKSUM
: 0));
460 IncStat(ts_tpdu_sent
);
462 err
= clnp_output(m0
, &tmppcb
, datalen
, flags
);
465 * Free route allocated by clnp (if the route was indeed allocated)
467 rtcache_free(&tmppcb
.isop_route
);
473 * clnp's input routine, indirectly through the protosw.
474 * FUNCTION and ARGUMENTS:
475 * Take a packet (m) from clnp, strip off the clnp header and give it to tp
479 tpclnp_input(struct mbuf
*m
, ...)
481 struct sockaddr_iso
*src
, *dst
;
482 int clnp_len
, ce_bit
;
483 void (*input
) (struct mbuf
*, ...) = tp_input
;
487 src
= va_arg(ap
, struct sockaddr_iso
*);
488 dst
= va_arg(ap
, struct sockaddr_iso
*);
489 clnp_len
= va_arg(ap
, int);
490 ce_bit
= va_arg(ap
, int);
493 IncStat(ts_pkt_rcvd
);
496 if (argo_debug
[D_TPINPUT
]) {
497 printf("tpclnp_input: m %p clnp_len 0x%x\n", m
, clnp_len
);
498 dump_mbuf(m
, "at tpclnp_input");
502 * CLNP gives us an mbuf chain WITH the clnp header pulled up,
503 * and the length of the clnp header.
504 * First, strip off the Clnp header. leave the mbuf there for the
505 * pullup that follows.
507 m
->m_len
-= clnp_len
;
508 m
->m_data
+= clnp_len
;
509 m
->m_pkthdr
.len
-= clnp_len
;
510 /* XXXX: should probably be in clnp_input */
511 switch (dst
->siso_data
[dst
->siso_nlen
- 1]) {
513 if (m
->m_len
== 0 && (m
= m_pullup(m
, 1)) == 0)
515 if (*(mtod(m
, u_char
*)) == ISO10747_IDRP
) {
516 idrp_input(m
, src
, dst
);
523 if (mtod(m
, u_char
*)[1] == UD_TPDU_type
)
527 if (argo_debug
[D_TPINPUT
]) {
528 dump_mbuf(m
, "after tpclnp_input both pullups");
533 if (argo_debug
[D_TPISO
]) {
534 printf("calling %sinput : src %p, dst %p, src addr:\n",
535 (input
== tp_input
? "tp_" : "clts_"), src
, dst
);
537 printf(" dst addr:\n");
542 (*input
) (m
, (struct sockaddr
*) src
, (struct sockaddr
*) dst
, 0,
543 tpclnp_output_dg
, ce_bit
);
546 if (argo_debug
[D_QUENCH
]) {{
550 if (now
.tv_usec
& 0x4 && now
.tv_usec
& 0x40) {
551 printf("tpclnp_input: FAKING %s\n",
552 tp_stat
.ts_pkt_rcvd
& 0x1 ? "QUENCH" : "QUENCH2");
553 if (tp_stat
.ts_pkt_rcvd
& 0x1)
554 tpclnp_ctlinput(PRC_QUENCH
,
558 tpclnp_ctlinput(PRC_QUENCH2
,
569 iso_rtchange(struct isopcb
*pcb
)
577 * FUNCTION and ARGUMENTS:
578 * find the tpcb pointer and pass it to tp_quench
581 tpiso_decbit(struct isopcb
*isop
)
583 tp_quench((struct inpcb
*) isop
->isop_socket
->so_pcb
, PRC_QUENCH2
);
588 * FUNCTION and ARGUMENTS:
589 * find the tpcb pointer and pass it to tp_quench
592 tpiso_quench(struct isopcb
*isop
)
594 tp_quench((struct inpcb
*) isop
->isop_socket
->so_pcb
, PRC_QUENCH
);
599 * The network layer through the protosw table.
600 * FUNCTION and ARGUMENTS:
601 * When clnp an ICMP-like msg this gets called.
602 * It either returns an error status to the user or
603 * it causes all connections on this address to be aborted
604 * by calling the appropriate xx_notify() routine.
605 * (cmd) is the type of ICMP error.
606 * (siso) is the address of the guy who sent the ER CLNPDU
609 tpclnp_ctlinput(int cmd
, const struct sockaddr
*sa
, void *dummy
)
611 const struct sockaddr_iso
*siso
= (const struct sockaddr_iso
*)sa
;
614 if (argo_debug
[D_TPINPUT
]) {
615 printf("tpclnp_ctlinput1: cmd 0x%x addr: \n", cmd
);
620 if ((unsigned)cmd
>= PRC_NCMDS
)
622 if (siso
->siso_family
!= AF_ISO
)
627 iso_pcbnotify(&tp_isopcb
, siso
, 0, tpiso_decbit
);
631 iso_pcbnotify(&tp_isopcb
, siso
, 0, tpiso_quench
);
634 case PRC_TIMXCEED_REASS
:
636 iso_pcbnotify(&tp_isopcb
, siso
, 0, tpiso_reset
);
639 case PRC_HOSTUNREACH
:
640 case PRC_UNREACH_NET
:
643 iso_pcbnotify(&tp_isopcb
, siso
,
644 (int) isoctlerrmap
[cmd
], iso_rtchange
);
650 case PRC_UNREACH_HOST:
651 case PRC_UNREACH_PROTOCOL:
652 case PRC_UNREACH_PORT:
653 case PRC_UNREACH_NEEDFRAG:
654 case PRC_UNREACH_SRCFAIL:
655 case PRC_REDIRECT_NET:
656 case PRC_REDIRECT_HOST:
657 case PRC_REDIRECT_TOSNET:
658 case PRC_REDIRECT_TOSHOST:
659 case PRC_TIMXCEED_INTRANS:
662 iso_pcbnotify(&tp_isopcb
, siso
, (int) isoctlerrmap
[cmd
], tpiso_abort
);
668 * XXX - Variant which is called by clnp_er.c with an isoaddr rather
669 * than a sockaddr_iso.
672 static struct sockaddr_iso siso
= {
673 .siso_len
= sizeof(siso
),
674 .siso_family
= AF_ISO
,
677 tpclnp_ctlinput1(int cmd
, struct iso_addr
*isoa
)
679 memset((void *) & siso
.siso_addr
, 0, sizeof(siso
.siso_addr
));
680 bcopy((void *) isoa
, (void *) & siso
.siso_addr
, isoa
->isoa_len
);
681 tpclnp_ctlinput(cmd
, (struct sockaddr
*) &siso
, NULL
);
685 * These next 2 routines are
687 * xxx_notify() from tp_ctlinput() when
688 * net level gets some ICMP-equiv. type event.
689 * FUNCTION and ARGUMENTS:
690 * Cause the connection to be aborted with some sort of error
691 * reason indicating that the network layer caused the abort.
692 * Fakes an ER TPDU so we can go through the driver.
693 * abort always aborts the TP connection.
694 * reset may or may not, depending on the TP class that's in use.
697 tpiso_abort(struct isopcb
*isop
)
702 if (argo_debug
[D_CONN
]) {
703 printf("tpiso_abort %p\n", isop
);
706 e
.ev_number
= ER_TPDU
;
707 e
.TPDU_ATTR(ER
).e_reason
= ECONNABORTED
;
708 tp_driver((struct tp_pcb
*) isop
->isop_socket
->so_pcb
, &e
);
712 tpiso_reset(struct isopcb
*isop
)
716 e
.ev_number
= T_NETRESET
;
717 tp_driver((struct tp_pcb
*) isop
->isop_socket
->so_pcb
, &e
);