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