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