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