xref: /original-bsd/sys/netccitt/pk_usrreq.c (revision de3f5c4e)
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  *
12  *	@(#)pk_usrreq.c	7.13 (Berkeley) 05/03/91
13  */
14 
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"
22 #include "ioctl.h"
23 #include "user.h"
24 #include "stat.h"
25 
26 #include "../net/if.h"
27 
28 #include "x25.h"
29 #include "pk.h"
30 #include "pk_var.h"
31 
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 
43 pk_usrreq (so, req, m, nam, control)
44 struct socket *so;
45 int req;
46 register struct mbuf *m, *nam;
47 struct mbuf *control;
48 {
49 	register struct pklcd *lcp = (struct pklcd *) so -> so_pcb;
50 	register int error = 0;
51 
52 	if (req == PRU_CONTROL)
53 		return (pk_control (so, (int)m, (caddr_t)nam,
54 			(struct ifnet *)control));
55 	if (control && control -> m_len) {
56 		error = EINVAL;
57 		goto release;
58 	}
59 	if (lcp == NULL && req != PRU_ATTACH) {
60 		error = EINVAL;
61 		goto release;
62 	}
63 
64 /*
65 	pk_trace (pkcbhead, TR_USER, (struct pklcd *)0,
66 		req, (struct x25_packet *)0);
67 */
68 
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 		}
81 		lcp = pk_attach (so);
82 		if (lcp == 0)
83 			error = ENOBUFS;
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:
108 		error = pk_listen (lcp);
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);
119 		if (pk_checksockaddr (nam))
120 			return (EINVAL);
121 		error = pk_connect (lcp, mtod (nam, struct sockaddr_x25 *));
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:
151 		lcp -> lcd_rxcnt++;
152 		lcp -> lcd_template = pk_template (lcp -> lcd_lcn, X25_RR);
153 		pk_output (lcp);
154 		/*pk_flowcontrol (lcp, sbspace (&so -> so_rcv) <= 0, 1);*/
155 		break;
156 
157 	/*
158 	 *  Send INTERRUPT packet.
159 	 */
160 	case PRU_SENDOOB:
161 		if (m == 0) {
162 			MGETHDR(m, M_WAITOK, MT_OOBDATA);
163 			m -> m_pkthdr.len = m -> m_len = 1;
164 			*mtod (m, octet *) = 0;
165 		}
166 		if (m -> m_pkthdr.len > 32) {
167 			m_freem (m);
168 			error = EMSGSIZE;
169 			break;
170 		}
171 		MCHTYPE(m, MT_OOBDATA);
172 		/* FALLTHROUGH */
173 
174 	/*
175 	 *  Do send by placing data on the socket output queue.
176 	 */
177 	case PRU_SEND:
178 		if (control) {
179 			register struct cmsghdr *ch = mtod (m, struct cmsghdr *);
180 			control -> m_len -= sizeof (*ch);
181 			control -> m_data += sizeof (*ch);
182 			pk_ctloutput (PRCO_SETOPT, so, ch -> cmsg_level,
183 					ch -> cmsg_type, &control);
184 		}
185 		if (m)
186 			error = pk_send (lcp, m);
187 		break;
188 
189 	/*
190 	 *  Abort a virtual circuit. For example all completed calls
191 	 *  waiting acceptance.
192 	 */
193 	case PRU_ABORT:
194 		pk_disconnect (lcp);
195 		break;
196 
197 	/* Begin unimplemented hooks. */
198 
199 	case PRU_SHUTDOWN:
200 		error = EOPNOTSUPP;
201 		break;
202 
203 	case PRU_CONTROL:
204 		error = EOPNOTSUPP;
205 		break;
206 
207 	case PRU_SENSE:
208 #ifdef BSD4_3
209 		((struct stat *)m) -> st_blksize = so -> so_snd.sb_hiwat;
210 #else
211 		error = EOPNOTSUPP;
212 #endif
213 		break;
214 
215 	/* End unimplemented hooks. */
216 
217 	case PRU_SOCKADDR:
218 		if (lcp -> lcd_ceaddr == 0)
219 			return (EADDRNOTAVAIL);
220 		nam -> m_len = sizeof (struct sockaddr_x25);
221 		bcopy ((caddr_t)lcp -> lcd_ceaddr, mtod (nam, caddr_t),
222 			sizeof (struct sockaddr_x25));
223 		if (lcp -> lcd_flags & X25_OLDSOCKADDR)
224 			new_to_old (nam);
225 		break;
226 
227 	case PRU_PEERADDR:
228 		if (lcp -> lcd_state != DATA_TRANSFER)
229 			return (ENOTCONN);
230 		nam -> m_len = sizeof (struct sockaddr_x25);
231 		bcopy (lcp -> lcd_craddr ? (caddr_t)lcp -> lcd_craddr :
232 			(caddr_t)lcp -> lcd_ceaddr,
233 			mtod (nam, caddr_t), sizeof (struct sockaddr_x25));
234 		if (lcp -> lcd_flags & X25_OLDSOCKADDR)
235 			new_to_old (nam);
236 		break;
237 
238 	/*
239 	 *  Receive INTERRUPT packet.
240 	 */
241 	case PRU_RCVOOB:
242 		if (so -> so_options & SO_OOBINLINE) {
243 			register struct mbuf *n  = so -> so_rcv.sb_mb;
244 			if (n && n -> m_type == MT_OOBDATA) {
245 				unsigned len =  n -> m_pkthdr.len;
246 				so -> so_rcv.sb_mb = n -> m_nextpkt;
247 				if (len !=  n -> m_len &&
248 				    (n = m_pullup (n, len)) == 0)
249 					break;
250 				m -> m_len = len;
251 				bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len);
252 				m_freem (n);
253 			}
254 			break;
255 		}
256 		m -> m_len = 1;
257 		*mtod (m, char *) = lcp -> lcd_intrdata;
258 		break;
259 
260 	default:
261 		panic ("pk_usrreq");
262 	}
263 release:
264 	if (control != NULL)
265 		m_freem (control);
266 	return (error);
267 }
268 
269 /*
270  * If you want to use UBC X.25 level 3 in conjunction with some
271  * other X.25 level 2 driver, have the ifp -> if_ioctl routine
272  * assign pk_start to pkp -> pk_start when called with SIOCSIFCONF_X25.
273  */
274 /* ARGSUSED */
275 pk_start (lcp)
276 register struct pklcd *lcp;
277 {
278 	pk_output (lcp);
279 	return (0); /* XXX pk_output should return a value */
280 }
281 
282 /*ARGSUSED*/
283 pk_control (so, cmd, data, ifp)
284 struct socket *so;
285 int cmd;
286 caddr_t data;
287 register struct ifnet *ifp;
288 {
289 	register struct ifreq_x25 *ifr = (struct ifreq_x25 *)data;
290 	register struct ifaddr *ifa = 0;
291 	register struct x25_ifaddr *ia = 0;
292 	struct pklcd *dev_lcp = 0;
293 	int error, s, old_maxlcn;
294 	unsigned n;
295 
296 	/*
297 	 * Find address for this interface, if it exists.
298 	 */
299 	if (ifp)
300 		for (ifa = ifp -> if_addrlist; ifa; ifa = ifa -> ifa_next)
301 			if (ifa -> ifa_addr -> sa_family == AF_CCITT)
302 				break;
303 
304 	ia = (struct x25_ifaddr *)ifa;
305 	switch (cmd) {
306 	case SIOCGIFCONF_X25:
307 		if (ifa == 0)
308 			return (EADDRNOTAVAIL);
309 		ifr -> ifr_xc = ia -> ia_xc;
310 		return (0);
311 
312 	case SIOCSIFCONF_X25:
313 		if (error = suser (u.u_cred, &u.u_acflag))
314 			return (error);
315 		if (ifp == 0)
316 			panic ("pk_control");
317 		if (ifa == (struct ifaddr *)0) {
318 			register struct mbuf *m;
319 
320 			MALLOC(ia, struct x25_ifaddr *, sizeof (*ia),
321 				M_IFADDR, M_WAITOK);
322 			if (ia == 0)
323 				return (ENOBUFS);
324 			bzero ((caddr_t)ia, sizeof (*ia));
325 			if (ifa = ifp -> if_addrlist) {
326 				for ( ; ifa -> ifa_next; ifa = ifa -> ifa_next)
327 					;
328 				ifa -> ifa_next = &ia -> ia_ifa;
329 			} else
330 				ifp -> if_addrlist = &ia -> ia_ifa;
331 			ifa = &ia -> ia_ifa;
332 			ifa -> ifa_netmask = (struct sockaddr *)&ia -> ia_sockmask;
333 			ifa -> ifa_addr = (struct sockaddr *)&ia -> ia_xc.xc_addr;
334 			ia -> ia_xcp = &ia -> ia_xc;
335 			ia -> ia_ifp = ifp;
336 			ia -> ia_pkcb.pk_ia = ia;
337 			ia -> ia_pkcb.pk_next = pkcbhead;
338 			ia -> ia_pkcb.pk_state = DTE_WAITING;
339 			ia -> ia_pkcb.pk_start = pk_start;
340 			pkcbhead = &ia -> ia_pkcb;
341 		}
342 		old_maxlcn = ia -> ia_maxlcn;
343 		ia -> ia_xc = ifr -> ifr_xc;
344 		if (ia -> ia_chan && (ia -> ia_maxlcn != old_maxlcn)) {
345 			pk_restart (&ia -> ia_pkcb, X25_RESTART_NETWORK_CONGESTION);
346 			dev_lcp = ia -> ia_chan[0];
347 			free ((caddr_t)ia -> ia_chan, M_IFADDR);
348 			ia -> ia_chan = 0;
349 		}
350 		if (ia -> ia_chan == 0) {
351 			n = (ia -> ia_maxlcn + 1) * sizeof (struct pklcd *);
352 			ia -> ia_chan = (struct pklcd **) malloc (n, M_IFADDR, M_WAITOK);
353 			if (ia -> ia_chan) {
354 				bzero ((caddr_t)ia -> ia_chan, n);
355 				if (dev_lcp == 0)
356 					dev_lcp = pk_attach ((struct socket *)0);
357 				ia -> ia_chan[0] = dev_lcp;
358 				dev_lcp -> lcd_state = READY;
359 				dev_lcp -> lcd_pkp = &ia -> ia_pkcb;
360 			} else {
361 				if (dev_lcp)
362 					pk_close (dev_lcp);
363 				return (ENOBUFS);
364 			}
365 		}
366 		/*
367 		 * Give the interface a chance to initialize if this
368 		 * is its first address, and to validate the address.
369 		 */
370 		s = splimp();
371 		if (ifp -> if_ioctl)
372 			error = (*ifp -> if_ioctl)(ifp, SIOCSIFCONF_X25, ifa);
373 		if (error)
374 			ifp -> if_flags &= ~IFF_UP;
375 		splx (s);
376 		return (error);
377 
378 	default:
379 		if (ifp == 0 || ifp -> if_ioctl == 0)
380 			return (EOPNOTSUPP);
381 		return ((*ifp -> if_ioctl)(ifp, cmd, data));
382 	}
383 }
384 
385 pk_ctloutput (cmd, so, level, optname, mp)
386 struct socket *so;
387 struct mbuf **mp;
388 int cmd, level, optname;
389 {
390 	register struct mbuf *m = *mp;
391 	register struct pklcd *lcp = (struct pklcd *) so -> so_pcb;
392 	int error;
393 
394 	if (cmd == PRCO_SETOPT) switch (optname) {
395 	case PK_ACCTFILE:
396 		if (m == 0)
397 			return (EINVAL);
398 		if (m -> m_len)
399 			error = pk_accton (mtod (m, char *));
400 		else
401 			error = pk_accton ((char *)0);
402 		(void) m_freem (m);
403 		*mp = 0;
404 		return (error);
405 
406 	case PK_FACILITIES:
407 		if (m == 0)
408 			return (EINVAL);
409 		lcp -> lcd_facilities = m;
410 		*mp = 0;
411 		return (0);
412 	}
413 	if (*mp) {
414 		(void) m_freem (*mp);
415 		*mp = 0;
416 	}
417 	return (EOPNOTSUPP);
418 
419 }
420 
421 /*
422  * Do an in-place conversion of an "old style"
423  * socket address to the new style
424  */
425 
426 static
427 old_to_new (m)
428 register 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;
440 	newp -> x25_len = sizeof(*newp);
441 	newp -> x25_opts.op_flags = (oldp -> xaddr_facilities & X25_REVERSE_CHARGE)
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,
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 	}
451 	ocp = (caddr_t)oldp -> xaddr_userdata;
452 	ncp = newp -> x25_udata + 4;
453 	while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) {
454 		if (newp -> x25_udlen == 0)
455 			newp -> x25_udlen = 4;
456 		*ncp++ = *ocp++;
457 		newp -> x25_udlen++;
458 	}
459 	bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp));
460 	m -> m_len = sizeof (*newp);
461 }
462 
463 /*
464  * Do an in-place conversion of a new style
465  * socket address to the old style
466  */
467 
468 static
469 new_to_old (m)
470 register 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);
492 	if (newp -> x25_udlen > 4)
493 		bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata,
494 			(unsigned)(newp -> x25_udlen - 4));
495 
496 	bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp));
497 	m -> m_len = sizeof (*oldp);
498 }
499 
500 
501 pk_checksockaddr (m)
502 struct 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 }
519 
520 pk_send (lcp, m)
521 struct pklcd *lcp;
522 register struct mbuf *m;
523 {
524 	int mqbit = 0, error = 0;
525 	register struct x25_packet *xp;
526 	register struct socket *so;
527 
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;
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);
541 		sbinsertoob ( (so = lcp -> lcd_so) ?
542 			&so -> so_snd : &lcp -> lcd_sb, m);
543 		goto send;
544 	}
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) {
551 		if (m -> m_len < 1) {
552 			m_freem (m);
553 			return (EMSGSIZE);
554 		}
555 		mqbit = *(mtod (m, u_char *));
556 		m -> m_len--;
557 		m -> m_data++;
558 		m -> m_pkthdr.len--;
559 	}
560 	error = pk_fragment (lcp, m, mqbit & 0x80, mqbit & 0x40, 1);
561 send:
562 	if (error == 0 && lcp -> lcd_state == DATA_TRANSFER)
563 		lcp -> lcd_send (lcp); /* XXXXXXXXX fix pk_output!!! */
564 	return (error);
565 bad:
566 	if (m)
567 		m_freem (m);
568 	return (error);
569 }
570