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