]>
git.saurik.com Git - apple/xnu.git/blob - bsd/netiso/iso_pcb.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 * Copyright (c) 1991, 1993
24 * The Regents of the University of California. All rights reserved.
26 * Redistribution and use in source and binary forms, with or without
27 * modification, are permitted provided that the following conditions
29 * 1. Redistributions of source code must retain the above copyright
30 * notice, this list of conditions and the following disclaimer.
31 * 2. Redistributions in binary form must reproduce the above copyright
32 * notice, this list of conditions and the following disclaimer in the
33 * documentation and/or other materials provided with the distribution.
34 * 3. All advertising materials mentioning features or use of this software
35 * must display the following acknowledgement:
36 * This product includes software developed by the University of
37 * California, Berkeley and its contributors.
38 * 4. Neither the name of the University nor the names of its contributors
39 * may be used to endorse or promote products derived from this software
40 * without specific prior written permission.
42 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
43 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
44 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
45 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
46 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
47 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
48 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
49 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
50 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
51 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * @(#)iso_pcb.c 8.1 (Berkeley) 6/10/93
57 /***********************************************************
58 Copyright IBM Corporation 1987
62 Permission to use, copy, modify, and distribute this software and its
63 documentation for any purpose and without fee is hereby granted,
64 provided that the above copyright notice appear in all copies and that
65 both that copyright notice and this permission notice appear in
66 supporting documentation, and that the name of IBM not be
67 used in advertising or publicity pertaining to distribution of the
68 software without specific, written prior permission.
70 IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
71 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
72 IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
73 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
74 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
75 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
78 ******************************************************************/
81 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
84 * Iso address family net-layer(s) pcb stuff. NEH 1/29/87
89 #include <sys/param.h>
90 #include <sys/systm.h>
92 #include <sys/socket.h>
93 #include <sys/socketvar.h>
94 #include <sys/errno.h>
96 #include <netiso/argo_debug.h>
97 #include <netiso/iso.h>
98 #include <netiso/clnp.h>
99 #include <netinet/in_systm.h>
101 #include <net/route.h>
102 #include <netiso/iso_pcb.h>
103 #include <netiso/iso_var.h>
104 #include <sys/protosw.h>
107 #include <netccitt/x25.h>
108 #include <netccitt/pk.h>
109 #include <netccitt/pk_var.h>
112 #define PCBNULL (struct isopcb *)0
113 struct iso_addr zeroiso_addr
= {
119 * FUNCTION: iso_pcballoc
121 * PURPOSE: creates an isopcb structure in an mbuf,
122 * with socket (so), and
123 * puts it in the queue with head (head)
125 * RETURNS: 0 if OK, ENOBUFS if can't alloc the necessary mbuf
128 iso_pcballoc(so
, head
)
132 register struct isopcb
*isop
;
135 printf("iso_pcballoc(so 0x%x)\n", so
);
137 MALLOC(isop
, struct isopcb
*, sizeof(*isop
), M_PCB
, M_NOWAIT
);
140 bzero((caddr_t
)isop
, sizeof(*isop
));
141 isop
->isop_head
= head
;
142 isop
->isop_socket
= so
;
145 so
->so_pcb
= (caddr_t
)isop
;
150 * FUNCTION: iso_pcbbind
152 * PURPOSE: binds the address given in *(nam) to the socket
153 * specified by the isopcb in *(isop)
154 * If the given address is zero, it makes sure the
155 * address isn't already in use and if it's got a network
156 * portion, we look for an interface with that network
157 * address. If the address given is zero, we allocate
158 * a port and stuff it in the (nam) structure.
160 * RETURNS: errno E* or 0 if ok.
162 * SIDE EFFECTS: increments head->isop_lport if it allocates a port #
166 #define satosiso(sa) ((struct sockaddr_iso *)(sa))
168 iso_pcbbind(isop
, nam
)
169 register struct isopcb
*isop
;
172 register struct isopcb
*head
= isop
->isop_head
;
173 register struct sockaddr_iso
*siso
;
174 struct iso_ifaddr
*ia
;
181 printf("iso_pcbbind(isop 0x%x, nam 0x%x)\n", isop
, nam
);
184 if (iso_ifaddr
== 0) /* any interfaces attached? */
185 return EADDRNOTAVAIL
;
186 if (isop
->isop_laddr
) /* already bound */
188 if(nam
== (struct mbuf
*)0) {
189 isop
->isop_laddr
= &isop
->isop_sladdr
;
190 isop
->isop_sladdr
.siso_len
= sizeof(struct sockaddr_iso
);
191 isop
->isop_sladdr
.siso_family
= AF_ISO
;
192 isop
->isop_sladdr
.siso_tlen
= 2;
193 isop
->isop_sladdr
.siso_nlen
= 0;
194 isop
->isop_sladdr
.siso_slen
= 0;
195 isop
->isop_sladdr
.siso_plen
= 0;
198 siso
= mtod(nam
, struct sockaddr_iso
*);
200 printf("iso_pcbbind(name len 0x%x)\n", nam
->m_len
);
201 printf("The address is %s\n", clnp_iso_addrp(&siso
->siso_addr
));
204 * We would like sort of length check but since some OSI addrs
205 * do not have fixed length, we can't really do much.
206 * The ONLY thing we can say is that an osi addr has to have
207 * at LEAST an afi and one more byte and had better fit into
209 * However, in fact the size of the whole thing is a struct
210 * sockaddr_iso, so probably this is what we should check for.
212 if( (nam
->m_len
< 2) || (nam
->m_len
< siso
->siso_len
)) {
215 if (siso
->siso_nlen
) {
216 /* non-zero net addr- better match one of our interfaces */
218 printf("iso_pcbbind: bind to NOT zeroisoaddr\n");
220 for (ia
= iso_ifaddr
; ia
; ia
= ia
->ia_next
)
221 if (SAME_ISOADDR(siso
, &ia
->ia_addr
))
224 return EADDRNOTAVAIL
;
226 if (siso
->siso_len
<= sizeof (isop
->isop_sladdr
)) {
227 isop
->isop_laddr
= &isop
->isop_sladdr
;
229 if ((nam
= m_copy(nam
, 0, (int)M_COPYALL
)) == 0)
231 isop
->isop_laddr
= mtod(nam
, struct sockaddr_iso
*);
233 bcopy((caddr_t
)siso
, (caddr_t
)isop
->isop_laddr
, siso
->siso_len
);
234 if (siso
->siso_tlen
== 0)
236 if ((isop
->isop_socket
->so_options
& SO_REUSEADDR
) == 0 &&
237 iso_pcblookup(head
, 0, (caddr_t
)0, isop
->isop_laddr
))
239 if (siso
->siso_tlen
<= 2) {
240 bcopy(TSEL(siso
), suf
.data
, sizeof(suf
.data
));
241 suf
.s
= ntohs(suf
.s
);
242 if((suf
.s
< ISO_PORT_RESERVED
) &&
243 (isop
->isop_socket
->so_state
&& SS_PRIV
) == 0)
248 cp
= TSEL(isop
->isop_laddr
);
250 printf("iso_pcbbind noname\n");
253 if (head
->isop_lport
++ < ISO_PORT_RESERVED
||
254 head
->isop_lport
> ISO_PORT_USERRESERVED
)
255 head
->isop_lport
= ISO_PORT_RESERVED
;
256 suf
.s
= htons(head
->isop_lport
);
259 } while (iso_pcblookup(head
, 0, (caddr_t
)0, isop
->isop_laddr
));
262 printf("iso_pcbbind returns 0, suf 0x%x\n", suf
);
267 * FUNCTION: iso_pcbconnect
269 * PURPOSE: Make the isopcb (isop) look like it's connected.
270 * In other words, give it the peer address given in
271 * the mbuf * (nam). Make sure such a combination
272 * of local, peer addresses doesn't already exist
273 * for this protocol. Internet mentality prevails here,
274 * wherein a src,dst pair uniquely identifies a connection.
275 * Both net address and port must be specified in argument
277 * If we don't have a local address for this socket yet,
278 * we pick one by calling iso_pcbbind().
280 * RETURNS: errno E* or 0 if ok.
282 * SIDE EFFECTS: Looks up a route, which may cause one to be left
288 iso_pcbconnect(isop
, nam
)
289 register struct isopcb
*isop
;
292 register struct sockaddr_iso
*siso
= mtod(nam
, struct sockaddr_iso
*);
293 int local_zero
, error
= 0;
294 struct iso_ifaddr
*ia
;
297 printf("iso_pcbconnect(isop 0x%x sock 0x%x nam 0x%x",
298 isop
, isop
->isop_socket
, nam
);
299 printf("nam->m_len 0x%x), addr:\n", nam
->m_len
);
302 if (nam
->m_len
< siso
->siso_len
)
304 if (siso
->siso_family
!= AF_ISO
)
306 if (siso
->siso_nlen
== 0) {
307 if (ia
= iso_ifaddr
) {
308 int nlen
= ia
->ia_addr
.siso_nlen
;
309 ovbcopy(TSEL(siso
), nlen
+ TSEL(siso
),
310 siso
->siso_plen
+ siso
->siso_tlen
+ siso
->siso_slen
);
311 bcopy((caddr_t
)&ia
->ia_addr
.siso_addr
,
312 (caddr_t
)&siso
->siso_addr
, nlen
+ 1);
313 /* includes siso->siso_nlen = nlen; */
315 return EADDRNOTAVAIL
;
318 * Local zero means either not bound, or bound to a TSEL, but no
319 * particular local interface. So, if we want to send somebody
320 * we need to choose a return address.
323 ((isop
->isop_laddr
== 0) || (isop
->isop_laddr
->siso_nlen
== 0));
328 printf("iso_pcbconnect localzero 1\n");
331 * If route is known or can be allocated now,
332 * our src addr is taken from the i/f, else punt.
334 flags
= isop
->isop_socket
->so_options
& SO_DONTROUTE
;
335 if (error
= clnp_route(&siso
->siso_addr
, &isop
->isop_route
, flags
,
336 (struct sockaddr
**)0, &ia
))
339 printf("iso_pcbconnect localzero 2, ro->ro_rt 0x%x",
340 isop
->isop_route
.ro_rt
);
341 printf(" ia 0x%x\n", ia
);
345 printf("in iso_pcbconnect before lookup isop 0x%x isop->sock 0x%x\n",
346 isop
, isop
->isop_socket
);
349 int nlen
, tlen
, totlen
; caddr_t oldtsel
, newtsel
;
350 siso
= isop
->isop_laddr
;
351 if (siso
== 0 || siso
->siso_tlen
== 0)
352 (void)iso_pcbbind(isop
, (struct mbuf
*)0);
354 * Here we have problem of squezeing in a definite network address
355 * into an existing sockaddr_iso, which in fact may not have room
356 * for it. This gets messy.
358 siso
= isop
->isop_laddr
;
359 oldtsel
= TSEL(siso
);
360 tlen
= siso
->siso_tlen
;
361 nlen
= ia
->ia_addr
.siso_nlen
;
362 totlen
= tlen
+ nlen
+ _offsetof(struct sockaddr_iso
, siso_data
[0]);
363 if ((siso
== &isop
->isop_sladdr
) &&
364 (totlen
> sizeof(isop
->isop_sladdr
))) {
365 struct mbuf
*m
= m_get(MT_SONAME
, M_DONTWAIT
);
369 isop
->isop_laddr
= siso
= mtod(m
, struct sockaddr_iso
*);
371 siso
->siso_nlen
= ia
->ia_addr
.siso_nlen
;
372 newtsel
= TSEL(siso
);
373 ovbcopy(oldtsel
, newtsel
, tlen
);
374 bcopy(ia
->ia_addr
.siso_data
, siso
->siso_data
, nlen
);
375 siso
->siso_tlen
= tlen
;
376 siso
->siso_family
= AF_ISO
;
377 siso
->siso_len
= totlen
;
378 siso
= mtod(nam
, struct sockaddr_iso
*);
381 printf("in iso_pcbconnect before bcopy isop 0x%x isop->sock 0x%x\n",
382 isop
, isop
->isop_socket
);
385 * If we had to allocate space to a previous big foreign address,
386 * and for some reason we didn't free it, we reuse it knowing
387 * that is going to be big enough, as sockaddrs are delivered in
389 * If the foreign address is small enough, we use default space;
390 * otherwise, we grab an mbuf to copy into.
392 if (isop
->isop_faddr
== 0 || isop
->isop_faddr
== &isop
->isop_sfaddr
) {
393 if (siso
->siso_len
<= sizeof(isop
->isop_sfaddr
))
394 isop
->isop_faddr
= &isop
->isop_sfaddr
;
396 struct mbuf
*m
= m_get(MT_SONAME
, M_DONTWAIT
);
399 isop
->isop_faddr
= mtod(m
, struct sockaddr_iso
*);
402 bcopy((caddr_t
)siso
, (caddr_t
)isop
->isop_faddr
, siso
->siso_len
);
404 printf("in iso_pcbconnect after bcopy isop 0x%x isop->sock 0x%x\n",
405 isop
, isop
->isop_socket
);
406 printf("iso_pcbconnect connected to addr:\n");
407 dump_isoaddr(isop
->isop_faddr
);
408 printf("iso_pcbconnect end: src addr:\n");
409 dump_isoaddr(isop
->isop_laddr
);
415 * FUNCTION: iso_pcbdisconnect()
417 * PURPOSE: washes away the peer address info so the socket
418 * appears to be disconnected.
419 * If there's no file descriptor associated with the socket
420 * it detaches the pcb.
424 * SIDE EFFECTS: May detach the pcb.
429 iso_pcbdisconnect(isop
)
432 void iso_pcbdetach();
433 register struct sockaddr_iso
*siso
;
436 printf("iso_pcbdisconnect(isop 0x%x)\n", isop
);
439 * Preserver binding infnormation if already bound.
441 if ((siso
= isop
->isop_laddr
) && siso
->siso_nlen
&& siso
->siso_tlen
) {
442 caddr_t otsel
= TSEL(siso
);
444 ovbcopy(otsel
, TSEL(siso
), siso
->siso_tlen
);
446 if (isop
->isop_faddr
&& isop
->isop_faddr
!= &isop
->isop_sfaddr
)
447 m_freem(dtom(isop
->isop_faddr
));
448 isop
->isop_faddr
= 0;
449 if (isop
->isop_socket
->so_state
& SS_NOFDREF
)
454 * FUNCTION: iso_pcbdetach
456 * PURPOSE: detach the pcb at *(isop) from it's socket and free
457 * the mbufs associated with the pcb..
458 * Dequeues (isop) from its head.
470 struct socket
*so
= isop
->isop_socket
;
473 printf("iso_pcbdetach(isop 0x%x socket 0x%x so 0x%x)\n",
474 isop
, isop
->isop_socket
, so
);
477 if (isop
->isop_chan
) {
478 register struct pklcd
*lcp
= (struct pklcd
*)isop
->isop_chan
;
479 if (--isop
->isop_refcnt
> 0)
481 if (lcp
&& lcp
->lcd_state
== DATA_TRANSFER
) {
489 if (so
) { /* in the x.25 domain, we sometimes have no socket */
494 printf("iso_pcbdetach 2 \n");
496 if (isop
->isop_options
)
497 (void)m_free(isop
->isop_options
);
499 printf("iso_pcbdetach 3 \n");
501 if (isop
->isop_route
.ro_rt
)
502 rtfree(isop
->isop_route
.ro_rt
);
504 printf("iso_pcbdetach 3.1\n");
506 if (isop
->isop_clnpcache
!= NULL
) {
507 struct clnp_cache
*clcp
=
508 mtod(isop
->isop_clnpcache
, struct clnp_cache
*);
510 printf("iso_pcbdetach 3.2: clcp 0x%x freeing clc_hdr x%x\n",
511 clcp
, clcp
->clc_hdr
);
513 if (clcp
->clc_hdr
!= NULL
)
514 m_free(clcp
->clc_hdr
);
516 printf("iso_pcbdetach 3.3: freeing cache x%x\n",
517 isop
->isop_clnpcache
);
519 m_free(isop
->isop_clnpcache
);
522 printf("iso_pcbdetach 4 \n");
526 printf("iso_pcbdetach 5 \n");
528 if (isop
->isop_laddr
&& (isop
->isop_laddr
!= &isop
->isop_sladdr
))
529 m_freem(dtom(isop
->isop_laddr
));
530 FREE((caddr_t
)isop
, M_PCB
);
535 * FUNCTION: iso_pcbnotify
537 * PURPOSE: notify all connections in this protocol's queue (head)
538 * that have peer address (dst) of the problem (errno)
539 * by calling (notify) on the connections' isopcbs.
545 * NOTES: (notify) is called at splimp!
548 iso_pcbnotify(head
, siso
, errno
, notify
)
550 register struct sockaddr_iso
*siso
;
551 int errno
, (*notify
)();
553 register struct isopcb
*isop
;
557 printf("iso_pcbnotify(head 0x%x, notify 0x%x) dst:\n", head
, notify
);
559 for (isop
= head
->isop_next
; isop
!= head
; isop
= isop
->isop_next
) {
560 if (isop
->isop_socket
== 0 || isop
->isop_faddr
== 0 ||
561 !SAME_ISOADDR(siso
, isop
->isop_faddr
)) {
563 printf("iso_pcbnotify: CONTINUE isop 0x%x, sock 0x%x\n" ,
564 isop
, isop
->isop_socket
);
565 printf("addrmatch cmp'd with (0x%x):\n", isop
->isop_faddr
);
566 dump_isoaddr(isop
->isop_faddr
);
571 isop
->isop_socket
->so_error
= errno
;
577 printf("END OF iso_pcbnotify\n" );
583 * FUNCTION: iso_pcblookup
585 * PURPOSE: looks for a given combination of (faddr), (fport),
586 * (lport), (laddr) in the queue named by (head).
587 * Argument (flags) is ignored.
589 * RETURNS: ptr to the isopcb if it finds a connection matching
590 * these arguments, o.w. returns zero.
597 iso_pcblookup(head
, fportlen
, fport
, laddr
)
599 register struct sockaddr_iso
*laddr
;
603 register struct isopcb
*isop
;
604 register caddr_t lp
= TSEL(laddr
);
605 unsigned int llen
= laddr
->siso_tlen
;
608 printf("iso_pcblookup(head 0x%x laddr 0x%x fport 0x%x)\n",
611 for (isop
= head
->isop_next
; isop
!= head
; isop
= isop
->isop_next
) {
612 if (isop
->isop_laddr
== 0 || isop
->isop_laddr
== laddr
)
614 if (isop
->isop_laddr
->siso_tlen
!= llen
)
616 if (bcmp(lp
, TSEL(isop
->isop_laddr
), llen
))
618 if (fportlen
&& isop
->isop_faddr
&&
619 bcmp(fport
, TSEL(isop
->isop_faddr
), (unsigned)fportlen
))
622 * addrmatch1 should be iso_addrmatch(a, b, mask)
623 * where mask is taken from isop->isop_laddrmask (new field)
624 * isop_lnetmask will also be available in isop
625 if (laddr != &zeroiso_addr &&
626 !iso_addrmatch1(laddr, &(isop->isop_laddr.siso_addr)))
629 if (laddr
->siso_nlen
&& (!SAME_ISOADDR(laddr
, isop
->isop_laddr
)))
633 return (struct isopcb
*)0;