]> git.saurik.com Git - apple/xnu.git/blob - bsd/netccitt/pk_usrreq.c
ba1cb95000094f280162674c37543c10d694a053
[apple/xnu.git] / bsd / netccitt / pk_usrreq.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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.
11 *
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
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) University of British Columbia, 1984
24 * Copyright (C) Computer Science Department IV,
25 * University of Erlangen-Nuremberg, Germany, 1992
26 * Copyright (c) 1991, 1992, 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * This code is derived from software contributed to Berkeley by the
30 * Laboratory for Computation Vision and the Computer Science Department
31 * of the the University of British Columbia and the Computer Science
32 * Department (IV) of the University of Erlangen-Nuremberg, Germany.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 * 1. Redistributions of source code must retain the above copyright
38 * notice, this list of conditions and the following disclaimer.
39 * 2. Redistributions in binary form must reproduce the above copyright
40 * notice, this list of conditions and the following disclaimer in the
41 * documentation and/or other materials provided with the distribution.
42 * 3. All advertising materials mentioning features or use of this software
43 * must display the following acknowledgement:
44 * This product includes software developed by the University of
45 * California, Berkeley and its contributors.
46 * 4. Neither the name of the University nor the names of its contributors
47 * may be used to endorse or promote products derived from this software
48 * without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
51 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
52 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
53 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
54 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
55 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
56 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
57 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
58 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
59 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * SUCH DAMAGE.
61 *
62 * @(#)pk_usrreq.c 8.1 (Berkeley) 6/10/93
63 */
64
65 #include <sys/param.h>
66 #include <sys/systm.h>
67 #include <sys/mbuf.h>
68 #include <sys/socket.h>
69 #include <sys/socketvar.h>
70 #include <sys/protosw.h>
71 #include <sys/errno.h>
72 #include <sys/ioctl.h>
73 #include <sys/stat.h>
74 #include <sys/malloc.h>
75
76 #include <net/if.h>
77 #include <net/if_types.h>
78 #include <net/route.h>
79
80 #include <netccitt/x25.h>
81 #include <netccitt/pk.h>
82 #include <netccitt/pk_var.h>
83
84 static old_to_new();
85 static new_to_old();
86 /*
87 *
88 * X.25 Packet level protocol interface to socket abstraction.
89 *
90 * Process an X.25 user request on a logical channel. If this is a send
91 * request then m is the mbuf chain of the send data. If this is a timer
92 * expiration (called from the software clock routine) them timertype is
93 * the particular timer.
94 *
95 */
96
97 pk_usrreq (so, req, m, nam, control)
98 struct socket *so;
99 int req;
100 register struct mbuf *m, *nam;
101 struct mbuf *control;
102 {
103 register struct pklcd *lcp = (struct pklcd *) so -> so_pcb;
104 register int error = 0;
105
106 if (req == PRU_CONTROL)
107 return (pk_control (so, (int)m, (caddr_t)nam,
108 (struct ifnet *)control));
109 if (control && control -> m_len) {
110 error = EINVAL;
111 goto release;
112 }
113 if (lcp == NULL && req != PRU_ATTACH) {
114 error = EINVAL;
115 goto release;
116 }
117
118 /*
119 pk_trace (pkcbhead, TR_USER, (struct pklcd *)0,
120 req, (struct x25_packet *)0);
121 */
122
123 switch (req) {
124 /*
125 * X.25 attaches to socket via PRU_ATTACH and allocates a logical
126 * channel descriptor. If the socket is to receive connections,
127 * then the LISTEN state is entered.
128 */
129 case PRU_ATTACH:
130 if (lcp) {
131 error = EISCONN;
132 /* Socket already connected. */
133 break;
134 }
135 lcp = pk_attach (so);
136 if (lcp == 0)
137 error = ENOBUFS;
138 break;
139
140 /*
141 * Detach a logical channel from the socket. If the state of the
142 * channel is embryonic, simply discard it. Otherwise we have to
143 * initiate a PRU_DISCONNECT which will finish later.
144 */
145 case PRU_DETACH:
146 pk_disconnect (lcp);
147 break;
148
149 /*
150 * Give the socket an address.
151 */
152 case PRU_BIND:
153 if (nam -> m_len == sizeof (struct x25_sockaddr))
154 old_to_new (nam);
155 error = pk_bind (lcp, nam);
156 break;
157
158 /*
159 * Prepare to accept connections.
160 */
161 case PRU_LISTEN:
162 error = pk_listen (lcp);
163 break;
164
165 /*
166 * Initiate a CALL REQUEST to peer entity. Enter state SENT_CALL
167 * and mark the socket as connecting. Set timer waiting for
168 * CALL ACCEPT or CLEAR.
169 */
170 case PRU_CONNECT:
171 if (nam -> m_len == sizeof (struct x25_sockaddr))
172 old_to_new (nam);
173 if (pk_checksockaddr (nam))
174 return (EINVAL);
175 error = pk_connect (lcp, mtod (nam, struct sockaddr_x25 *));
176 break;
177
178 /*
179 * Initiate a disconnect to peer entity via a CLEAR REQUEST packet.
180 * The socket will be disconnected when we receive a confirmation
181 * or a clear collision.
182 */
183 case PRU_DISCONNECT:
184 pk_disconnect (lcp);
185 break;
186
187 /*
188 * Accept an INCOMING CALL. Most of the work has already been done
189 * by pk_input. Just return the callers address to the user.
190 */
191 case PRU_ACCEPT:
192 if (lcp -> lcd_craddr == NULL)
193 break;
194 bcopy ((caddr_t)lcp -> lcd_craddr, mtod (nam, caddr_t),
195 sizeof (struct sockaddr_x25));
196 nam -> m_len = sizeof (struct sockaddr_x25);
197 if (lcp -> lcd_flags & X25_OLDSOCKADDR)
198 new_to_old (nam);
199 break;
200
201 /*
202 * After a receive, we should send a RR.
203 */
204 case PRU_RCVD:
205 pk_flowcontrol (lcp, /*sbspace (&so -> so_rcv) <= */ 0, 1);
206 break;
207
208 /*
209 * Send INTERRUPT packet.
210 */
211 case PRU_SENDOOB:
212 if (m == 0) {
213 MGETHDR(m, M_WAITOK, MT_OOBDATA);
214 m -> m_pkthdr.len = m -> m_len = 1;
215 *mtod (m, octet *) = 0;
216 }
217 if (m -> m_pkthdr.len > 32) {
218 m_freem (m);
219 error = EMSGSIZE;
220 break;
221 }
222 MCHTYPE(m, MT_OOBDATA);
223 /* FALLTHROUGH */
224
225 /*
226 * Do send by placing data on the socket output queue.
227 */
228 case PRU_SEND:
229 if (control) {
230 register struct cmsghdr *ch = mtod (m, struct cmsghdr *);
231 control -> m_len -= sizeof (*ch);
232 control -> m_data += sizeof (*ch);
233 error = pk_ctloutput (PRCO_SETOPT, so, ch -> cmsg_level,
234 ch -> cmsg_type, &control);
235 }
236 if (error == 0 && m)
237 error = pk_send (lcp, m);
238 break;
239
240 /*
241 * Abort a virtual circuit. For example all completed calls
242 * waiting acceptance.
243 */
244 case PRU_ABORT:
245 pk_disconnect (lcp);
246 break;
247
248 /* Begin unimplemented hooks. */
249
250 case PRU_SHUTDOWN:
251 error = EOPNOTSUPP;
252 break;
253
254 case PRU_CONTROL:
255 error = EOPNOTSUPP;
256 break;
257
258 case PRU_SENSE:
259 #ifdef BSD4_3
260 ((struct stat *)m) -> st_blksize = so -> so_snd.sb_hiwat;
261 #else
262 error = EOPNOTSUPP;
263 #endif
264 break;
265
266 /* End unimplemented hooks. */
267
268 case PRU_SOCKADDR:
269 if (lcp -> lcd_ceaddr == 0)
270 return (EADDRNOTAVAIL);
271 nam -> m_len = sizeof (struct sockaddr_x25);
272 bcopy ((caddr_t)lcp -> lcd_ceaddr, mtod (nam, caddr_t),
273 sizeof (struct sockaddr_x25));
274 if (lcp -> lcd_flags & X25_OLDSOCKADDR)
275 new_to_old (nam);
276 break;
277
278 case PRU_PEERADDR:
279 if (lcp -> lcd_state != DATA_TRANSFER)
280 return (ENOTCONN);
281 nam -> m_len = sizeof (struct sockaddr_x25);
282 bcopy (lcp -> lcd_craddr ? (caddr_t)lcp -> lcd_craddr :
283 (caddr_t)lcp -> lcd_ceaddr,
284 mtod (nam, caddr_t), sizeof (struct sockaddr_x25));
285 if (lcp -> lcd_flags & X25_OLDSOCKADDR)
286 new_to_old (nam);
287 break;
288
289 /*
290 * Receive INTERRUPT packet.
291 */
292 case PRU_RCVOOB:
293 if (so -> so_options & SO_OOBINLINE) {
294 register struct mbuf *n = so -> so_rcv.sb_mb;
295 if (n && n -> m_type == MT_OOBDATA) {
296 unsigned len = n -> m_pkthdr.len;
297 so -> so_rcv.sb_mb = n -> m_nextpkt;
298 if (len != n -> m_len &&
299 (n = m_pullup (n, len)) == 0)
300 break;
301 m -> m_len = len;
302 bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len);
303 m_freem (n);
304 }
305 break;
306 }
307 m -> m_len = 1;
308 *mtod (m, char *) = lcp -> lcd_intrdata;
309 break;
310
311 default:
312 panic ("pk_usrreq");
313 }
314 release:
315 if (control != NULL)
316 m_freem (control);
317 return (error);
318 }
319
320 /*
321 * If you want to use UBC X.25 level 3 in conjunction with some
322 * other X.25 level 2 driver, have the ifp -> if_ioctl routine
323 * assign pk_start to ia -> ia_start when called with SIOCSIFCONF_X25.
324 */
325 /* ARGSUSED */
326 pk_start (lcp)
327 register struct pklcd *lcp;
328 {
329 pk_output (lcp);
330 return (0); /* XXX pk_output should return a value */
331 }
332
333 #ifndef _offsetof
334 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
335 #endif
336 struct sockaddr_x25 pk_sockmask = {
337 _offsetof(struct sockaddr_x25, x25_addr[0]), /* x25_len */
338 0, /* x25_family */
339 -1, /* x25_net id */
340 };
341
342 /*ARGSUSED*/
343 pk_control (so, cmd, data, ifp)
344 struct socket *so;
345 int cmd;
346 caddr_t data;
347 register struct ifnet *ifp;
348 {
349 register struct ifreq_x25 *ifr = (struct ifreq_x25 *)data;
350 register struct ifaddr *ifa = 0;
351 register struct x25_ifaddr *ia = 0;
352 struct pklcd *dev_lcp = 0;
353 int error, s, old_maxlcn;
354 unsigned n;
355
356 /*
357 * Find address for this interface, if it exists.
358 */
359 if (ifp)
360 for (ifa = ifp -> if_addrlist; ifa; ifa = ifa -> ifa_next)
361 if (ifa -> ifa_addr -> sa_family == AF_CCITT)
362 break;
363
364 ia = (struct x25_ifaddr *)ifa;
365 switch (cmd) {
366 case SIOCGIFCONF_X25:
367 if (ifa == 0)
368 return (EADDRNOTAVAIL);
369 ifr -> ifr_xc = ia -> ia_xc;
370 return (0);
371
372 case SIOCSIFCONF_X25:
373 if ((so->so_state & SS_PRIV) == 0)
374 return (EPERM);
375 if (ifp == 0)
376 panic ("pk_control");
377 if (ifa == (struct ifaddr *)0) {
378 register struct mbuf *m;
379
380 MALLOC(ia, struct x25_ifaddr *, sizeof (*ia),
381 M_IFADDR, M_WAITOK);
382 if (ia == 0)
383 return (ENOBUFS);
384 bzero ((caddr_t)ia, sizeof (*ia));
385 if (ifa = ifp -> if_addrlist) {
386 for ( ; ifa -> ifa_next; ifa = ifa -> ifa_next)
387 ;
388 ifa -> ifa_next = &ia -> ia_ifa;
389 } else
390 ifp -> if_addrlist = &ia -> ia_ifa;
391 ifa = &ia -> ia_ifa;
392 ifa -> ifa_netmask = (struct sockaddr *)&pk_sockmask;
393 ifa -> ifa_addr = (struct sockaddr *)&ia -> ia_xc.xc_addr;
394 ifa -> ifa_dstaddr = (struct sockaddr *)&ia -> ia_dstaddr; /* XXX */
395 ia -> ia_ifp = ifp;
396 ia -> ia_dstaddr.x25_family = AF_CCITT;
397 ia -> ia_dstaddr.x25_len = pk_sockmask.x25_len;
398 } else if (ISISO8802(ifp) == 0) {
399 rtinit (ifa, (int)RTM_DELETE, 0);
400 }
401 old_maxlcn = ia -> ia_maxlcn;
402 ia -> ia_xc = ifr -> ifr_xc;
403 ia -> ia_dstaddr.x25_net = ia -> ia_xc.xc_addr.x25_net;
404 if (ia -> ia_maxlcn != old_maxlcn && old_maxlcn != 0) {
405 /* VERY messy XXX */
406 register struct pkcb *pkp;
407 FOR_ALL_PKCBS(pkp)
408 if (pkp -> pk_ia == ia)
409 pk_resize (pkp);
410 }
411 /*
412 * Give the interface a chance to initialize if this
413 p * is its first address, and to validate the address.
414 */
415 ia -> ia_start = pk_start;
416 s = splimp();
417 if (ifp -> if_ioctl)
418 error = (*ifp -> if_ioctl)(ifp, SIOCSIFCONF_X25,
419 (caddr_t) ifa);
420 if (error)
421 ifp -> if_flags &= ~IFF_UP;
422 else if (ISISO8802(ifp) == 0)
423 error = rtinit (ifa, (int)RTM_ADD, RTF_UP);
424 splx (s);
425 return (error);
426
427 default:
428 if (ifp == 0 || ifp -> if_ioctl == 0)
429 return (EOPNOTSUPP);
430 return ((*ifp -> if_ioctl)(ifp, cmd, data));
431 }
432 }
433
434 pk_ctloutput (cmd, so, level, optname, mp)
435 struct socket *so;
436 struct mbuf **mp;
437 int cmd, level, optname;
438 {
439 register struct mbuf *m = *mp;
440 register struct pklcd *lcp = (struct pklcd *) so -> so_pcb;
441 int error = EOPNOTSUPP;
442
443 if (m == 0)
444 return (EINVAL);
445 if (cmd == PRCO_SETOPT) switch (optname) {
446 case PK_FACILITIES:
447 if (m == 0)
448 return (EINVAL);
449 lcp -> lcd_facilities = m;
450 *mp = 0;
451 return (0);
452
453 case PK_ACCTFILE:
454 if ((so->so_state & SS_PRIV) == 0)
455 error = EPERM;
456 else if (m -> m_len)
457 error = pk_accton (mtod (m, char *));
458 else
459 error = pk_accton ((char *)0);
460 break;
461
462 case PK_RTATTACH:
463 error = pk_rtattach (so, m);
464 break;
465
466 case PK_PRLISTEN:
467 error = pk_user_protolisten (mtod (m, u_char *));
468 }
469 if (*mp) {
470 (void) m_freem (*mp);
471 *mp = 0;
472 }
473 return (error);
474
475 }
476
477
478 /*
479 * Do an in-place conversion of an "old style"
480 * socket address to the new style
481 */
482
483 static
484 old_to_new (m)
485 register struct mbuf *m;
486 {
487 register struct x25_sockaddr *oldp;
488 register struct sockaddr_x25 *newp;
489 register char *ocp, *ncp;
490 struct sockaddr_x25 new;
491
492 oldp = mtod (m, struct x25_sockaddr *);
493 newp = &new;
494 bzero ((caddr_t)newp, sizeof (*newp));
495
496 newp -> x25_family = AF_CCITT;
497 newp -> x25_len = sizeof(*newp);
498 newp -> x25_opts.op_flags = (oldp -> xaddr_facilities & X25_REVERSE_CHARGE)
499 | X25_MQBIT | X25_OLDSOCKADDR;
500 if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */
501 newp -> x25_opts.op_psize = X25_PS128;
502 bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr,
503 (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1));
504 if (bcmp ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4) != 0) {
505 bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4);
506 newp -> x25_udlen = 4;
507 }
508 ocp = (caddr_t)oldp -> xaddr_userdata;
509 ncp = newp -> x25_udata + 4;
510 while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) {
511 if (newp -> x25_udlen == 0)
512 newp -> x25_udlen = 4;
513 *ncp++ = *ocp++;
514 newp -> x25_udlen++;
515 }
516 bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp));
517 m -> m_len = sizeof (*newp);
518 }
519
520 /*
521 * Do an in-place conversion of a new style
522 * socket address to the old style
523 */
524
525 static
526 new_to_old (m)
527 register struct mbuf *m;
528 {
529 register struct x25_sockaddr *oldp;
530 register struct sockaddr_x25 *newp;
531 register char *ocp, *ncp;
532 struct x25_sockaddr old;
533
534 oldp = &old;
535 newp = mtod (m, struct sockaddr_x25 *);
536 bzero ((caddr_t)oldp, sizeof (*oldp));
537
538 oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE;
539 if (newp -> x25_opts.op_psize == X25_PS128)
540 oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */
541 ocp = (char *)oldp -> xaddr_addr;
542 ncp = newp -> x25_addr;
543 while (*ncp) {
544 *ocp++ = *ncp++;
545 oldp -> xaddr_len++;
546 }
547
548 bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4);
549 if (newp -> x25_udlen > 4)
550 bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata,
551 (unsigned)(newp -> x25_udlen - 4));
552
553 bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp));
554 m -> m_len = sizeof (*oldp);
555 }
556
557
558 pk_checksockaddr (m)
559 struct mbuf *m;
560 {
561 register struct sockaddr_x25 *sa = mtod (m, struct sockaddr_x25 *);
562 register char *cp;
563
564 if (m -> m_len != sizeof (struct sockaddr_x25))
565 return (1);
566 if (sa -> x25_family != AF_CCITT ||
567 sa -> x25_udlen > sizeof (sa -> x25_udata))
568 return (1);
569 for (cp = sa -> x25_addr; *cp; cp++) {
570 if (*cp < '0' || *cp > '9' ||
571 cp >= &sa -> x25_addr[sizeof (sa -> x25_addr) - 1])
572 return (1);
573 }
574 return (0);
575 }
576
577 pk_send (lcp, m)
578 struct pklcd *lcp;
579 register struct mbuf *m;
580 {
581 int mqbit = 0, error = 0;
582 register struct x25_packet *xp;
583 register struct socket *so;
584
585 if (m -> m_type == MT_OOBDATA) {
586 if (lcp -> lcd_intrconf_pending)
587 error = ETOOMANYREFS;
588 if (m -> m_pkthdr.len > 32)
589 error = EMSGSIZE;
590 M_PREPEND(m, PKHEADERLN, M_WAITOK);
591 if (m == 0 || error)
592 goto bad;
593 *(mtod (m, octet *)) = 0;
594 xp = mtod (m, struct x25_packet *);
595 X25SBITS(xp -> bits, fmt_identifier, 1);
596 xp -> packet_type = X25_INTERRUPT;
597 SET_LCN(xp, lcp -> lcd_lcn);
598 sbinsertoob ( (so = lcp -> lcd_so) ?
599 &so -> so_snd : &lcp -> lcd_sb, m);
600 goto send;
601 }
602 /*
603 * Application has elected (at call setup time) to prepend
604 * a control byte to each packet written indicating m-bit
605 * and q-bit status. Examine and then discard this byte.
606 */
607 if (lcp -> lcd_flags & X25_MQBIT) {
608 if (m -> m_len < 1) {
609 m_freem (m);
610 return (EMSGSIZE);
611 }
612 mqbit = *(mtod (m, u_char *));
613 m -> m_len--;
614 m -> m_data++;
615 m -> m_pkthdr.len--;
616 }
617 error = pk_fragment (lcp, m, mqbit & 0x80, mqbit & 0x40, 1);
618 send:
619 if (error == 0 && lcp -> lcd_state == DATA_TRANSFER)
620 lcp -> lcd_send (lcp); /* XXXXXXXXX fix pk_output!!! */
621 return (error);
622 bad:
623 if (m)
624 m_freem (m);
625 return (error);
626 }