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