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.8 (Berkeley) 10/04/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, old_maxlcn; 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 bzero((caddr_t)ia, sizeof (*ia)); 313 if (ifa = ifp->if_addrlist) { 314 for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 315 ; 316 ifa->ifa_next = &ia->ia_ifa; 317 } else 318 ifp->if_addrlist = &ia->ia_ifa; 319 ifa = &ia->ia_ifa; 320 ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; 321 ifa->ifa_addr = (struct sockaddr *)&ia->ia_xc.xc_addr; 322 ia->ia_xcp = &ia->ia_xc; 323 ia->ia_ifp = ifp; 324 ia->ia_pkcb.pk_ia = ia; 325 ia->ia_pkcb.pk_next = pkcbhead; 326 ia->ia_pkcb.pk_state = DTE_WAITING; 327 pkcbhead = &ia->ia_pkcb; 328 } 329 old_maxlcn = ia->ia_maxlcn; 330 ia->ia_xc = ifr->ifr_xc; 331 if (ia->ia_chan && (ia->ia_maxlcn != old_maxlcn)) { 332 pk_restart(&ia->ia_pkcb, X25_RESTART_NETWORK_CONGESTION); 333 dev_lcp = ia->ia_chan[0]; 334 free((caddr_t)ia->ia_chan, M_IFADDR); 335 ia->ia_chan = 0; 336 } 337 if (ia->ia_chan == 0) { 338 n = (ia->ia_maxlcn + 1) * sizeof(struct pklcd *); 339 ia->ia_chan = (struct pklcd **) malloc(n, M_IFADDR, M_WAITOK); 340 if (ia->ia_chan) { 341 bzero((caddr_t)ia->ia_chan, n); 342 if (dev_lcp == 0) 343 dev_lcp = pk_attach((struct socket *)0); 344 ia->ia_chan[0] = dev_lcp; 345 dev_lcp->lcd_state = READY; 346 dev_lcp->lcd_pkp = &ia->ia_pkcb; 347 } else { 348 if (dev_lcp) 349 pk_close(dev_lcp); 350 return (ENOBUFS); 351 } 352 } 353 /* 354 * Give the interface a chance to initialize if this 355 * is its first address, and to validate the address. 356 */ 357 s = splimp(); 358 if (ifp->if_ioctl) 359 error = (*ifp->if_ioctl)(ifp, SIOCSIFCONF_X25, ifa); 360 if (error) 361 ifp->if_flags &= ~IFF_UP; 362 splx(s); 363 return (error); 364 365 default: 366 if (ifp == 0 || ifp->if_ioctl == 0) 367 return (EOPNOTSUPP); 368 return ((*ifp->if_ioctl)(ifp, cmd, data)); 369 } 370 } 371 372 pk_ctloutput(cmd, so, level, optname, mp) 373 struct socket *so; 374 struct mbuf **mp; 375 int cmd, level, optname; 376 { 377 register struct mbuf *m = *mp; 378 int error; 379 380 if (cmd == PRCO_SETOPT) switch (optname) { 381 case PK_ACCTFILE: 382 if (m == 0) 383 return (EINVAL); 384 if (m->m_len) 385 error = pk_accton(mtod(m, char *)); 386 else 387 error = pk_accton((char *)0); 388 (void) m_freem(m); 389 *mp = 0; 390 return (error); 391 } 392 if (*mp) { 393 (void) m_freem(*mp); 394 *mp = 0; 395 } 396 return (EOPNOTSUPP); 397 398 } 399 400 /* 401 * Do an in-place conversion of an "old style" 402 * socket address to the new style 403 */ 404 405 static 406 old_to_new (m) 407 register struct mbuf *m; 408 { 409 register struct x25_sockaddr *oldp; 410 register struct sockaddr_x25 *newp; 411 register char *ocp, *ncp; 412 struct sockaddr_x25 new; 413 414 oldp = mtod (m, struct x25_sockaddr *); 415 newp = &new; 416 bzero ((caddr_t)newp, sizeof (*newp)); 417 418 newp -> x25_family = AF_CCITT; 419 newp->x25_opts.op_flags = (oldp->xaddr_facilities & X25_REVERSE_CHARGE) 420 | X25_MQBIT | X25_OLDSOCKADDR; 421 if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */ 422 newp -> x25_opts.op_psize = X25_PS128; 423 bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr, 424 (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1)); 425 bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4); 426 newp -> x25_udlen = 4; 427 428 ocp = (caddr_t)oldp -> xaddr_userdata; 429 ncp = newp -> x25_udata + 4; 430 while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) { 431 *ncp++ = *ocp++; 432 newp -> x25_udlen++; 433 } 434 435 bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp)); 436 m->m_len = sizeof (*newp); 437 } 438 439 /* 440 * Do an in-place conversion of a new style 441 * socket address to the old style 442 */ 443 444 static 445 new_to_old (m) 446 register struct mbuf *m; 447 { 448 register struct x25_sockaddr *oldp; 449 register struct sockaddr_x25 *newp; 450 register char *ocp, *ncp; 451 struct x25_sockaddr old; 452 453 oldp = &old; 454 newp = mtod (m, struct sockaddr_x25 *); 455 bzero ((caddr_t)oldp, sizeof (*oldp)); 456 457 oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE; 458 if (newp -> x25_opts.op_psize == X25_PS128) 459 oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */ 460 ocp = (char *)oldp -> xaddr_addr; 461 ncp = newp -> x25_addr; 462 while (*ncp) { 463 *ocp++ = *ncp++; 464 oldp -> xaddr_len++; 465 } 466 467 bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4); 468 bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata, 469 (unsigned)(newp -> x25_udlen - 4)); 470 471 bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp)); 472 m -> m_len = sizeof (*oldp); 473 } 474 475 pk_send (lcp, m) 476 struct pklcd *lcp; 477 register struct mbuf *m; 478 { 479 int mqbit = 0, error; 480 481 /* 482 * Application has elected (at call setup time) to prepend 483 * a control byte to each packet written indicating m-bit 484 * and q-bit status. Examine and then discard this byte. 485 */ 486 if (lcp -> lcd_flags & X25_MQBIT) { 487 if (m -> m_len < 1) { 488 m_freem (m); 489 return (EMSGSIZE); 490 } 491 mqbit = *(mtod(m, u_char *)); 492 m -> m_len--; 493 m -> m_data++; 494 m -> m_pkthdr.len--; 495 } 496 if ((error = pk_fragment(lcp, m, mqbit & 0x80, mqbit &0x40, 1)) == 0) 497 error = pk_output (lcp); 498 return (error); 499 } 500