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.7 (Berkeley) 08/30/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 switch (req) { 73 /* 74 * X.25 attaches to socket via PRU_ATTACH and allocates a logical 75 * channel descriptor. If the socket is to receive connections, 76 * then the LISTEN state is entered. 77 */ 78 case PRU_ATTACH: 79 if (lcp) { 80 error = EISCONN; 81 /* Socket already connected. */ 82 break; 83 } 84 lcp = pk_attach (so); 85 if (lcp == 0) 86 error = ENOBUFS; 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, (struct sockaddr_25 *)0); 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 /* 256 * If you want to use UBC X.25 level 3 in conjunction with some 257 * other X.25 level 2 driver, have the ifp->if_ioctl routine 258 * assign pk_start to pkp -> pk_start when called with SIOCSIFCONF_X25. 259 */ 260 /* ARGSUSED */ 261 pk_start (lcp) 262 register struct pklcd *lcp; 263 { 264 extern int pk_send(); 265 266 lcp -> lcd_send = pk_send; 267 return (pk_output(lcp)); 268 } 269 270 /*ARGSUSED*/ 271 pk_control (so, cmd, data, ifp) 272 struct socket *so; 273 int cmd; 274 caddr_t data; 275 register struct ifnet *ifp; 276 { 277 register struct ifreq_x25 *ifr = (struct ifreq_x25 *)data; 278 register struct ifaddr *ifa = 0; 279 register struct x25_ifaddr *ia = 0; 280 struct pklcd *dev_lcp = 0; 281 int error, s; 282 unsigned n; 283 284 /* 285 * Find address for this interface, if it exists. 286 */ 287 if (ifp) 288 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 289 if (ifa->ifa_addr->sa_family == AF_CCITT) 290 break; 291 292 ia = (struct x25_ifaddr *)ifa; 293 switch (cmd) { 294 case SIOCGIFCONF_X25: 295 if (ifa == 0) 296 return (EADDRNOTAVAIL); 297 ifr->ifr_xc = ia->ia_xc; 298 return (0); 299 300 case SIOCSIFCONF_X25: 301 if (error = suser(u.u_cred, &u.u_acflag)) 302 return (error); 303 if (ifp == 0) 304 panic("pk_control"); 305 if (ifa == (struct ifaddr *)0) { 306 register struct mbuf *m; 307 308 MALLOC(ia, struct x25_ifaddr *, sizeof (*ia), 309 M_IFADDR, M_WAITOK); 310 if (ia == 0) 311 return (ENOBUFS); 312 if (ifa = ifp->if_addrlist) { 313 for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 314 ; 315 ifa->ifa_next = &ia->ia_ifa; 316 } else 317 ifp->if_addrlist = &ia->ia_ifa; 318 ifa = &ia->ia_ifa; 319 ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; 320 ifa->ifa_addr = (struct sockaddr *)&ia->ia_xc.xc_addr; 321 ia->ia_ifp = ifp; 322 ia->ia_pkcb.pk_ia = ia; 323 ia->ia_pkcb.pk_next = pkcbhead; 324 pkcbhead = &ia->ia_pkcb; 325 } 326 ia->ia_xcp = &(ifr->ifr_xc); 327 if (ia->ia_chan && (ia->ia_maxlcn != ia->ia_xcp->xc_maxlcn)) { 328 pk_restart(&ia->ia_pkcb, X25_RESTART_NETWORK_CONGESTION); 329 dev_lcp = ia->ia_chan[0]; 330 free((caddr_t)ia->ia_chan, M_IFADDR); 331 ia->ia_chan = 0; 332 } 333 if (ia->ia_chan == 0) { 334 n = ia->ia_maxlcn * sizeof(struct pklcd *); 335 ia->ia_chan = (struct pklcd **) malloc(n, M_IFADDR); 336 if (ia->ia_chan) { 337 bzero((caddr_t)ia->ia_chan, n); 338 if (dev_lcp == 0) 339 dev_lcp = pk_attach((struct socket *)0); 340 ia->ia_chan[0] = dev_lcp; 341 } else { 342 if (dev_lcp) 343 pk_close(dev_lcp); 344 ia->ia_xcp = &ia->ia_xc; 345 return (ENOBUFS); 346 } 347 } 348 /* 349 * Give the interface a chance to initialize if this 350 * is its first address, and to validate the address. 351 */ 352 s = splimp(); 353 if (ifp->if_ioctl) 354 error = (*ifp->if_ioctl)(ifp, SIOCSIFCONF_X25, ifa); 355 splx(s); 356 if (error == 0) { 357 ia->ia_xc = *ia->ia_xcp; 358 } 359 ia->ia_xcp = &ia->ia_xc; 360 return (error); 361 362 default: 363 if (ifp == 0 || ifp->if_ioctl == 0) 364 return (EOPNOTSUPP); 365 return ((*ifp->if_ioctl)(ifp, cmd, data)); 366 } 367 } 368 369 pk_ctloutput(cmd, so, level, optname, mp) 370 struct socket *so; 371 struct mbuf **mp; 372 int cmd, level, optname; 373 { 374 register struct mbuf *m = *mp; 375 int error; 376 377 if (cmd == PRCO_SETOPT) switch (optname) { 378 case PK_ACCTFILE: 379 if (m == 0) 380 return (EINVAL); 381 if (m->m_len) 382 error = pk_accton(mtod(m, char *)); 383 else 384 error = pk_accton((char *)0); 385 (void) m_freem(m); 386 *mp = 0; 387 return (error); 388 } 389 if (*mp) { 390 (void) m_freem(*mp); 391 *mp = 0; 392 } 393 return (EOPNOTSUPP); 394 395 } 396 397 /* 398 * Do an in-place conversion of an "old style" 399 * socket address to the new style 400 */ 401 402 static 403 old_to_new (m) 404 register struct mbuf *m; 405 { 406 register struct x25_sockaddr *oldp; 407 register struct sockaddr_x25 *newp; 408 register char *ocp, *ncp; 409 struct sockaddr_x25 new; 410 411 oldp = mtod (m, struct x25_sockaddr *); 412 newp = &new; 413 bzero ((caddr_t)newp, sizeof (*newp)); 414 415 newp -> x25_family = AF_CCITT; 416 newp->x25_opts.op_flags = (oldp->xaddr_facilities & X25_REVERSE_CHARGE) 417 | X25_MQBIT | X25_OLDSOCKADDR; 418 if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */ 419 newp -> x25_opts.op_psize = X25_PS128; 420 bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr, 421 (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1)); 422 bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4); 423 newp -> x25_udlen = 4; 424 425 ocp = (caddr_t)oldp -> xaddr_userdata; 426 ncp = newp -> x25_udata + 4; 427 while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) { 428 *ncp++ = *ocp++; 429 newp -> x25_udlen++; 430 } 431 432 bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp)); 433 m->m_len = sizeof (*newp); 434 } 435 436 /* 437 * Do an in-place conversion of a new style 438 * socket address to the old style 439 */ 440 441 static 442 new_to_old (m) 443 register struct mbuf *m; 444 { 445 register struct x25_sockaddr *oldp; 446 register struct sockaddr_x25 *newp; 447 register char *ocp, *ncp; 448 struct x25_sockaddr old; 449 450 oldp = &old; 451 newp = mtod (m, struct sockaddr_x25 *); 452 bzero ((caddr_t)oldp, sizeof (*oldp)); 453 454 oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE; 455 if (newp -> x25_opts.op_psize == X25_PS128) 456 oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */ 457 ocp = (char *)oldp -> xaddr_addr; 458 ncp = newp -> x25_addr; 459 while (*ncp) { 460 *ocp++ = *ncp++; 461 oldp -> xaddr_len++; 462 } 463 464 bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4); 465 bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata, 466 (unsigned)(newp -> x25_udlen - 4)); 467 468 bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp)); 469 m -> m_len = sizeof (*oldp); 470 } 471 472 pk_send (lcp, m) 473 register struct pklcd *lcp; 474 register struct mbuf *m; 475 { 476 register struct x25_packet *xp; 477 register struct mbuf *m0; 478 register int len; 479 480 m0 = dtom ((xp = pk_template (lcp -> lcd_lcn, X25_DATA))); 481 m0 -> m_next = m; 482 /* 483 * Application has elected (at call setup time) to prepend 484 * a control byte to each packet written indicating m-bit 485 * and q-bit status. Examine and then discard this byte. 486 */ 487 if (lcp -> lcd_flags & X25_MQBIT) { 488 register octet *cp; 489 490 if (m -> m_len < 1) { 491 m_freem (m0); 492 return (EMSGSIZE); 493 } 494 cp = mtod (m, octet *); 495 if (*cp & 0x80) /* XXX */ 496 xp -> q_bit = 1; 497 xp -> packet_type |= (*cp & 0x40) >> 2; /* XXX */ 498 m -> m_len--; 499 m -> m_data++; 500 } 501 len = m -> m_len; 502 while (m -> m_next) { 503 m = m -> m_next; 504 len += m -> m_len; 505 } 506 if (len > (1 << lcp -> lcd_packetsize)) { 507 m_freem (m0); 508 return (EMSGSIZE); 509 } 510 if (lcp -> lcd_so) 511 sbappendrecord (&lcp -> lcd_so -> so_snd, m0); 512 else 513 sbappendrecord (&lcp -> lcd_sb, m0); 514 lcp -> lcd_template = 0; 515 lcp -> lcd_txcnt++; 516 pk_output (lcp); 517 return (0); 518 } 519