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