1 /*
2 * Copyright (c) University of British Columbia, 1984
3 * Copyright (C) Computer Science Department IV,
4 * University of Erlangen-Nuremberg, Germany, 1992
5 * Copyright (c) 1991, 1992, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
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.
12 *
13 * %sccs.include.redist.c%
14 *
15 * @(#)pk_usrreq.c 8.2 (Berkeley) 01/09/95
16 */
17
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>
27
28 #include <net/if.h>
29 #include <net/if_types.h>
30 #include <net/route.h>
31
32 #include <netccitt/x25.h>
33 #include <netccitt/pk.h>
34 #include <netccitt/pk_var.h>
35
36 static old_to_new();
37 static new_to_old();
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
49 pk_usrreq (so, req, m, nam, control)
50 struct socket *so;
51 int req;
52 register struct mbuf *m, *nam;
53 struct mbuf *control;
54 {
55 register struct pklcd *lcp = (struct pklcd *) so -> so_pcb;
56 register int error = 0;
57
58 if (req == PRU_CONTROL)
59 return (pk_control (so, (int)m, (caddr_t)nam,
60 (struct ifnet *)control));
61 if (control && control -> m_len) {
62 error = EINVAL;
63 goto release;
64 }
65 if (lcp == NULL && req != PRU_ATTACH) {
66 error = EINVAL;
67 goto release;
68 }
69
70 /*
71 pk_trace (pkcbhead, TR_USER, (struct pklcd *)0,
72 req, (struct x25_packet *)0);
73 */
74
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 }
87 lcp = pk_attach (so);
88 if (lcp == 0)
89 error = ENOBUFS;
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:
114 error = pk_listen (lcp);
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);
125 if (pk_checksockaddr (nam))
126 return (EINVAL);
127 error = pk_connect (lcp, mtod (nam, struct sockaddr_x25 *));
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:
157 pk_flowcontrol (lcp, /*sbspace (&so -> so_rcv) <= */ 0, 1);
158 break;
159
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;
167 *mtod (m, octet *) = 0;
168 }
169 if (m -> m_pkthdr.len > 32) {
170 m_freem (m);
171 error = EMSGSIZE;
172 break;
173 }
174 MCHTYPE(m, MT_OOBDATA);
175 /* FALLTHROUGH */
176
177 /*
178 * Do send by placing data on the socket output queue.
179 */
180 case PRU_SEND:
181 if (control) {
182 register struct cmsghdr *ch = mtod (m, struct cmsghdr *);
183 control -> m_len -= sizeof (*ch);
184 control -> m_data += sizeof (*ch);
185 error = pk_ctloutput (PRCO_SETOPT, so, ch -> cmsg_level,
186 ch -> cmsg_type, &control);
187 }
188 if (error == 0 && m)
189 error = pk_send (lcp, m);
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:
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 &&
251 (n = m_pullup (n, len)) == 0)
252 break;
253 m -> m_len = len;
254 bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len);
255 m_freem (n);
256 }
257 break;
258 }
259 m -> m_len = 1;
260 *mtod (m, char *) = lcp -> lcd_intrdata;
261 break;
262
263 default:
264 panic ("pk_usrreq");
265 }
266 release:
267 if (control != NULL)
268 m_freem (control);
269 return (error);
270 }
271
272 /*
273 * If you want to use UBC X.25 level 3 in conjunction with some
274 * other X.25 level 2 driver, have the ifp -> if_ioctl routine
275 * assign pk_start to ia -> ia_start when called with SIOCSIFCONF_X25.
276 */
277 /* ARGSUSED */
pk_start(lcp)278 pk_start (lcp)
279 register struct pklcd *lcp;
280 {
281 pk_output (lcp);
282 return (0); /* XXX pk_output should return a value */
283 }
284
285 #ifndef _offsetof
286 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m))
287 #endif
288 struct sockaddr_x25 pk_sockmask = {
289 _offsetof(struct sockaddr_x25, x25_addr[0]), /* x25_len */
290 0, /* x25_family */
291 -1, /* x25_net id */
292 };
293
294 /*ARGSUSED*/
295 pk_control (so, cmd, data, ifp)
296 struct socket *so;
297 u_long cmd;
298 caddr_t data;
299 register struct ifnet *ifp;
300 {
301 register struct ifreq_x25 *ifr = (struct ifreq_x25 *)data;
302 register struct ifaddr *ifa = 0;
303 register struct x25_ifaddr *ia = 0;
304 struct pklcd *dev_lcp = 0;
305 int error, s, old_maxlcn;
306 unsigned n;
307
308 /*
309 * Find address for this interface, if it exists.
310 */
311 if (ifp)
312 for (ifa = ifp -> if_addrlist; ifa; ifa = ifa -> ifa_next)
313 if (ifa -> ifa_addr -> sa_family == AF_CCITT)
314 break;
315
316 ia = (struct x25_ifaddr *)ifa;
317 switch (cmd) {
318 case SIOCGIFCONF_X25:
319 if (ifa == 0)
320 return (EADDRNOTAVAIL);
321 ifr -> ifr_xc = ia -> ia_xc;
322 return (0);
323
324 case SIOCSIFCONF_X25:
325 if ((so->so_state & SS_PRIV) == 0)
326 return (EPERM);
327 if (ifp == 0)
328 panic ("pk_control");
329 if (ifa == (struct ifaddr *)0) {
330 register struct mbuf *m;
331
332 MALLOC(ia, struct x25_ifaddr *, sizeof (*ia),
333 M_IFADDR, M_WAITOK);
334 if (ia == 0)
335 return (ENOBUFS);
336 bzero ((caddr_t)ia, sizeof (*ia));
337 if (ifa = ifp -> if_addrlist) {
338 for ( ; ifa -> ifa_next; ifa = ifa -> ifa_next)
339 ;
340 ifa -> ifa_next = &ia -> ia_ifa;
341 } else
342 ifp -> if_addrlist = &ia -> ia_ifa;
343 ifa = &ia -> ia_ifa;
344 ifa -> ifa_netmask = (struct sockaddr *)&pk_sockmask;
345 ifa -> ifa_addr = (struct sockaddr *)&ia -> ia_xc.xc_addr;
346 ifa -> ifa_dstaddr = (struct sockaddr *)&ia -> ia_dstaddr; /* XXX */
347 ia -> ia_ifp = ifp;
348 ia -> ia_dstaddr.x25_family = AF_CCITT;
349 ia -> ia_dstaddr.x25_len = pk_sockmask.x25_len;
350 } else if (ISISO8802(ifp) == 0) {
351 rtinit (ifa, (int)RTM_DELETE, 0);
352 }
353 old_maxlcn = ia -> ia_maxlcn;
354 ia -> ia_xc = ifr -> ifr_xc;
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;
359 FOR_ALL_PKCBS(pkp)
360 if (pkp -> pk_ia == ia)
361 pk_resize (pkp);
362 }
363 /*
364 * Give the interface a chance to initialize if this
365 p * is its first address, and to validate the address.
366 */
367 ia -> ia_start = pk_start;
368 s = splimp();
369 if (ifp -> if_ioctl)
370 error = (*ifp -> if_ioctl)(ifp, SIOCSIFCONF_X25,
371 (caddr_t) ifa);
372 if (error)
373 ifp -> if_flags &= ~IFF_UP;
374 else if (ISISO8802(ifp) == 0)
375 error = rtinit (ifa, (int)RTM_ADD, RTF_UP);
376 splx (s);
377 return (error);
378
379 default:
380 if (ifp == 0 || ifp -> if_ioctl == 0)
381 return (EOPNOTSUPP);
382 return ((*ifp -> if_ioctl)(ifp, cmd, data));
383 }
384 }
385
386 pk_ctloutput (cmd, so, level, optname, mp)
387 struct socket *so;
388 struct mbuf **mp;
389 int cmd, level, optname;
390 {
391 register struct mbuf *m = *mp;
392 register struct pklcd *lcp = (struct pklcd *) so -> so_pcb;
393 int error = EOPNOTSUPP;
394
395 if (m == 0)
396 return (EINVAL);
397 if (cmd == PRCO_SETOPT) switch (optname) {
398 case PK_FACILITIES:
399 if (m == 0)
400 return (EINVAL);
401 lcp -> lcd_facilities = m;
402 *mp = 0;
403 return (0);
404
405 case PK_ACCTFILE:
406 if ((so->so_state & SS_PRIV) == 0)
407 error = EPERM;
408 else if (m -> m_len)
409 error = pk_accton (mtod (m, char *));
410 else
411 error = pk_accton ((char *)0);
412 break;
413
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 *));
420 }
421 if (*mp) {
422 (void) m_freem (*mp);
423 *mp = 0;
424 }
425 return (error);
426
427 }
428
429
430 /*
431 * Do an in-place conversion of an "old style"
432 * socket address to the new style
433 */
434
435 static
old_to_new(m)436 old_to_new (m)
437 register 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;
449 newp -> x25_len = sizeof(*newp);
450 newp -> x25_opts.op_flags = (oldp -> xaddr_facilities & X25_REVERSE_CHARGE)
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,
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 }
460 ocp = (caddr_t)oldp -> xaddr_userdata;
461 ncp = newp -> x25_udata + 4;
462 while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) {
463 if (newp -> x25_udlen == 0)
464 newp -> x25_udlen = 4;
465 *ncp++ = *ocp++;
466 newp -> x25_udlen++;
467 }
468 bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp));
469 m -> m_len = sizeof (*newp);
470 }
471
472 /*
473 * Do an in-place conversion of a new style
474 * socket address to the old style
475 */
476
477 static
new_to_old(m)478 new_to_old (m)
479 register 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);
501 if (newp -> x25_udlen > 4)
502 bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata,
503 (unsigned)(newp -> x25_udlen - 4));
504
505 bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp));
506 m -> m_len = sizeof (*oldp);
507 }
508
509
510 pk_checksockaddr (m)
511 struct 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 }
528
529 pk_send (lcp, m)
530 struct pklcd *lcp;
531 register struct mbuf *m;
532 {
533 int mqbit = 0, error = 0;
534 register struct x25_packet *xp;
535 register struct socket *so;
536
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;
545 *(mtod (m, octet *)) = 0;
546 xp = mtod (m, struct x25_packet *);
547 X25SBITS(xp -> bits, fmt_identifier, 1);
548 xp -> packet_type = X25_INTERRUPT;
549 SET_LCN(xp, lcp -> lcd_lcn);
550 sbinsertoob ( (so = lcp -> lcd_so) ?
551 &so -> so_snd : &lcp -> lcd_sb, m);
552 goto send;
553 }
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) {
560 if (m -> m_len < 1) {
561 m_freem (m);
562 return (EMSGSIZE);
563 }
564 mqbit = *(mtod (m, u_char *));
565 m -> m_len--;
566 m -> m_data++;
567 m -> m_pkthdr.len--;
568 }
569 error = pk_fragment (lcp, m, mqbit & 0x80, mqbit & 0x40, 1);
570 send:
571 if (error == 0 && lcp -> lcd_state == DATA_TRANSFER)
572 lcp -> lcd_send (lcp); /* XXXXXXXXX fix pk_output!!! */
573 return (error);
574 bad:
575 if (m)
576 m_freem (m);
577 return (error);
578 }
579