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