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