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