exit on end-of-file if file shorter than a screen, regardless
[unix-history] / usr / src / sys / netiso / iso_pcb.c
CommitLineData
627d3292
KS
1/***********************************************************
2 Copyright IBM Corporation 1987
3
4 All Rights Reserved
5
6Permission to use, copy, modify, and distribute this software and its
7documentation for any purpose and without fee is hereby granted,
8provided that the above copyright notice appear in all copies and that
9both that copyright notice and this permission notice appear in
10supporting documentation, and that the name of IBM not be
11used in advertising or publicity pertaining to distribution of the
12software without specific, written prior permission.
13
14IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20SOFTWARE.
21
22******************************************************************/
23
24/*
25 * ARGO Project, Computer Sciences Dept., University of Wisconsin - Madison
26 */
27/*
28 * $Header: iso_pcb.c,v 4.5 88/06/29 14:59:56 hagens Exp $
29 * $Source: /usr/argo/sys/netiso/RCS/iso_pcb.c,v $
30 *
31 * Iso address family net-layer(s) pcb stuff. NEH 1/29/87
32 */
33#ifndef lint
34static char *rcsid = "$Header: iso_pcb.c,v 4.5 88/06/29 14:59:56 hagens Exp $";
35#endif
36
37#ifdef ISO
38
39#include "param.h"
40#include "systm.h"
41#include "dir.h"
42#include "user.h"
43#include "mbuf.h"
44#include "../h/socket.h"
45#include "../h/socketvar.h"
46#include "../netiso/argo_debug.h"
47#include "../netiso/iso.h"
48#include "../netiso/clnp.h"
49#include "../netinet/in_systm.h"
50#include "../net/if.h"
51#include "../net/route.h"
52#include "../netiso/iso_pcb.h"
53#include "../netiso/iso_var.h"
54#include "protosw.h"
55
56#define PCBNULL (struct isopcb *)0
57struct iso_addr zeroiso_addr = {
58 0
59};
60
61
62/*
63 * FUNCTION: iso_pcballoc
64 *
65 * PURPOSE: creates an isopcb structure in an mbuf,
66 * with socket (so), and
67 * puts it in the queue with head (head)
68 *
69 * RETURNS: 0 if OK, ENOBUFS if can't alloc the necessary mbuf
70 */
71int
72iso_pcballoc(so, head)
73 struct socket *so;
74 struct isopcb *head;
75{
76 struct mbuf *m;
77 register struct isopcb *isop;
78
79 IFDEBUG(D_ISO)
80 printf("iso_pcballoc(so 0x%x)\n", so);
81 ENDDEBUG
82 m = m_getclr(M_DONTWAIT, MT_PCB);
83 if (m == NULL)
84 return ENOBUFS;
85 isop = mtod(m, struct isopcb *);
86 isop->isop_head = head;
87 isop->isop_socket = so;
88 insque(isop, head);
89 so->so_pcb = (caddr_t)isop;
90 return 0;
91}
92
93/*
94 * FUNCTION: iso_pcbbind
95 *
96 * PURPOSE: binds the address given in *(nam) to the socket
97 * specified by the isopcb in *(isop)
98 * If the given address is zero, it makes sure the
99 * address isn't already in use and if it's got a network
100 * portion, we look for an interface with that network
101 * address. If the address given is zero, we allocate
102 * a port and stuff it in the (nam) structure.
103 *
104 * RETURNS: errno E* or 0 if ok.
105 *
106 * SIDE EFFECTS: increments head->isop_lport if it allocates a port #
107 *
108 * NOTES:
109 */
110int
111iso_pcbbind(isop, nam)
112 register struct isopcb *isop;
113 struct mbuf *nam;
114{
115 register struct isopcb *head = isop->isop_head;
116 register struct sockaddr_iso *siso;
117 struct ifaddr *ia;
118 u_short suf = 0;
119
120 IFDEBUG(D_ISO)
121 printf("iso_pcbbind(isop 0x%x, nam 0x%x)\n", isop, nam);
122 ENDDEBUG
123 if (iso_ifaddr == 0) /* any interfaces attached? */
124 return EADDRNOTAVAIL;
125 if (isop->isop_lport) /* already bound */
126 return EADDRINUSE;
127 if(nam == (struct mbuf *)0)
128 goto noname;
129 siso = mtod(nam, struct sockaddr_iso *);
130 IFDEBUG(D_ISO)
131 printf("iso_pcbbind(name len 0x%x)\n", nam->m_len);
132 printf("The address is %s\n", clnp_iso_addrp(&siso->siso_addr));
133 ENDDEBUG
134 /*
135 * We would like sort of length check but since some OSI addrs
136 * do not have fixed length, we can't really do much.
137 * The ONLY thing we can say is that an osi addr has to have
138 * at LEAST an afi and one more byte and had better fit into
139 * a struct iso_addr.
140 * However, in fact the size of the whole thing is a struct
141 * sockaddr_iso, so probably this is what we should check for.
142 */
143 if( (nam->m_len < 2) || (nam->m_len > sizeof(struct sockaddr_iso))) {
144 return ENAMETOOLONG;
145 }
146 suf = siso->siso_tsuffix;
147
148 if (bcmp(&siso->siso_addr,&zeroiso_addr, 1)) {
149 /* non-zero net addr- better match one of our interfaces */
150 IFDEBUG(D_ISO)
151 printf("iso_pcbbind: bind to NOT zeroisoaddr\n");
152 ENDDEBUG
153 siso->siso_tsuffix = 0; /* yech... */
154 /* PHASE 2: this call is ok */
155 if ((ia = ifa_ifwithaddr((struct sockaddr *)siso))
156 == (struct ifaddr *)0)
157 return EADDRNOTAVAIL;
158 /* copy to the inpcb */
159 bcopy( (caddr_t)&((struct sockaddr_iso *)&(ia->ifa_addr))->siso_addr,
160 (caddr_t)&(isop->isop_laddr.siso_addr),
161 sizeof(struct sockaddr_iso) );
162 isop->isop_laddr.siso_tsuffix = suf;
163 /* copy also to the nam parameter */
164 bcopy( (caddr_t)&(isop->isop_laddr.siso_addr),
165 (caddr_t)&(siso->siso_addr), sizeof(struct sockaddr_iso));
166 siso->siso_tsuffix = suf;
167 }
168 if (suf) {
169 if((suf < ISO_PORT_RESERVED) && (u.u_uid != 0))
170 return EACCES;
171 if ((isop->isop_socket->so_options & SO_REUSEADDR) == 0 &&
172 iso_pcblookup(head, 0, &(isop->isop_laddr.siso_addr), suf, 0) )
173 return EADDRINUSE;
174 }
175 /* copy the if addr to the result (siso) and to the isopcb */
176noname:
177 IFDEBUG(D_ISO)
178 printf("iso_pcbbind noname\n");
179 ENDDEBUG
180 if (suf == 0)
181 do {
182 if (head->isop_lport++ < ISO_PORT_RESERVED ||
183 head->isop_lport > ISO_PORT_USERRESERVED)
184 head->isop_lport = ISO_PORT_RESERVED;
185 suf = head->isop_lport;
186 } while (iso_pcblookup(head, 0, &(isop->isop_laddr.siso_addr), suf, 0));
187 isop->isop_lport = suf;
188 IFDEBUG(D_ISO)
189 printf("iso_pcbbind returns 0, suf 0x%x\n", suf);
190 ENDDEBUG
191 return 0;
192}
193
194/*
195 * FUNCTION: iso_pcbconnect
196 *
197 * PURPOSE: Make the isopcb (isop) look like it's connected.
198 * In other words, give it the peer address given in
199 * the mbuf * (nam). Make sure such a combination
200 * of local, peer addresses doesn't already exist
201 * for this protocol. Internet mentality prevails here,
202 * wherein a src,dst pair uniquely identifies a connection.
203 * Both net address and port must be specified in argument
204 * (nam).
205 * If we don't have a local address for this socket yet,
206 * we pick one by calling iso_pcbbind().
207 *
208 * RETURNS: errno E* or 0 if ok.
209 *
210 * SIDE EFFECTS: Looks up a route, which may cause one to be left
211 * in the isopcb.
212 *
213 * NOTES:
214 */
215#define satosiso(sa) ((struct sockaddr_iso *)(sa))
216
217int
218iso_pcbconnect(isop, nam)
219 struct isopcb *isop;
220 struct mbuf *nam;
221{
222 struct ifnet *ifp = (struct ifnet *)0;
223 struct sockaddr_iso ifaddr;
224 register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
225 int local_zero = 0;
226
227 IFDEBUG(D_ISO)
228 printf(
229 "iso_pcbconnect(isop 0x%x sock 0x%x nam 0x%x nam->m_len 0x%x), addr:\n",
230 isop, isop->isop_socket, nam, nam->m_len);
231 dump_isoaddr(siso);
232 ENDDEBUG
233 if (nam->m_len > sizeof (*siso))
234 return ENAMETOOLONG; /* not great but better than EINVAL! */
235 if (siso->siso_family != AF_ISO)
236 return EAFNOSUPPORT;
237#ifdef notdef
238 /* removed for the sake of extended tsels -
239 * user may setsockopt for extended tsel (foreign) and then
240 * connect to nsap w/ tsuffix zero
241 */
242 if (siso->siso_tsuffix == 0)
243 return EADDRNOTAVAIL;
244 local_zero = iso_addrmatch1(&(isop->isop_laddr.siso_addr), &zeroiso_addr);
245#endif notdef
246 local_zero = !bcmp(&(isop->isop_laddr.siso_addr), &zeroiso_addr, 1);
247
248#ifdef PHASEONE
249 if (local_zero) {
250 /*
251 * We need to get the local nsap address.
252 * First, route to the destination. This will provide us with
253 * an ifp. Second, determine which local address linked on
254 * that ifp is appropriate
255 */
256 struct sockaddr_iso *first_hop; /* filled by clnp_route */
257 struct ifnet *ifp; /* filled by clnp_route */
258 int err;
259 struct iso_addr *localaddr;
260
261 if (err = clnp_route(&siso->siso_addr, &isop->isop_route, /* flags */0,
262 &first_hop, &ifp))
263 return(err);
264
265 /* determine local address based upon ifp */
266 if ((localaddr = clnp_srcaddr(ifp, &first_hop->siso_addr)) == NULL)
267 return(ENETUNREACH);
268
269 ifaddr.siso_family = AF_ISO;
270 ifaddr.siso_addr = *localaddr;
271
272 if (isop->isop_lport == 0)
273 (void)iso_pcbbind(isop, (struct mbuf *)0);
274 isop->isop_laddr = ifaddr;
275 }
276#else
277 if (local_zero) {
278 struct iso_ifaddr *ia;
279 register struct route *ro;
280
281 IFDEBUG(D_ISO)
282 printf("iso_pcbconnect localzero 1\n");
283 ENDDEBUG
284 ia = (struct iso_ifaddr *)0;
285 /*
286 * If route is known or can be allocated now,
287 * our src addr is taken from the i/f, else punt.
288 */
289 ro = &isop->isop_route;
290 IFDEBUG(D_ISO)
291 printf("iso_pcbconnect rtalloc 1.1, ro->ro_rt 0x%x\n",
292 ro->ro_rt);
293 ENDDEBUG
294 if (ro->ro_rt && ! iso_addrmatch1( &(satosiso(&ro->ro_dst)->siso_addr),
295 &siso->siso_addr)) {
296 RTFREE(ro->ro_rt);
297 ro->ro_rt = (struct rtentry *)0;
298 }
299 /*
300 * TODO: it seems this code has a lot in common with clnp_route.
301 * Maybe they could be combined? (RAH)
302 */
303 if ((isop->isop_socket->so_options & SO_DONTROUTE) == 0 && /*XXX*/
304 (ro->ro_rt == (struct rtentry *)0 ||
305 (ifp = ro->ro_rt->rt_ifp) == (struct ifnet *)0)) {
306 /* No route yet, so try to acquire one */
307 ro->ro_dst.sa_family = AF_ISO;
308 ((struct sockaddr_iso *) &ro->ro_dst)->siso_addr =
309 siso->siso_addr;
310 rtalloc(ro);
311 IFDEBUG(D_ISO)
312 printf("iso_pcbconnect rtalloc 1.5, ro->ro_rt 0x%x\n",
313 ro->ro_rt);
314 if (ro->ro_rt != NULL) {
315 printf("ro->ro_rt->rt_refcnt %d\n",
316 ro->ro_rt->rt_refcnt);
317 printf("rt entry rt_gateway (as sockaddr):\n");
318 dump_buf(&ro->ro_rt->rt_gateway,
319 sizeof (struct sockaddr));
320 }
321 ENDDEBUG
322 /*
323 * If we found a route, use the address
324 * corresponding to the outgoing interface
325 * unless it is the loopback (in case a route
326 * to our address on another net goes to loopback).
327 *
328 * We must check to use the address that is of the
329 * same type (in the case where the interface has more
330 * than one type associated with it). (ie ecn0 has
331 * both t37 and osinet addresses.
332 */
333 if (ro->ro_rt && (ifp = ro->ro_rt->rt_ifp) &&
334 (ifp->if_flags & IFF_LOOPBACK) == 0)
335 for (ia = iso_ifaddr; ia; ia = ia->ia_next) {
336 struct iso_addr *isoap = &IA_SIS(ia)->siso_addr;
337
338 IFDEBUG(D_ISO)
339 printf("iso_pcbconnect: ia x%x yields: %s\n",
340 ia, clnp_iso_addrp(isoap));
341 ENDDEBUG
342
343 if ((ia->ia_ifp == ifp) &&
344 (iso_eqtype(&siso->siso_addr, isoap)))
345 break;
346 }
347 }
348 IFDEBUG(D_ISO)
349 printf("iso_pcbconnect localzero 2: ia x%x\n", ia);
350 ENDDEBUG
351 if (ia == 0) {
352 ia = (struct iso_ifaddr *)
353 ifa_ifwithdstaddr((struct sockaddr *)siso);
354 if (ia == 0)
355 ia = iso_iaonnetof(siso);
356 if (ia == 0)
357 return EADDRNOTAVAIL;
358 }
359 ifaddr = *(struct sockaddr_iso *)&ia->ia_addr;
360 }
361 IFDEBUG(D_ISO)
362 printf("in iso_pcbconnect before lookup isop 0x%x isop->sock 0x%x\n",
363 isop, isop->isop_socket);
364 ENDDEBUG
365 if (local_zero) {
366 if (isop->isop_lport == 0)
367 (void)iso_pcbbind(isop, (struct mbuf *)0);
368 isop->isop_laddr.siso_addr = ifaddr.siso_addr;
369 isop->isop_laddr.siso_family = AF_ISO;
370 }
371#endif PHASEONE
372 IFDEBUG(D_ISO)
373 printf("in iso_pcbconnect before bcopy isop 0x%x isop->sock 0x%x\n",
374 isop, isop->isop_socket);
375 ENDDEBUG
376 bcopy((caddr_t) &(siso->siso_addr), (caddr_t) &(isop->isop_faddr.siso_addr),
377 sizeof(struct iso_addr));
378 IFDEBUG(D_ISO)
379 printf("in iso_pcbconnect after bcopy isop 0x%x isop->sock 0x%x\n",
380 isop, isop->isop_socket);
381 ENDDEBUG
382 isop->isop_faddr.siso_family = AF_ISO;
383 isop->isop_fport = siso->siso_tsuffix;
384 IFDEBUG(D_ISO)
385 printf("in iso_pcbconnect end isop 0x%x isop->sock 0x%x\n",
386 isop, isop->isop_socket);
387 printf("iso_pcbconnect connected to addr:\n");
388 dump_isoaddr(&isop->isop_faddr);
389 printf("iso_pcbconnect end: src addr:\n");
390 dump_isoaddr(&isop->isop_laddr);
391 ENDDEBUG
392 return 0;
393}
394
395/*
396 * FUNCTION: iso_pcbdisconnect()
397 *
398 * PURPOSE: washes away the peer address info so the socket
399 * appears to be disconnected.
400 * If there's no file descriptor associated with the socket
401 * it detaches the pcb.
402 *
403 * RETURNS: Nada.
404 *
405 * SIDE EFFECTS: May detach the pcb.
406 *
407 * NOTES:
408 */
409void
410iso_pcbdisconnect(isop)
411 struct isopcb *isop;
412{
413 void iso_pcbdetach();
414
415 IFDEBUG(D_ISO)
416 printf("iso_pcbdisconnect(isop 0x%x)\n", isop);
417 ENDDEBUG
418 isop->isop_laddr.siso_addr = zeroiso_addr;
419 isop->isop_fport = 0;
420 if (isop->isop_socket->so_state & SS_NOFDREF)
421 iso_pcbdetach(isop);
422}
423
424/*
425 * FUNCTION: iso_pcbdetach
426 *
427 * PURPOSE: detach the pcb at *(isop) from it's socket and free
428 * the mbufs associated with the pcb..
429 * Dequeues (isop) from its head.
430 *
431 * RETURNS: Nada.
432 *
433 * SIDE EFFECTS:
434 *
435 * NOTES:
436 */
437void
438iso_pcbdetach(isop)
439 struct isopcb *isop;
440{
441 struct socket *so = isop->isop_socket;
442
443 IFDEBUG(D_ISO)
444 printf("iso_pcbdetach(isop 0x%x socket 0x%x so 0x%x)\n",
445 isop, isop->isop_socket, so);
446 ENDDEBUG
447 if (so ) { /* in the x.25 domain, we sometimes have no socket */
448 so->so_pcb = 0;
449 sofree(so);
450 }
451 IFDEBUG(D_ISO)
452 printf("iso_pcbdetach 2 \n");
453 ENDDEBUG
454 if (isop->isop_options)
455 (void)m_free(isop->isop_options);
456 IFDEBUG(D_ISO)
457 printf("iso_pcbdetach 3 \n");
458 ENDDEBUG
459 if (isop->isop_route.ro_rt)
460 rtfree(isop->isop_route.ro_rt);
461 IFDEBUG(D_ISO)
462 printf("iso_pcbdetach 3.1\n");
463 ENDDEBUG
464 if (isop->isop_clnpcache != NULL) {
465 struct clnp_cache *clcp =
466 mtod(isop->isop_clnpcache, struct clnp_cache *);
467 IFDEBUG(D_ISO)
468 printf("iso_pcbdetach 3.2: clcp 0x%x freeing clc_hdr x%x\n",
469 clcp, clcp->clc_hdr);
470 ENDDEBUG
471 if (clcp->clc_hdr != NULL)
472 m_free(clcp->clc_hdr);
473 IFDEBUG(D_ISO)
474 printf("iso_pcbdetach 3.3: freeing cache x%x\n",
475 isop->isop_clnpcache);
476 ENDDEBUG
477 m_free(isop->isop_clnpcache);
478 }
479 IFDEBUG(D_ISO)
480 printf("iso_pcbdetach 4 \n");
481 ENDDEBUG
482 remque(isop);
483 IFDEBUG(D_ISO)
484 printf("iso_pcbdetach 5 \n");
485 ENDDEBUG
486 (void) m_free(dtom(isop));
487}
488
489#ifdef notdef
490/* NEEDED? */
491void
492iso_setsockaddr(isop, nam)
493 register struct isopcb *isop;
494 struct mbuf *nam;
495{
496 register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
497
498 nam->m_len = sizeof (*siso);
499 siso = mtod(nam, struct sockaddr_iso *);
500 bzero((caddr_t)siso, sizeof (*siso));
501 siso->siso_family = AF_ISO;
502 siso->siso_tsuffix = isop->isop_lport;
503 siso->siso_addr = isop->isop_laddr.siso_addr;
504}
505
506/* NEEDED? */
507void
508iso_setpeeraddr(isop, nam)
509 register struct isopcb *isop;
510 struct mbuf *nam;
511{
512 register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
513
514 nam->m_len = sizeof (*siso);
515 siso = mtod(nam, struct sockaddr_iso *);
516 bzero((caddr_t)siso, sizeof (*siso));
517 siso->siso_family = AF_ISO;
518 siso->siso_tsuffix = isop->isop_fport;
519 siso->siso_addr = isop->isop_faddr.siso_addr;
520}
521#endif notdef
522
523/*
524 * FUNCTION: iso_pcbnotify
525 *
526 * PURPOSE: notify all connections in this protocol's queue (head)
527 * that have peer address (dst) of the problem (errno)
528 * by calling (notify) on the connections' isopcbs.
529 *
530 * RETURNS: Rien.
531 *
532 * SIDE EFFECTS:
533 *
534 * NOTES: (notify) is called at splimp!
535 */
536void
537iso_pcbnotify(head, dst, errno, notify)
538 struct isopcb *head;
539 register struct iso_addr *dst;
540 int errno, (*notify)();
541{
542 register struct isopcb *isop, *oisop;
543 int s = splimp();
544
545 IFDEBUG(D_ISO)
546 printf("iso_pcbnotify(head 0x%x, notify 0x%x) dst:\n", head, notify);
547 ENDDEBUG
548 for (isop = head->isop_next; isop != head;) {
549 if (!iso_addrmatch1(&(isop->isop_faddr.siso_addr), dst) ||
550 isop->isop_socket == 0) {
551 IFDEBUG(D_ISO)
552 printf("iso_pcbnotify: CONTINUE isop 0x%x, sock 0x%x\n" ,
553 isop, isop->isop_socket);
554 printf("addrmatch cmp'd with (0x%x):\n",
555 &(isop->isop_faddr.siso_addr));
556 dump_isoaddr(&isop->isop_faddr);
557 ENDDEBUG
558 isop = isop->isop_next;
559 continue;
560 }
561 if (errno)
562 isop->isop_socket->so_error = errno;
563 oisop = isop;
564 isop = isop->isop_next;
565 if (notify)
566 (*notify)(oisop);
567 }
568 splx(s);
569 IFDEBUG(D_ISO)
570 printf("END OF iso_pcbnotify\n" );
571 ENDDEBUG
572}
573
574
575/*
576 * FUNCTION: iso_pcblookup
577 *
578 * PURPOSE: looks for a given combination of (faddr), (fport),
579 * (lport), (laddr) in the queue named by (head).
580 * Argument (flags) is ignored.
581 *
582 * RETURNS: ptr to the isopcb if it finds a connection matching
583 * these arguments, o.w. returns zero.
584 *
585 * SIDE EFFECTS:
586 *
587 * NOTES:
588 */
589struct isopcb *
590iso_pcblookup(head, fport, laddr, lport, flags)
591 struct isopcb *head;
592 struct iso_addr *laddr;
593 u_short fport, lport;
594 int flags;
595{
596 register struct isopcb *isop;
597
598 IFDEBUG(D_ISO)
599 printf("iso_pcblookup(head 0x%x lport 0x%x fport 0x%x)\n",
600 head, lport, fport);
601 ENDDEBUG
602 for (isop = head->isop_next; isop != head; isop = isop->isop_next) {
603#ifdef notdef
604 /*
605 * This should be changed to do bcmp on lsuffix in the tpcb instead
606 * since we should be ignoring the lport concept.
607 */
608#endif notdef
609 if (isop->isop_lport != lport)
610 continue;
611 if (isop->isop_fport != fport)
612 continue;
613 /* PHASE2
614 * addrmatch1 should be iso_addrmatch(a, b, mask)
615 * where mask is taken from isop->isop_laddrmask (new field)
616 * isop_lnetmask will also be available in isop
617 */
618 if (laddr != &zeroiso_addr &&
619 !iso_addrmatch1(laddr, &(isop->isop_laddr.siso_addr)))
620 continue;
621 return (isop);
622 }
623 return (struct isopcb *)0;
624}
625#endif ISO