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