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