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.15 (Berkeley) 06/26/91 13 */ 14 15 #include "param.h" 16 #include "systm.h" 17 #include "mbuf.h" 18 #include "socket.h" 19 #include "socketvar.h" 20 #include "protosw.h" 21 #include "errno.h" 22 #include "ioctl.h" 23 #include "user.h" 24 #include "stat.h" 25 26 #include "../net/if.h" 27 #include "../net/route.h" 28 29 #include "x25.h" 30 #include "pk.h" 31 #include "pk_var.h" 32 33 /* 34 * 35 * X.25 Packet level protocol interface to socket abstraction. 36 * 37 * Process an X.25 user request on a logical channel. If this is a send 38 * request then m is the mbuf chain of the send data. If this is a timer 39 * expiration (called from the software clock routine) them timertype is 40 * the particular timer. 41 * 42 */ 43 44 pk_usrreq (so, req, m, nam, control) 45 struct socket *so; 46 int req; 47 register struct mbuf *m, *nam; 48 struct mbuf *control; 49 { 50 register struct pklcd *lcp = (struct pklcd *) so -> so_pcb; 51 register int error = 0; 52 53 if (req == PRU_CONTROL) 54 return (pk_control (so, (int)m, (caddr_t)nam, 55 (struct ifnet *)control)); 56 if (control && control -> m_len) { 57 error = EINVAL; 58 goto release; 59 } 60 if (lcp == NULL && req != PRU_ATTACH) { 61 error = EINVAL; 62 goto release; 63 } 64 65 /* 66 pk_trace (pkcbhead, TR_USER, (struct pklcd *)0, 67 req, (struct x25_packet *)0); 68 */ 69 70 switch (req) { 71 /* 72 * X.25 attaches to socket via PRU_ATTACH and allocates a logical 73 * channel descriptor. If the socket is to receive connections, 74 * then the LISTEN state is entered. 75 */ 76 case PRU_ATTACH: 77 if (lcp) { 78 error = EISCONN; 79 /* Socket already connected. */ 80 break; 81 } 82 lcp = pk_attach (so); 83 if (lcp == 0) 84 error = ENOBUFS; 85 break; 86 87 /* 88 * Detach a logical channel from the socket. If the state of the 89 * channel is embryonic, simply discard it. Otherwise we have to 90 * initiate a PRU_DISCONNECT which will finish later. 91 */ 92 case PRU_DETACH: 93 pk_disconnect (lcp); 94 break; 95 96 /* 97 * Give the socket an address. 98 */ 99 case PRU_BIND: 100 if (nam -> m_len == sizeof (struct x25_sockaddr)) 101 old_to_new (nam); 102 error = pk_bind (lcp, nam); 103 break; 104 105 /* 106 * Prepare to accept connections. 107 */ 108 case PRU_LISTEN: 109 error = pk_listen (lcp); 110 break; 111 112 /* 113 * Initiate a CALL REQUEST to peer entity. Enter state SENT_CALL 114 * and mark the socket as connecting. Set timer waiting for 115 * CALL ACCEPT or CLEAR. 116 */ 117 case PRU_CONNECT: 118 if (nam -> m_len == sizeof (struct x25_sockaddr)) 119 old_to_new (nam); 120 if (pk_checksockaddr (nam)) 121 return (EINVAL); 122 error = pk_connect (lcp, mtod (nam, struct sockaddr_x25 *)); 123 break; 124 125 /* 126 * Initiate a disconnect to peer entity via a CLEAR REQUEST packet. 127 * The socket will be disconnected when we receive a confirmation 128 * or a clear collision. 129 */ 130 case PRU_DISCONNECT: 131 pk_disconnect (lcp); 132 break; 133 134 /* 135 * Accept an INCOMING CALL. Most of the work has already been done 136 * by pk_input. Just return the callers address to the user. 137 */ 138 case PRU_ACCEPT: 139 if (lcp -> lcd_craddr == NULL) 140 break; 141 bcopy ((caddr_t)lcp -> lcd_craddr, mtod (nam, caddr_t), 142 sizeof (struct sockaddr_x25)); 143 nam -> m_len = sizeof (struct sockaddr_x25); 144 if (lcp -> lcd_flags & X25_OLDSOCKADDR) 145 new_to_old (nam); 146 break; 147 148 /* 149 * After a receive, we should send a RR. 150 */ 151 case PRU_RCVD: 152 pk_flowcontrol (lcp, /*sbspace (&so -> so_rcv) <= */ 0, 1); 153 break; 154 155 /* 156 * Send INTERRUPT packet. 157 */ 158 case PRU_SENDOOB: 159 if (m == 0) { 160 MGETHDR(m, M_WAITOK, MT_OOBDATA); 161 m -> m_pkthdr.len = m -> m_len = 1; 162 *mtod (m, octet *) = 0; 163 } 164 if (m -> m_pkthdr.len > 32) { 165 m_freem (m); 166 error = EMSGSIZE; 167 break; 168 } 169 MCHTYPE(m, MT_OOBDATA); 170 /* FALLTHROUGH */ 171 172 /* 173 * Do send by placing data on the socket output queue. 174 */ 175 case PRU_SEND: 176 if (control) { 177 register struct cmsghdr *ch = mtod (m, struct cmsghdr *); 178 control -> m_len -= sizeof (*ch); 179 control -> m_data += sizeof (*ch); 180 error = pk_ctloutput (PRCO_SETOPT, so, ch -> cmsg_level, 181 ch -> cmsg_type, &control); 182 } 183 if (error == 0 && m) 184 error = pk_send (lcp, m); 185 break; 186 187 /* 188 * Abort a virtual circuit. For example all completed calls 189 * waiting acceptance. 190 */ 191 case PRU_ABORT: 192 pk_disconnect (lcp); 193 break; 194 195 /* Begin unimplemented hooks. */ 196 197 case PRU_SHUTDOWN: 198 error = EOPNOTSUPP; 199 break; 200 201 case PRU_CONTROL: 202 error = EOPNOTSUPP; 203 break; 204 205 case PRU_SENSE: 206 #ifdef BSD4_3 207 ((struct stat *)m) -> st_blksize = so -> so_snd.sb_hiwat; 208 #else 209 error = EOPNOTSUPP; 210 #endif 211 break; 212 213 /* End unimplemented hooks. */ 214 215 case PRU_SOCKADDR: 216 if (lcp -> lcd_ceaddr == 0) 217 return (EADDRNOTAVAIL); 218 nam -> m_len = sizeof (struct sockaddr_x25); 219 bcopy ((caddr_t)lcp -> lcd_ceaddr, mtod (nam, caddr_t), 220 sizeof (struct sockaddr_x25)); 221 if (lcp -> lcd_flags & X25_OLDSOCKADDR) 222 new_to_old (nam); 223 break; 224 225 case PRU_PEERADDR: 226 if (lcp -> lcd_state != DATA_TRANSFER) 227 return (ENOTCONN); 228 nam -> m_len = sizeof (struct sockaddr_x25); 229 bcopy (lcp -> lcd_craddr ? (caddr_t)lcp -> lcd_craddr : 230 (caddr_t)lcp -> lcd_ceaddr, 231 mtod (nam, caddr_t), sizeof (struct sockaddr_x25)); 232 if (lcp -> lcd_flags & X25_OLDSOCKADDR) 233 new_to_old (nam); 234 break; 235 236 /* 237 * Receive INTERRUPT packet. 238 */ 239 case PRU_RCVOOB: 240 if (so -> so_options & SO_OOBINLINE) { 241 register struct mbuf *n = so -> so_rcv.sb_mb; 242 if (n && n -> m_type == MT_OOBDATA) { 243 unsigned len = n -> m_pkthdr.len; 244 so -> so_rcv.sb_mb = n -> m_nextpkt; 245 if (len != n -> m_len && 246 (n = m_pullup (n, len)) == 0) 247 break; 248 m -> m_len = len; 249 bcopy (mtod (m, caddr_t), mtod (n, caddr_t), len); 250 m_freem (n); 251 } 252 break; 253 } 254 m -> m_len = 1; 255 *mtod (m, char *) = lcp -> lcd_intrdata; 256 break; 257 258 default: 259 panic ("pk_usrreq"); 260 } 261 release: 262 if (control != NULL) 263 m_freem (control); 264 return (error); 265 } 266 267 /* 268 * If you want to use UBC X.25 level 3 in conjunction with some 269 * other X.25 level 2 driver, have the ifp -> if_ioctl routine 270 * assign pk_start to ia -> ia_start when called with SIOCSIFCONF_X25. 271 */ 272 /* ARGSUSED */ 273 pk_start (lcp) 274 register struct pklcd *lcp; 275 { 276 pk_output (lcp); 277 return (0); /* XXX pk_output should return a value */ 278 } 279 280 #ifndef _offsetof 281 #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) 282 #endif 283 struct sockaddr_x25 pk_sockmask = { 284 _offsetof(struct sockaddr_x25, x25_addr[0]), 285 0, -1}; 286 287 /*ARGSUSED*/ 288 pk_control (so, cmd, data, ifp) 289 struct socket *so; 290 int cmd; 291 caddr_t data; 292 register struct ifnet *ifp; 293 { 294 register struct ifreq_x25 *ifr = (struct ifreq_x25 *)data; 295 register struct ifaddr *ifa = 0; 296 register struct x25_ifaddr *ia = 0; 297 struct pklcd *dev_lcp = 0; 298 int error, s, old_maxlcn; 299 unsigned n; 300 301 /* 302 * Find address for this interface, if it exists. 303 */ 304 if (ifp) 305 for (ifa = ifp -> if_addrlist; ifa; ifa = ifa -> ifa_next) 306 if (ifa -> ifa_addr -> sa_family == AF_CCITT) 307 break; 308 309 ia = (struct x25_ifaddr *)ifa; 310 switch (cmd) { 311 case SIOCGIFCONF_X25: 312 if (ifa == 0) 313 return (EADDRNOTAVAIL); 314 ifr -> ifr_xc = ia -> ia_xc; 315 return (0); 316 317 case SIOCSIFCONF_X25: 318 if (error = suser (u.u_cred, &u.u_acflag)) 319 return (error); 320 if (ifp == 0) 321 panic ("pk_control"); 322 if (ifa == (struct ifaddr *)0) { 323 register struct mbuf *m; 324 325 MALLOC(ia, struct x25_ifaddr *, sizeof (*ia), 326 M_IFADDR, M_WAITOK); 327 if (ia == 0) 328 return (ENOBUFS); 329 bzero ((caddr_t)ia, sizeof (*ia)); 330 if (ifa = ifp -> if_addrlist) { 331 for ( ; ifa -> ifa_next; ifa = ifa -> ifa_next) 332 ; 333 ifa -> ifa_next = &ia -> ia_ifa; 334 } else 335 ifp -> if_addrlist = &ia -> ia_ifa; 336 ifa = &ia -> ia_ifa; 337 ifa -> ifa_netmask = (struct sockaddr *)&pk_sockmask; 338 ifa -> ifa_addr = (struct sockaddr *)&ia -> ia_xc.xc_addr; 339 ifa -> ifa_dstaddr = (struct sockaddr *)&ia -> ia_dstaddr; /* XXX */ 340 ia -> ia_ifp = ifp; 341 ia -> ia_dstaddr.x25_family = AF_CCITT; 342 ia -> ia_dstaddr.x25_len = pk_sockmask.x25_len; 343 } else { 344 rtinit (ifa, (int)RTM_DELETE, 0); 345 } 346 old_maxlcn = ia -> ia_maxlcn; 347 ia -> ia_xc = ifr -> ifr_xc; 348 ia -> ia_dstaddr.x25_net = ia -> ia_xc.xc_addr.x25_net; 349 if (ia -> ia_maxlcn != old_maxlcn && old_maxlcn != 0) { 350 /* VERY messy XXX */ 351 register struct pkcb *pkp; 352 for (pkp = pkcbhead; pkp; pkp = pkp -> pk_next) 353 if (pkp -> pk_ia == ia) 354 pk_resize (pkp); 355 } 356 /* 357 * Give the interface a chance to initialize if this 358 * is its first address, and to validate the address. 359 */ 360 ia -> ia_start = pk_start; 361 s = splimp(); 362 if (ifp -> if_ioctl) 363 error = (*ifp -> if_ioctl)(ifp, SIOCSIFCONF_X25, ifa); 364 if (error) 365 ifp -> if_flags &= ~IFF_UP; 366 else 367 error = rtinit (ifa, (int)RTM_ADD, RTF_UP); 368 splx (s); 369 return (error); 370 371 default: 372 if (ifp == 0 || ifp -> if_ioctl == 0) 373 return (EOPNOTSUPP); 374 return ((*ifp -> if_ioctl)(ifp, cmd, data)); 375 } 376 } 377 378 pk_ctloutput (cmd, so, level, optname, mp) 379 struct socket *so; 380 struct mbuf **mp; 381 int cmd, level, optname; 382 { 383 register struct mbuf *m = *mp; 384 register struct pklcd *lcp = (struct pklcd *) so -> so_pcb; 385 int error = EOPNOTSUPP; 386 387 if (m == 0) 388 return (EINVAL); 389 if (cmd == PRCO_SETOPT) switch (optname) { 390 case PK_FACILITIES: 391 if (m == 0) 392 return (EINVAL); 393 lcp -> lcd_facilities = m; 394 *mp = 0; 395 return (0); 396 397 case PK_ACCTFILE: 398 if (m -> m_len) 399 error = pk_accton (mtod (m, char *)); 400 else 401 error = pk_accton ((char *)0); 402 break; 403 404 case PK_RTATTACH: 405 error = pk_rtattach (so, m); 406 break; 407 408 case PK_PRLISTEN: 409 error = pk_user_protolisten (mtod (m, u_char *)); 410 } 411 if (*mp) { 412 (void) m_freem (*mp); 413 *mp = 0; 414 } 415 return (error); 416 417 } 418 419 420 /* 421 * Do an in-place conversion of an "old style" 422 * socket address to the new style 423 */ 424 425 static 426 old_to_new (m) 427 register struct mbuf *m; 428 { 429 register struct x25_sockaddr *oldp; 430 register struct sockaddr_x25 *newp; 431 register char *ocp, *ncp; 432 struct sockaddr_x25 new; 433 434 oldp = mtod (m, struct x25_sockaddr *); 435 newp = &new; 436 bzero ((caddr_t)newp, sizeof (*newp)); 437 438 newp -> x25_family = AF_CCITT; 439 newp -> x25_len = sizeof(*newp); 440 newp -> x25_opts.op_flags = (oldp -> xaddr_facilities & X25_REVERSE_CHARGE) 441 | X25_MQBIT | X25_OLDSOCKADDR; 442 if (oldp -> xaddr_facilities & XS_HIPRIO) /* Datapac specific */ 443 newp -> x25_opts.op_psize = X25_PS128; 444 bcopy ((caddr_t)oldp -> xaddr_addr, newp -> x25_addr, 445 (unsigned)min (oldp -> xaddr_len, sizeof (newp -> x25_addr) - 1)); 446 if (bcmp ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4) != 0) { 447 bcopy ((caddr_t)oldp -> xaddr_proto, newp -> x25_udata, 4); 448 newp -> x25_udlen = 4; 449 } 450 ocp = (caddr_t)oldp -> xaddr_userdata; 451 ncp = newp -> x25_udata + 4; 452 while (*ocp && ocp < (caddr_t)oldp -> xaddr_userdata + 12) { 453 if (newp -> x25_udlen == 0) 454 newp -> x25_udlen = 4; 455 *ncp++ = *ocp++; 456 newp -> x25_udlen++; 457 } 458 bcopy ((caddr_t)newp, mtod (m, char *), sizeof (*newp)); 459 m -> m_len = sizeof (*newp); 460 } 461 462 /* 463 * Do an in-place conversion of a new style 464 * socket address to the old style 465 */ 466 467 static 468 new_to_old (m) 469 register struct mbuf *m; 470 { 471 register struct x25_sockaddr *oldp; 472 register struct sockaddr_x25 *newp; 473 register char *ocp, *ncp; 474 struct x25_sockaddr old; 475 476 oldp = &old; 477 newp = mtod (m, struct sockaddr_x25 *); 478 bzero ((caddr_t)oldp, sizeof (*oldp)); 479 480 oldp -> xaddr_facilities = newp -> x25_opts.op_flags & X25_REVERSE_CHARGE; 481 if (newp -> x25_opts.op_psize == X25_PS128) 482 oldp -> xaddr_facilities |= XS_HIPRIO; /* Datapac specific */ 483 ocp = (char *)oldp -> xaddr_addr; 484 ncp = newp -> x25_addr; 485 while (*ncp) { 486 *ocp++ = *ncp++; 487 oldp -> xaddr_len++; 488 } 489 490 bcopy (newp -> x25_udata, (caddr_t)oldp -> xaddr_proto, 4); 491 if (newp -> x25_udlen > 4) 492 bcopy (newp -> x25_udata + 4, (caddr_t)oldp -> xaddr_userdata, 493 (unsigned)(newp -> x25_udlen - 4)); 494 495 bcopy ((caddr_t)oldp, mtod (m, char *), sizeof (*oldp)); 496 m -> m_len = sizeof (*oldp); 497 } 498 499 500 pk_checksockaddr (m) 501 struct mbuf *m; 502 { 503 register struct sockaddr_x25 *sa = mtod (m, struct sockaddr_x25 *); 504 register char *cp; 505 506 if (m -> m_len != sizeof (struct sockaddr_x25)) 507 return (1); 508 if (sa -> x25_family != AF_CCITT || 509 sa -> x25_udlen > sizeof (sa -> x25_udata)) 510 return (1); 511 for (cp = sa -> x25_addr; *cp; cp++) { 512 if (*cp < '0' || *cp > '9' || 513 cp >= &sa -> x25_addr[sizeof (sa -> x25_addr) - 1]) 514 return (1); 515 } 516 return (0); 517 } 518 519 pk_send (lcp, m) 520 struct pklcd *lcp; 521 register struct mbuf *m; 522 { 523 int mqbit = 0, error = 0; 524 register struct x25_packet *xp; 525 register struct socket *so; 526 527 if (m -> m_type == MT_OOBDATA) { 528 if (lcp -> lcd_intrconf_pending) 529 error = ETOOMANYREFS; 530 if (m -> m_pkthdr.len > 32) 531 error = EMSGSIZE; 532 M_PREPEND(m, PKHEADERLN, M_WAITOK); 533 if (m == 0 || error) 534 goto bad; 535 *(mtod (m, octet *)) = 0; 536 xp = mtod (m, struct x25_packet *); 537 xp -> fmt_identifier = 1; 538 xp -> packet_type = X25_INTERRUPT; 539 SET_LCN(xp, lcp -> lcd_lcn); 540 sbinsertoob ( (so = lcp -> lcd_so) ? 541 &so -> so_snd : &lcp -> lcd_sb, m); 542 goto send; 543 } 544 /* 545 * Application has elected (at call setup time) to prepend 546 * a control byte to each packet written indicating m-bit 547 * and q-bit status. Examine and then discard this byte. 548 */ 549 if (lcp -> lcd_flags & X25_MQBIT) { 550 if (m -> m_len < 1) { 551 m_freem (m); 552 return (EMSGSIZE); 553 } 554 mqbit = *(mtod (m, u_char *)); 555 m -> m_len--; 556 m -> m_data++; 557 m -> m_pkthdr.len--; 558 } 559 error = pk_fragment (lcp, m, mqbit & 0x80, mqbit & 0x40, 1); 560 send: 561 if (error == 0 && lcp -> lcd_state == DATA_TRANSFER) 562 lcp -> lcd_send (lcp); /* XXXXXXXXX fix pk_output!!! */ 563 return (error); 564 bad: 565 if (m) 566 m_freem (m); 567 return (error); 568 } 569