get rid of dtom's in kernel
[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 *
5d3068dc 12 * @(#)pk_usrreq.c 7.9 (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:
5abb4ba0
KS
232 if (lcp -> lcd_intrconf_pending) {
233 error = ETOOMANYREFS;
234 break;
235 }
236 lcp -> lcd_intrcnt++;
237 xp = lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_INTERRUPT);
238 xp -> packet_data = 0;
239 (dtom (xp)) -> m_len++;
240 pk_output (lcp);
5d3068dc 241 m_freem (m);
5abb4ba0
KS
242 break;
243
244 default:
245 panic ("pk_usrreq");
246 }
dc8f6c26
KS
247release:
248 if (control != NULL)
249 m_freem(control);
5abb4ba0
KS
250 return (error);
251}
252
ffababe5
KS
253/*
254 * If you want to use UBC X.25 level 3 in conjunction with some
255 * other X.25 level 2 driver, have the ifp->if_ioctl routine
256 * assign pk_start to pkp -> pk_start when called with SIOCSIFCONF_X25.
257 */
258/* ARGSUSED */
259pk_start (lcp)
260register struct pklcd *lcp;
261{
262 extern int pk_send();
263
4507dea2 264 lcp -> lcd_send = pk_send;
ffababe5
KS
265 return (pk_output(lcp));
266}
267
5abb4ba0
KS
268/*ARGSUSED*/
269pk_control (so, cmd, data, ifp)
270struct socket *so;
271int cmd;
272caddr_t data;
273register struct ifnet *ifp;
274{
039be508 275 register struct ifreq_x25 *ifr = (struct ifreq_x25 *)data;
5abb4ba0 276 register struct ifaddr *ifa = 0;
dc8f6c26 277 register struct x25_ifaddr *ia = 0;
ffababe5 278 struct pklcd *dev_lcp = 0;
1c41f5e9 279 int error, s, old_maxlcn;
dc8f6c26 280 unsigned n;
5abb4ba0
KS
281
282 /*
283 * Find address for this interface, if it exists.
284 */
285 if (ifp)
286 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
039be508 287 if (ifa->ifa_addr->sa_family == AF_CCITT)
5abb4ba0
KS
288 break;
289
dc8f6c26 290 ia = (struct x25_ifaddr *)ifa;
5abb4ba0 291 switch (cmd) {
039be508 292 case SIOCGIFCONF_X25:
5abb4ba0
KS
293 if (ifa == 0)
294 return (EADDRNOTAVAIL);
4507dea2 295 ifr->ifr_xc = ia->ia_xc;
5abb4ba0
KS
296 return (0);
297
039be508 298 case SIOCSIFCONF_X25:
4507dea2
KS
299 if (error = suser(u.u_cred, &u.u_acflag))
300 return (error);
5abb4ba0
KS
301 if (ifp == 0)
302 panic("pk_control");
303 if (ifa == (struct ifaddr *)0) {
5abb4ba0
KS
304 register struct mbuf *m;
305
ffababe5
KS
306 MALLOC(ia, struct x25_ifaddr *, sizeof (*ia),
307 M_IFADDR, M_WAITOK);
308 if (ia == 0)
5abb4ba0 309 return (ENOBUFS);
1c41f5e9 310 bzero((caddr_t)ia, sizeof (*ia));
5abb4ba0
KS
311 if (ifa = ifp->if_addrlist) {
312 for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
313 ;
dc8f6c26 314 ifa->ifa_next = &ia->ia_ifa;
5abb4ba0 315 } else
dc8f6c26
KS
316 ifp->if_addrlist = &ia->ia_ifa;
317 ifa = &ia->ia_ifa;
dc8f6c26 318 ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask;
4507dea2 319 ifa->ifa_addr = (struct sockaddr *)&ia->ia_xc.xc_addr;
1c41f5e9 320 ia->ia_xcp = &ia->ia_xc;
039be508
KS
321 ia->ia_ifp = ifp;
322 ia->ia_pkcb.pk_ia = ia;
323 ia->ia_pkcb.pk_next = pkcbhead;
1c41f5e9 324 ia->ia_pkcb.pk_state = DTE_WAITING;
5d3068dc 325 ia->ia_pkcb.pk_start = pk_start;
039be508 326 pkcbhead = &ia->ia_pkcb;
5abb4ba0 327 }
1c41f5e9
KS
328 old_maxlcn = ia->ia_maxlcn;
329 ia->ia_xc = ifr->ifr_xc;
330 if (ia->ia_chan && (ia->ia_maxlcn != old_maxlcn)) {
4507dea2 331 pk_restart(&ia->ia_pkcb, X25_RESTART_NETWORK_CONGESTION);
ffababe5 332 dev_lcp = ia->ia_chan[0];
dc8f6c26 333 free((caddr_t)ia->ia_chan, M_IFADDR);
ffababe5 334 ia->ia_chan = 0;
dc8f6c26 335 }
ffababe5 336 if (ia->ia_chan == 0) {
1c41f5e9
KS
337 n = (ia->ia_maxlcn + 1) * sizeof(struct pklcd *);
338 ia->ia_chan = (struct pklcd **) malloc(n, M_IFADDR, M_WAITOK);
ffababe5
KS
339 if (ia->ia_chan) {
340 bzero((caddr_t)ia->ia_chan, n);
341 if (dev_lcp == 0)
342 dev_lcp = pk_attach((struct socket *)0);
4507dea2 343 ia->ia_chan[0] = dev_lcp;
1c41f5e9
KS
344 dev_lcp->lcd_state = READY;
345 dev_lcp->lcd_pkp = &ia->ia_pkcb;
ffababe5
KS
346 } else {
347 if (dev_lcp)
348 pk_close(dev_lcp);
ffababe5
KS
349 return (ENOBUFS);
350 }
039be508 351 }
5abb4ba0
KS
352 /*
353 * Give the interface a chance to initialize if this
354 * is its first address, and to validate the address.
355 */
dc8f6c26
KS
356 s = splimp();
357 if (ifp->if_ioctl)
4507dea2 358 error = (*ifp->if_ioctl)(ifp, SIOCSIFCONF_X25, ifa);
1c41f5e9
KS
359 if (error)
360 ifp->if_flags &= ~IFF_UP;
5abb4ba0 361 splx(s);
dc8f6c26 362 return (error);
5abb4ba0
KS
363
364 default:
365 if (ifp == 0 || ifp->if_ioctl == 0)
366 return (EOPNOTSUPP);
367 return ((*ifp->if_ioctl)(ifp, cmd, data));
368 }
369}
5abb4ba0 370
4507dea2
KS
371pk_ctloutput(cmd, so, level, optname, mp)
372struct socket *so;
373struct mbuf **mp;
374int cmd, level, optname;
375{
376 register struct mbuf *m = *mp;
377 int error;
378
379 if (cmd == PRCO_SETOPT) switch (optname) {
380 case PK_ACCTFILE:
381 if (m == 0)
382 return (EINVAL);
383 if (m->m_len)
384 error = pk_accton(mtod(m, char *));
385 else
386 error = pk_accton((char *)0);
387 (void) m_freem(m);
388 *mp = 0;
389 return (error);
390 }
391 if (*mp) {
392 (void) m_freem(*mp);
393 *mp = 0;
394 }
395 return (EOPNOTSUPP);
396
397}
398
5abb4ba0
KS
399/*
400 * Do an in-place conversion of an "old style"
401 * socket address to the new style
402 */
403
404static
405old_to_new (m)
406register struct mbuf *m;
407{
408 register struct x25_sockaddr *oldp;
409 register struct sockaddr_x25 *newp;
410 register char *ocp, *ncp;
411 struct sockaddr_x25 new;
412
413 oldp = mtod (m, struct x25_sockaddr *);
414 newp = &new;
415 bzero ((caddr_t)newp, sizeof (*newp));
416
417 newp -> x25_family = AF_CCITT;
418 newp->x25_opts.op_flags = (oldp->xaddr_facilities & X25_REVERSE_CHARGE)
419 | X25_MQBIT | X25_OLDSOCKADDR;
420 if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */
421 newp -> x25_opts.op_psize = X25_PS128;
422 bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr,
423 (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1));
424 bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4);
425 newp -> x25_udlen = 4;
426
427 ocp = (caddr_t)oldp -> xaddr_userdata;
428 ncp = newp -> x25_udata + 4;
429 while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) {
430 *ncp++ = *ocp++;
431 newp -> x25_udlen++;
432 }
433
434 bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp));
435 m->m_len = sizeof (*newp);
436}
437
438/*
439 * Do an in-place conversion of a new style
440 * socket address to the old style
441 */
442
443static
444new_to_old (m)
445register struct mbuf *m;
446{
447 register struct x25_sockaddr *oldp;
448 register struct sockaddr_x25 *newp;
449 register char *ocp, *ncp;
450 struct x25_sockaddr old;
451
452 oldp = &old;
453 newp = mtod (m, struct sockaddr_x25 *);
454 bzero ((caddr_t)oldp, sizeof (*oldp));
455
456 oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE;
457 if (newp -> x25_opts.op_psize == X25_PS128)
458 oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */
459 ocp = (char *)oldp -> xaddr_addr;
460 ncp = newp -> x25_addr;
461 while (*ncp) {
462 *ocp++ = *ncp++;
463 oldp -> xaddr_len++;
464 }
465
466 bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4);
467 bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata,
468 (unsigned)(newp -> x25_udlen - 4));
469
470 bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp));
471 m -> m_len = sizeof (*oldp);
472}
473
474pk_send (lcp, m)
1c41f5e9 475struct pklcd *lcp;
5abb4ba0
KS
476register struct mbuf *m;
477{
1c41f5e9 478 int mqbit = 0, error;
5abb4ba0 479
5abb4ba0
KS
480 /*
481 * Application has elected (at call setup time) to prepend
482 * a control byte to each packet written indicating m-bit
483 * and q-bit status. Examine and then discard this byte.
484 */
485 if (lcp -> lcd_flags & X25_MQBIT) {
5abb4ba0 486 if (m -> m_len < 1) {
1c41f5e9 487 m_freem (m);
5abb4ba0
KS
488 return (EMSGSIZE);
489 }
1c41f5e9 490 mqbit = *(mtod(m, u_char *));
5abb4ba0 491 m -> m_len--;
dc8f6c26 492 m -> m_data++;
1c41f5e9 493 m -> m_pkthdr.len--;
5abb4ba0 494 }
1c41f5e9
KS
495 if ((error = pk_fragment(lcp, m, mqbit & 0x80, mqbit &0x40, 1)) == 0)
496 error = pk_output (lcp);
497 return (error);
5abb4ba0 498}