|
|
1.1 root 1: /***********************************************************
2: Copyright IBM Corporation 1987
3:
4: All Rights Reserved
5:
6: Permission to use, copy, modify, and distribute this software and its
7: documentation for any purpose and without fee is hereby granted,
8: provided that the above copyright notice appear in all copies and that
9: both that copyright notice and this permission notice appear in
10: supporting documentation, and that the name of IBM not be
11: used in advertising or publicity pertaining to distribution of the
12: software without specific, written prior permission.
13:
14: IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
15: ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
16: IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
17: ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
18: WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
19: ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
20: SOFTWARE.
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: * @(#)iso_pcb.c 7.7 (Berkeley) 4/16/90
31: *
32: * Iso address family net-layer(s) pcb stuff. NEH 1/29/87
33: */
34:
35: #ifndef lint
36: static char *rcsid = "$Header: iso_pcb.c,v 4.5 88/06/29 14:59:56 hagens Exp $";
37: #endif
38:
39: #ifdef ISO
40:
41: #include "param.h"
42: #include "systm.h"
43: #include "user.h"
44: #include "mbuf.h"
45: #include "socket.h"
46: #include "socketvar.h"
47: #include "argo_debug.h"
48: #include "iso.h"
49: #include "clnp.h"
50: #include "../netinet/in_systm.h"
51: #include "../net/if.h"
52: #include "../net/route.h"
53: #include "iso_pcb.h"
54: #include "iso_var.h"
55: #include "protosw.h"
56:
57: #define PCBNULL (struct isopcb *)0
58: struct iso_addr zeroiso_addr = {
59: 0
60: };
61:
62:
63: /*
64: * FUNCTION: iso_pcballoc
65: *
66: * PURPOSE: creates an isopcb structure in an mbuf,
67: * with socket (so), and
68: * puts it in the queue with head (head)
69: *
70: * RETURNS: 0 if OK, ENOBUFS if can't alloc the necessary mbuf
71: */
72: int
73: iso_pcballoc(so, head)
74: struct socket *so;
75: struct isopcb *head;
76: {
77: register struct isopcb *isop;
78:
79: IFDEBUG(D_ISO)
80: printf("iso_pcballoc(so 0x%x)\n", so);
81: ENDDEBUG
82: MALLOC(isop, struct isopcb *, sizeof(*isop), M_PCB, M_NOWAIT);
83: if (isop == NULL)
84: return ENOBUFS;
85: bzero((caddr_t)isop, sizeof(*isop));
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: */
110: #define satosiso(sa) ((struct sockaddr_iso *)(sa))
111: int
112: iso_pcbbind(isop, nam)
113: register struct isopcb *isop;
114: struct mbuf *nam;
115: {
116: register struct isopcb *head = isop->isop_head;
117: register struct sockaddr_iso *siso;
118: struct iso_ifaddr *ia;
119: union {
120: char data[2];
121: u_short s;
122: } suf;
123:
124: IFDEBUG(D_ISO)
125: printf("iso_pcbbind(isop 0x%x, nam 0x%x)\n", isop, nam);
126: ENDDEBUG
127: suf.s = 0;
128: if (iso_ifaddr == 0) /* any interfaces attached? */
129: return EADDRNOTAVAIL;
130: if (isop->isop_laddr) /* already bound */
131: return EADDRINUSE;
132: if(nam == (struct mbuf *)0) {
133: isop->isop_laddr = &isop->isop_sladdr;
134: isop->isop_sladdr.siso_len = sizeof(struct sockaddr_iso);
135: isop->isop_sladdr.siso_family = AF_ISO;
136: isop->isop_sladdr.siso_tlen = 2;
137: isop->isop_sladdr.siso_nlen = 0;
138: isop->isop_sladdr.siso_slen = 0;
139: isop->isop_sladdr.siso_plen = 0;
140: goto noname;
141: }
142: siso = mtod(nam, struct sockaddr_iso *);
143: IFDEBUG(D_ISO)
144: printf("iso_pcbbind(name len 0x%x)\n", nam->m_len);
145: printf("The address is %s\n", clnp_iso_addrp(&siso->siso_addr));
146: ENDDEBUG
147: /*
148: * We would like sort of length check but since some OSI addrs
149: * do not have fixed length, we can't really do much.
150: * The ONLY thing we can say is that an osi addr has to have
151: * at LEAST an afi and one more byte and had better fit into
152: * a struct iso_addr.
153: * However, in fact the size of the whole thing is a struct
154: * sockaddr_iso, so probably this is what we should check for.
155: */
156: if( (nam->m_len < 2) || (nam->m_len < siso->siso_len)) {
157: return ENAMETOOLONG;
158: }
159: if (siso->siso_tlen) {
160: register char *cp = TSEL(siso);
161: suf.data[0] = cp[0];
162: suf.data[1] = cp[1];
163: }
164: if (siso->siso_nlen) {
165: /* non-zero net addr- better match one of our interfaces */
166: IFDEBUG(D_ISO)
167: printf("iso_pcbbind: bind to NOT zeroisoaddr\n");
168: ENDDEBUG
169: for (ia = iso_ifaddr; ia; ia = ia->ia_next)
170: if (SAME_ISOADDR(siso, &ia->ia_addr))
171: break;
172: if (ia == 0)
173: return EADDRNOTAVAIL;
174: }
175: if (siso->siso_len <= sizeof (isop->isop_sladdr)) {
176: isop->isop_laddr = &isop->isop_sladdr;
177: } else {
178: if ((nam = m_copy(nam, 0, (int)M_COPYALL)) == 0)
179: return ENOBUFS;
180: isop->isop_laddr = mtod(nam, struct sockaddr_iso *);
181: }
182: bcopy((caddr_t)siso, (caddr_t)isop->isop_laddr, siso->siso_len);
183: if (suf.s || siso->siso_tlen != 2) {
184: if((suf.s < ISO_PORT_RESERVED) && (siso->siso_tlen <= 2) &&
185: (u.u_uid != 0))
186: return EACCES;
187: if ((isop->isop_socket->so_options & SO_REUSEADDR) == 0 &&
188: iso_pcblookup(head, 0, (caddr_t)0, isop->isop_laddr))
189: return EADDRINUSE;
190: } else {
191: register char *cp;
192: noname:
193: cp = TSEL(isop->isop_laddr);
194: IFDEBUG(D_ISO)
195: printf("iso_pcbbind noname\n");
196: ENDDEBUG
197: do {
198: if (head->isop_lport++ < ISO_PORT_RESERVED ||
199: head->isop_lport > ISO_PORT_USERRESERVED)
200: head->isop_lport = ISO_PORT_RESERVED;
201: suf.s = head->isop_lport;
202: cp[0] = suf.data[0];
203: cp[1] = suf.data[1];
204: } while (iso_pcblookup(head, 0, (caddr_t)0, isop->isop_laddr));
205: }
206: IFDEBUG(D_ISO)
207: printf("iso_pcbbind returns 0, suf 0x%x\n", suf);
208: ENDDEBUG
209: return 0;
210: }
211: /*
212: * FUNCTION: iso_pcbconnect
213: *
214: * PURPOSE: Make the isopcb (isop) look like it's connected.
215: * In other words, give it the peer address given in
216: * the mbuf * (nam). Make sure such a combination
217: * of local, peer addresses doesn't already exist
218: * for this protocol. Internet mentality prevails here,
219: * wherein a src,dst pair uniquely identifies a connection.
220: * Both net address and port must be specified in argument
221: * (nam).
222: * If we don't have a local address for this socket yet,
223: * we pick one by calling iso_pcbbind().
224: *
225: * RETURNS: errno E* or 0 if ok.
226: *
227: * SIDE EFFECTS: Looks up a route, which may cause one to be left
228: * in the isopcb.
229: *
230: * NOTES:
231: */
232: int
233: iso_pcbconnect(isop, nam)
234: register struct isopcb *isop;
235: struct mbuf *nam;
236: {
237: register struct sockaddr_iso *siso = mtod(nam, struct sockaddr_iso *);
238: int local_zero, error = 0;
239: struct iso_ifaddr *ia;
240:
241: IFDEBUG(D_ISO)
242: printf("iso_pcbconnect(isop 0x%x sock 0x%x nam 0x%x",
243: isop, isop->isop_socket, nam);
244: printf("nam->m_len 0x%x), addr:\n", nam->m_len);
245: dump_isoaddr(siso);
246: ENDDEBUG
247: if (nam->m_len < siso->siso_len)
248: return EINVAL;
249: if (siso->siso_family != AF_ISO)
250: return EAFNOSUPPORT;
251: if (siso->siso_nlen == 0) {
252: if (ia = iso_ifaddr) {
253: int nlen = ia->ia_addr.siso_nlen;
254: ovbcopy(TSEL(siso), nlen + TSEL(siso),
255: siso->siso_plen + siso->siso_tlen + siso->siso_slen);
256: bcopy((caddr_t)&ia->ia_addr.siso_addr,
257: (caddr_t)&siso->siso_addr, nlen + 1);
258: /* includes siso->siso_nlen = nlen; */
259: } else
260: return EADDRNOTAVAIL;
261: }
262: /*
263: * Local zero means either not bound, or bound to a TSEL, but no
264: * particular local interface. So, if we want to send somebody
265: * we need to choose a return address.
266: */
267: local_zero =
268: ((isop->isop_laddr == 0) || (isop->isop_laddr->siso_nlen == 0));
269: if (local_zero) {
270: int flags;
271:
272: IFDEBUG(D_ISO)
273: printf("iso_pcbconnect localzero 1\n");
274: ENDDEBUG
275: /*
276: * If route is known or can be allocated now,
277: * our src addr is taken from the i/f, else punt.
278: */
279: flags = isop->isop_socket->so_options & SO_DONTROUTE;
280: if (error = clnp_route(&siso->siso_addr, &isop->isop_route, flags,
281: (struct sockaddr **)0, &ia))
282: return error;
283: IFDEBUG(D_ISO)
284: printf("iso_pcbconnect localzero 2, ro->ro_rt 0x%x",
285: isop->isop_route.ro_rt);
286: printf(" ia 0x%x\n", ia);
287: ENDDEBUG
288: }
289: IFDEBUG(D_ISO)
290: printf("in iso_pcbconnect before lookup isop 0x%x isop->sock 0x%x\n",
291: isop, isop->isop_socket);
292: ENDDEBUG
293: if (local_zero) {
294: int nlen, tlen, totlen; caddr_t oldtsel, newtsel;
295: siso = isop->isop_laddr;
296: if (siso == 0 || siso->siso_tlen == 0)
297: (void)iso_pcbbind(isop, (struct mbuf *)0);
298: /*
299: * Here we have problem of squezeing in a definite network address
300: * into an existing sockaddr_iso, which in fact may not have room
301: * for it. This gets messy.
302: */
303: siso = isop->isop_laddr;
304: oldtsel = TSEL(siso);
305: tlen = siso->siso_tlen;
306: nlen = ia->ia_addr.siso_nlen;
307: totlen = tlen + nlen + _offsetof(struct sockaddr_iso, siso_data[0]);
308: if ((siso == &isop->isop_sladdr) &&
309: (totlen > sizeof(isop->isop_sladdr))) {
310: struct mbuf *m = m_get(MT_SONAME, M_DONTWAIT);
311: if (m == 0)
312: return ENOBUFS;
313: m->m_len = totlen;
314: isop->isop_laddr = siso = mtod(m, struct sockaddr_iso *);
315: }
316: siso->siso_nlen = ia->ia_addr.siso_nlen;
317: newtsel = TSEL(siso);
318: ovbcopy(oldtsel, newtsel, tlen);
319: bcopy(ia->ia_addr.siso_data, siso->siso_data, nlen);
320: siso->siso_tlen = tlen;
321: siso->siso_family = AF_ISO;
322: siso->siso_len = totlen;
323: siso = mtod(nam, struct sockaddr_iso *);
324: }
325: IFDEBUG(D_ISO)
326: printf("in iso_pcbconnect before bcopy isop 0x%x isop->sock 0x%x\n",
327: isop, isop->isop_socket);
328: ENDDEBUG
329: /*
330: * If we had to allocate space to a previous big foreign address,
331: * and for some reason we didn't free it, we reuse it knowing
332: * that is going to be big enough, as sockaddrs are delivered in
333: * 128 byte mbufs.
334: * If the foreign address is small enough, we use default space;
335: * otherwise, we grab an mbuf to copy into.
336: */
337: if (isop->isop_faddr == 0 || isop->isop_faddr == &isop->isop_sfaddr) {
338: if (siso->siso_len <= sizeof(isop->isop_sfaddr))
339: isop->isop_faddr = &isop->isop_sfaddr;
340: else {
341: struct mbuf *m = m_get(MT_SONAME, M_DONTWAIT);
342: if (m == 0)
343: return ENOBUFS;
344: isop->isop_faddr = mtod(m, struct sockaddr_iso *);
345: }
346: }
347: bcopy((caddr_t)siso, (caddr_t)isop->isop_faddr, siso->siso_len);
348: IFDEBUG(D_ISO)
349: printf("in iso_pcbconnect after bcopy isop 0x%x isop->sock 0x%x\n",
350: isop, isop->isop_socket);
351: printf("iso_pcbconnect connected to addr:\n");
352: dump_isoaddr(isop->isop_faddr);
353: printf("iso_pcbconnect end: src addr:\n");
354: dump_isoaddr(isop->isop_laddr);
355: ENDDEBUG
356: return 0;
357: }
358:
359: /*
360: * FUNCTION: iso_pcbdisconnect()
361: *
362: * PURPOSE: washes away the peer address info so the socket
363: * appears to be disconnected.
364: * If there's no file descriptor associated with the socket
365: * it detaches the pcb.
366: *
367: * RETURNS: Nada.
368: *
369: * SIDE EFFECTS: May detach the pcb.
370: *
371: * NOTES:
372: */
373: void
374: iso_pcbdisconnect(isop)
375: struct isopcb *isop;
376: {
377: void iso_pcbdetach();
378: register struct sockaddr_iso *siso;
379:
380: IFDEBUG(D_ISO)
381: printf("iso_pcbdisconnect(isop 0x%x)\n", isop);
382: ENDDEBUG
383: /*
384: * Preserver binding infnormation if already bound.
385: */
386: if ((siso = isop->isop_laddr) && siso->siso_nlen && siso->siso_tlen) {
387: caddr_t otsel = TSEL(siso);
388: siso->siso_nlen = 0;
389: ovbcopy(otsel, TSEL(siso), siso->siso_tlen);
390: }
391: if (isop->isop_faddr && isop->isop_faddr != &isop->isop_sfaddr)
392: m_freem(dtom(isop->isop_faddr));
393: isop->isop_faddr = 0;
394: if (isop->isop_socket->so_state & SS_NOFDREF)
395: iso_pcbdetach(isop);
396: }
397:
398: /*
399: * FUNCTION: iso_pcbdetach
400: *
401: * PURPOSE: detach the pcb at *(isop) from it's socket and free
402: * the mbufs associated with the pcb..
403: * Dequeues (isop) from its head.
404: *
405: * RETURNS: Nada.
406: *
407: * SIDE EFFECTS:
408: *
409: * NOTES:
410: */
411: void
412: iso_pcbdetach(isop)
413: struct isopcb *isop;
414: {
415: struct socket *so = isop->isop_socket;
416:
417: IFDEBUG(D_ISO)
418: printf("iso_pcbdetach(isop 0x%x socket 0x%x so 0x%x)\n",
419: isop, isop->isop_socket, so);
420: ENDDEBUG
421: if (so ) { /* in the x.25 domain, we sometimes have no socket */
422: so->so_pcb = 0;
423: sofree(so);
424: }
425: IFDEBUG(D_ISO)
426: printf("iso_pcbdetach 2 \n");
427: ENDDEBUG
428: if (isop->isop_options)
429: (void)m_free(isop->isop_options);
430: IFDEBUG(D_ISO)
431: printf("iso_pcbdetach 3 \n");
432: ENDDEBUG
433: if (isop->isop_route.ro_rt)
434: rtfree(isop->isop_route.ro_rt);
435: IFDEBUG(D_ISO)
436: printf("iso_pcbdetach 3.1\n");
437: ENDDEBUG
438: if (isop->isop_clnpcache != NULL) {
439: struct clnp_cache *clcp =
440: mtod(isop->isop_clnpcache, struct clnp_cache *);
441: IFDEBUG(D_ISO)
442: printf("iso_pcbdetach 3.2: clcp 0x%x freeing clc_hdr x%x\n",
443: clcp, clcp->clc_hdr);
444: ENDDEBUG
445: if (clcp->clc_hdr != NULL)
446: m_free(clcp->clc_hdr);
447: IFDEBUG(D_ISO)
448: printf("iso_pcbdetach 3.3: freeing cache x%x\n",
449: isop->isop_clnpcache);
450: ENDDEBUG
451: m_free(isop->isop_clnpcache);
452: }
453: IFDEBUG(D_ISO)
454: printf("iso_pcbdetach 4 \n");
455: ENDDEBUG
456: remque(isop);
457: IFDEBUG(D_ISO)
458: printf("iso_pcbdetach 5 \n");
459: ENDDEBUG
460: if (isop->isop_laddr && (isop->isop_laddr != &isop->isop_sladdr))
461: m_freem(dtom(isop->isop_laddr));
462: free((caddr_t)isop, M_PCB);
463: }
464:
465:
466: /*
467: * FUNCTION: iso_pcbnotify
468: *
469: * PURPOSE: notify all connections in this protocol's queue (head)
470: * that have peer address (dst) of the problem (errno)
471: * by calling (notify) on the connections' isopcbs.
472: *
473: * RETURNS: Rien.
474: *
475: * SIDE EFFECTS:
476: *
477: * NOTES: (notify) is called at splimp!
478: */
479: void
480: iso_pcbnotify(head, siso, errno, notify)
481: struct isopcb *head;
482: register struct sockaddr_iso *siso;
483: int errno, (*notify)();
484: {
485: register struct isopcb *isop;
486: int s = splimp();
487:
488: IFDEBUG(D_ISO)
489: printf("iso_pcbnotify(head 0x%x, notify 0x%x) dst:\n", head, notify);
490: ENDDEBUG
491: for (isop = head->isop_next; isop != head; isop = isop->isop_next) {
492: if (isop->isop_socket == 0 || isop->isop_faddr == 0 ||
493: !SAME_ISOADDR(siso, isop->isop_faddr)) {
494: IFDEBUG(D_ISO)
495: printf("iso_pcbnotify: CONTINUE isop 0x%x, sock 0x%x\n" ,
496: isop, isop->isop_socket);
497: printf("addrmatch cmp'd with (0x%x):\n", isop->isop_faddr);
498: dump_isoaddr(isop->isop_faddr);
499: ENDDEBUG
500: continue;
501: }
502: if (errno)
503: isop->isop_socket->so_error = errno;
504: if (notify)
505: (*notify)(isop);
506: }
507: splx(s);
508: IFDEBUG(D_ISO)
509: printf("END OF iso_pcbnotify\n" );
510: ENDDEBUG
511: }
512:
513:
514: /*
515: * FUNCTION: iso_pcblookup
516: *
517: * PURPOSE: looks for a given combination of (faddr), (fport),
518: * (lport), (laddr) in the queue named by (head).
519: * Argument (flags) is ignored.
520: *
521: * RETURNS: ptr to the isopcb if it finds a connection matching
522: * these arguments, o.w. returns zero.
523: *
524: * SIDE EFFECTS:
525: *
526: * NOTES:
527: */
528: struct isopcb *
529: iso_pcblookup(head, fportlen, fport, laddr)
530: struct isopcb *head;
531: register struct sockaddr_iso *laddr;
532: caddr_t fport;
533: int fportlen;
534: {
535: register struct isopcb *isop;
536: register caddr_t lp = TSEL(laddr);
537: unsigned int llen = laddr->siso_tlen;
538:
539: IFDEBUG(D_ISO)
540: printf("iso_pcblookup(head 0x%x laddr 0x%x fport 0x%x)\n",
541: head, laddr, fport);
542: ENDDEBUG
543: for (isop = head->isop_next; isop != head; isop = isop->isop_next) {
544: if (isop->isop_laddr == 0 || isop->isop_laddr == laddr)
545: continue;
546: if (isop->isop_laddr->siso_tlen != llen)
547: continue;
548: if (bcmp(lp, TSEL(isop->isop_laddr), llen))
549: continue;
550: if (fportlen && isop->isop_faddr &&
551: bcmp(fport, TSEL(isop->isop_faddr), (unsigned)fportlen))
552: continue;
553: /* PHASE2
554: * addrmatch1 should be iso_addrmatch(a, b, mask)
555: * where mask is taken from isop->isop_laddrmask (new field)
556: * isop_lnetmask will also be available in isop
557: if (laddr != &zeroiso_addr &&
558: !iso_addrmatch1(laddr, &(isop->isop_laddr.siso_addr)))
559: continue;
560: */
561: if (laddr->siso_nlen && (!SAME_ISOADDR(laddr, isop->isop_laddr)))
562: continue;
563: return (isop);
564: }
565: return (struct isopcb *)0;
566: }
567: #endif ISO
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.