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