Print this page
onc plus-be-gone
   1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /* ONC_PLUS EXTRACT START */
  22 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  */
  26 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  27 /*        All Rights Reserved   */
  28 
  29 
  30 /*
  31  * Transport Interface Library cooperating module - issue 2
  32  */
  33 
  34 /* ONC_PLUS EXTRACT END */
  35 #include <sys/param.h>
  36 #include <sys/types.h>
  37 #include <sys/stream.h>
  38 #include <sys/stropts.h>
  39 #include <sys/strsubr.h>
  40 #define _SUN_TPI_VERSION 2
  41 #include <sys/tihdr.h>
  42 #include <sys/timod.h>
  43 #include <sys/suntpi.h>
  44 #include <sys/debug.h>
  45 #include <sys/strlog.h>
  46 #include <sys/errno.h>
  47 #include <sys/cred.h>
  48 #include <sys/cmn_err.h>
  49 #include <sys/kmem.h>
  50 #include <sys/sysmacros.h>
  51 #include <sys/ddi.h>
  52 #include <sys/sunddi.h>
  53 #include <sys/strsun.h>
  54 #include <c2/audit.h>


 178  *
 179  * There may be 3 states for transport:
 180  *
 181  * 1) It provides T_CAPABILITY_REQ
 182  * 2) It does not provide T_CAPABILITY_REQ
 183  * 3) It is not known yet whether transport provides T_CAPABILITY_REQ or not.
 184  *
 185  * It is assumed that the underlying transport either provides
 186  * T_CAPABILITY_REQ or not and this does not changes during the
 187  * system lifetime.
 188  *
 189  */
 190 #define PEEK_RDQ_EXPIND 0x0001  /* look for expinds on stream rd queues */
 191 #define WAITIOCACK      0x0002  /* waiting for info for ioctl act       */
 192 #define CLTS            0x0004  /* connectionless transport             */
 193 #define COTS            0x0008  /* connection-oriented transport        */
 194 #define CONNWAIT        0x0010  /* waiting for connect confirmation     */
 195 #define LOCORDREL       0x0020  /* local end has orderly released       */
 196 #define REMORDREL       0x0040  /* remote end had orderly released      */
 197 #define NAMEPROC        0x0080  /* processing a NAME ioctl              */
 198 /* ONC_PLUS EXTRACT START */
 199 #define DO_MYNAME       0x0100  /* timod handles TI_GETMYNAME           */
 200 /* ONC_PLUS EXTRACT END */
 201 #define DO_PEERNAME     0x0200  /* timod handles TI_GETPEERNAME         */
 202 #define TI_CAP_RECVD    0x0400  /* TI_CAPABILITY received               */
 203 #define CAP_WANTS_INFO  0x0800  /* TI_CAPABILITY has TC1_INFO set       */
 204 #define WAIT_IOCINFOACK 0x1000  /* T_INFO_REQ generated from ioctl      */
 205 #define WAIT_CONNRESACK 0x2000  /* waiting for T_OK_ACK to T_CONN_RES   */
 206 
 207 
 208 /* Debugging facilities */
 209 /*
 210  * Logging needed for debugging timod should only appear in DEBUG kernel.
 211  */
 212 #ifdef DEBUG
 213 #define TILOG(msg, arg)         tilog((msg), (arg))
 214 #define TILOGP(msg, arg)        tilogp((msg), (arg))
 215 #else
 216 #define TILOG(msg, arg)
 217 #define TILOGP(msg, arg)
 218 #endif
 219 
 220 


 296 #define TIM_HASH(id) (((uintptr_t)(id) >> 8) % TIM_HASH_SIZE)
 297 #else
 298 #define TIM_HASH(id) ((uintptr_t)(id) % TIM_HASH_SIZE)
 299 #endif  /* _ILP32 */
 300 static struct tim_tim   *tim_hash[TIM_HASH_SIZE];
 301 int             tim_cnt = 0;
 302 
 303 static void tilog(char *, t_scalar_t);
 304 static void tilogp(char *, uintptr_t);
 305 static mblk_t *tim_filladdr(queue_t *, mblk_t *, boolean_t);
 306 static void tim_addlink(struct tim_tim  *);
 307 static void tim_dellink(struct tim_tim  *);
 308 static struct tim_tim *tim_findlink(t_uscalar_t);
 309 static void tim_recover(queue_t *, mblk_t *, t_scalar_t);
 310 static void tim_ioctl_retry(queue_t *);
 311 
 312 int dotilog = 0;
 313 
 314 #define TIMOD_ID        3
 315 
 316 /* ONC_PLUS EXTRACT START */
 317 static int timodopen(queue_t *, dev_t *, int, int, cred_t *);
 318 /* ONC_PLUS EXTRACT END */
 319 static int timodclose(queue_t *, int, cred_t *);
 320 static void timodwput(queue_t *, mblk_t *);
 321 static void timodrput(queue_t *, mblk_t *);
 322 /* ONC_PLUS EXTRACT START */
 323 static void timodrsrv(queue_t *);
 324 /* ONC_PLUS EXTRACT END */
 325 static void timodwsrv(queue_t *);
 326 /* ONC_PLUS EXTRACT START */
 327 static int timodrproc(queue_t *, mblk_t *);
 328 static int timodwproc(queue_t *, mblk_t *);
 329 /* ONC_PLUS EXTRACT END */
 330 
 331 /* stream data structure definitions */
 332 
 333 static struct module_info timod_info =
 334         {TIMOD_ID, "timod", 0, INFPSZ, 512, 128};
 335 static struct qinit timodrinit = {
 336         (int (*)())timodrput,
 337         (int (*)())timodrsrv,
 338         timodopen,
 339         timodclose,
 340         nulldev,
 341         &timod_info,
 342         NULL
 343 };
 344 static struct qinit timodwinit = {
 345         (int (*)())timodwput,
 346         (int (*)())timodwsrv,
 347         timodopen,
 348         timodclose,
 349         nulldev,
 350         &timod_info,
 351         NULL
 352 };
 353 static struct streamtab timinfo = { &timodrinit, &timodwinit, NULL, NULL };
 354 
 355 /* ONC_PLUS EXTRACT START */
 356 /*
 357  * timodopen -  open routine gets called when the module gets pushed
 358  *              onto the stream.
 359  */
 360 /*ARGSUSED*/
 361 static int
 362 timodopen(
 363         queue_t *q,
 364         dev_t *devp,
 365         int flag,
 366         int sflag,
 367         cred_t *crp)
 368 {
 369         struct tim_tim *tp;
 370         struct stroptions *sop;
 371         mblk_t *bp;
 372 
 373         ASSERT(q != NULL);
 374 
 375         if (q->q_ptr) {


 471 }
 472 
 473 static void
 474 tim_buffer(void *arg)
 475 {
 476         queue_t *q = arg;
 477         struct tim_tim *tp = (struct tim_tim *)q->q_ptr;
 478 
 479         ASSERT(tp);
 480 
 481         if (q->q_flag & QREADR) {
 482                 ASSERT(tp->tim_rbufcid);
 483                 tp->tim_rbufcid = 0;
 484         } else {
 485                 ASSERT(tp->tim_wbufcid);
 486                 tp->tim_wbufcid = 0;
 487         }
 488         enableok(q);
 489         qenable(q);
 490 }
 491 /* ONC_PLUS EXTRACT END */
 492 
 493 /*
 494  * timodclose - This routine gets called when the module gets popped
 495  * off of the stream.
 496  */
 497 /*ARGSUSED*/
 498 static int
 499 timodclose(
 500         queue_t *q,
 501         int flag,
 502         cred_t *crp)
 503 {
 504         struct tim_tim *tp;
 505         mblk_t *mp;
 506         mblk_t *nmp;
 507 
 508         ASSERT(q != NULL);
 509 
 510         tp = (struct tim_tim *)q->q_ptr;
 511         q->q_ptr = NULL;


 620                 switch (pptr->type) {
 621                 case T_EXDATA_IND:
 622                 case T_DATA_IND:
 623                 case T_UNITDATA_IND:
 624                         if (bcanputnext(q, mp->b_band))
 625                                 putnext(q, mp);
 626                         else
 627                                 (void) putq(q, mp);
 628                         break;
 629                 default:
 630                         (void) timodrproc(q, mp);
 631                         break;
 632                 }
 633                 break;
 634         default:
 635                 (void) timodrproc(q, mp);
 636                 break;
 637         }
 638 }
 639 
 640 /* ONC_PLUS EXTRACT START */
 641 /*
 642  * timodrsrv -  Module read queue service procedure.  This is called when
 643  *              messages are placed on an empty queue, when high priority
 644  *              messages are placed on the queue, and when flow control
 645  *              restrictions subside.  This code used to be included in a
 646  *              put procedure, but it was moved to a service procedure
 647  *              because several points were added where memory allocation
 648  *              could fail, and there is no reasonable recovery mechanism
 649  *              from the put procedure.
 650  */
 651 /*ARGSUSED*/
 652 static void
 653 timodrsrv(queue_t *q)
 654 {
 655 /* ONC_PLUS EXTRACT END */
 656         mblk_t *mp;
 657         struct tim_tim *tp;
 658 
 659         ASSERT(q != NULL);
 660 
 661         tp = (struct tim_tim *)q->q_ptr;
 662         if (!tp)
 663                 return;
 664 
 665         while ((mp = getq(q)) != NULL) {
 666                 if (timodrproc(q, mp)) {
 667                         /*
 668                          * timodrproc did a putbq - stop processing
 669                          * messages.
 670                          */
 671                         return;
 672                 }
 673         }
 674 /* ONC_PLUS EXTRACT START */
 675 }
 676 
 677 /*
 678  * Perform common processing when a T_CAPABILITY_ACK or T_INFO_ACK
 679  * arrive.  Set the queue properties and adjust the tim_flags according
 680  * to the service type.
 681  */
 682 static void
 683 timodprocessinfo(queue_t *q, struct tim_tim *tp, struct T_info_ack *tia)
 684 {
 685         TILOG("timodprocessinfo: strqset(%d)\n", tia->TIDU_size);
 686         (void) strqset(q, QMAXPSZ, 0, tia->TIDU_size);
 687         (void) strqset(OTHERQ(q), QMAXPSZ, 0, tia->TIDU_size);
 688 
 689         if ((tia->SERV_type == T_COTS) || (tia->SERV_type == T_COTS_ORD))
 690                 tp->tim_flags = (tp->tim_flags & ~CLTS) | COTS;
 691         else if (tia->SERV_type == T_CLTS)
 692                 tp->tim_flags = (tp->tim_flags & ~COTS) | CLTS;
 693 }
 694 
 695 static int
 696 timodrproc(queue_t *q, mblk_t *mp)
 697 {
 698         uint32_t auditing = AU_AUDITING();
 699         union T_primitives *pptr;
 700         struct tim_tim *tp;
 701         struct iocblk *iocbp;
 702         mblk_t *nbp;
 703         size_t blen;
 704 /* ONC_PLUS EXTRACT END */
 705 
 706         tp = (struct tim_tim *)q->q_ptr;
 707 
 708 /* ONC_PLUS EXTRACT START */
 709         switch (mp->b_datap->db_type) {
 710         default:
 711                 putnext(q, mp);
 712                 break;
 713 
 714         case M_ERROR:
 715                 TILOG("timodrproc: Got M_ERROR, flags = %x\n", tp->tim_flags);
 716                 /*
 717                  * There is no specified standard response for driver when it
 718                  * receives unknown message type and M_ERROR is one
 719                  * possibility. If we send T_CAPABILITY_REQ down and transport
 720                  * provider responds with M_ERROR we assume that it doesn't
 721                  * understand this message type. This assumption may be
 722                  * sometimes incorrect (transport may reply with M_ERROR for
 723                  * some other reason) but there is no way for us to distinguish
 724                  * between different cases. In the worst case timod and everyone
 725                  * else sharing global transport description with it may end up
 726                  * emulating T_CAPABILITY_REQ.
 727                  */
 728 


 769                          * was too short, then the message would have
 770                          * already been putnext'd, and would thus
 771                          * never appear here.  Just the same, the code
 772                          * below handles the impossible case since
 773                          * it's easy to do and saves future
 774                          * maintainers from unfortunate accidents.
 775                          */
 776                         ASSERT(mp->b_datap->db_type == M_PROTO);
 777                         if (mp->b_datap->db_type == M_PROTO &&
 778                             !bcanputnext(q, mp->b_band)) {
 779                                 (void) putbq(q, mp);
 780                                 return (1);
 781                         }
 782                         putnext(q, mp);
 783                         break;
 784                 }
 785 
 786                 pptr = (union T_primitives *)mp->b_rptr;
 787                 switch (pptr->type) {
 788                 default:
 789 /* ONC_PLUS EXTRACT END */
 790 
 791                         if (auditing)
 792                                 audit_sock(T_UNITDATA_IND, q, mp, TIMOD_ID);
 793 /* ONC_PLUS EXTRACT START */
 794                         putnext(q, mp);
 795                         break;
 796 /* ONC_PLUS EXTRACT END */
 797 
 798                 case T_ERROR_ACK:
 799                         /* Restore db_type - recover() might have changed it */
 800                         mp->b_datap->db_type = M_PCPROTO;
 801                         if (blen < sizeof (struct T_error_ack)) {
 802                                 putnext(q, mp);
 803                                 break;
 804                         }
 805 
 806                         tilog("timodrproc: Got T_ERROR_ACK, flags = %x\n",
 807                             tp->tim_flags);
 808 
 809                         if ((tp->tim_flags & WAIT_CONNRESACK) &&
 810                             tp->tim_saved_prim == pptr->error_ack.ERROR_prim) {
 811                                 tp->tim_flags &=
 812                                     ~(WAIT_CONNRESACK | WAITIOCACK);
 813                                 freemsg(tp->tim_iocsave);
 814                                 tp->tim_iocsave = NULL;
 815                                 tp->tim_saved_prim = -1;
 816                                 putnext(q, mp);


 886                                         ntp->tim_peermaxlen = indp->SRC_length;
 887                                 }
 888                                 ntp->tim_peerlen = indp->SRC_length;
 889                                 ptr = (caddr_t)indp + indp->SRC_offset;
 890                                 bcopy(ptr, ntp->tim_peername, ntp->tim_peerlen);
 891 
 892                                 mutex_exit(&ntp->tim_mutex);
 893 
 894                         cresackout:
 895                                 rw_exit(&tim_list_rwlock);
 896                                 tp->tim_flags &=
 897                                     ~(WAIT_CONNRESACK | WAITIOCACK);
 898                                 freemsg(tp->tim_iocsave);
 899                                 tp->tim_iocsave = NULL;
 900                                 tp->tim_saved_prim = -1;
 901                         }
 902 
 903                         tim_send_reply(q, mp, tp, pptr->ok_ack.CORRECT_prim);
 904                         break;
 905 
 906 /* ONC_PLUS EXTRACT START */
 907                 case T_BIND_ACK: {
 908                         struct T_bind_ack *ackp =
 909                             (struct T_bind_ack *)mp->b_rptr;
 910 
 911                         /* Restore db_type - recover() might have changed it */
 912                         mp->b_datap->db_type = M_PCPROTO;
 913                         if (blen < sizeof (*ackp)) {
 914                                 putnext(q, mp);
 915                                 break;
 916                         }
 917 
 918                         /* save negotiated backlog */
 919                         tp->tim_backlog = ackp->CONIND_number;
 920 
 921                         if (((tp->tim_flags & WAITIOCACK) == 0) ||
 922                             ((tp->tim_saved_prim != O_T_BIND_REQ) &&
 923                             (tp->tim_saved_prim != T_BIND_REQ))) {
 924                                 putnext(q, mp);
 925                                 break;
 926                         }


 950                                         ASSERT(tp->tim_mymaxlen >= 0);
 951                                         if (tp->tim_mymaxlen != NULL) {
 952                                                 kmem_free(tp->tim_myname,
 953                                                     tp->tim_mymaxlen);
 954                                         }
 955                                         tp->tim_myname = p;
 956                                         tp->tim_mymaxlen = ackp->ADDR_length;
 957                                 }
 958                                 tp->tim_mylen = ackp->ADDR_length;
 959                                 bcopy(mp->b_rptr + ackp->ADDR_offset,
 960                                     tp->tim_myname, tp->tim_mylen);
 961                         }
 962                         tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
 963                         tp->tim_iocsave = NULL;
 964                         tp->tim_saved_prim = -1;
 965                         tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
 966                             TI_CAP_RECVD | CAP_WANTS_INFO);
 967                         break;
 968                 }
 969 
 970 /* ONC_PLUS EXTRACT END */
 971                 case T_OPTMGMT_ACK:
 972 
 973                         tilog("timodrproc: Got T_OPTMGMT_ACK\n", 0);
 974 
 975                         /* Restore db_type - recover() might have change it */
 976                         mp->b_datap->db_type = M_PCPROTO;
 977 
 978                         if (((tp->tim_flags & WAITIOCACK) == 0) ||
 979                             ((tp->tim_saved_prim != T_SVR4_OPTMGMT_REQ) &&
 980                             (tp->tim_saved_prim != T_OPTMGMT_REQ))) {
 981                                 putnext(q, mp);
 982                         } else {
 983                                 ASSERT(tp->tim_iocsave != NULL);
 984                                 tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
 985                                 tp->tim_iocsave = NULL;
 986                                 tp->tim_saved_prim = -1;
 987                                 tp->tim_flags &= ~(WAITIOCACK |
 988                                     WAIT_IOCINFOACK | TI_CAP_RECVD |
 989                                     CAP_WANTS_INFO);
 990                         }


1183                                 }
1184                                 mp->b_wptr += 2*sizeof (uint32_t);
1185                         }
1186                         tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
1187                         tp->tim_iocsave = NULL;
1188                         tp->tim_saved_prim = -1;
1189                         tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
1190                             TI_CAP_RECVD | CAP_WANTS_INFO);
1191                         break;
1192                 }
1193             }
1194 
1195             putnext(q, mp);
1196             break;
1197 
1198             case T_ADDR_ACK:
1199                 tilog("timodrproc: Got T_ADDR_ACK\n", 0);
1200                 tim_send_reply(q, mp, tp, T_ADDR_REQ);
1201                 break;
1202 
1203 /* ONC_PLUS EXTRACT START */
1204                 case T_CONN_IND: {
1205                         struct T_conn_ind *tcip =
1206                             (struct T_conn_ind *)mp->b_rptr;
1207 
1208                         tilog("timodrproc: Got T_CONN_IND\n", 0);
1209 
1210                         if (blen >= sizeof (*tcip) &&
1211                             MBLKIN(mp, tcip->SRC_offset, tcip->SRC_length)) {
1212                                 if (((nbp = dupmsg(mp)) != NULL) ||
1213                                     ((nbp = copymsg(mp)) != NULL)) {
1214                                         nbp->b_next = tp->tim_consave;
1215                                         tp->tim_consave = nbp;
1216                                 } else {
1217                                         tim_recover(q, mp,
1218                                             (t_scalar_t)sizeof (mblk_t));
1219                                         return (1);
1220                                 }
1221                         }
1222 /* ONC_PLUS EXTRACT END */
1223                         if (auditing)
1224                                 audit_sock(T_CONN_IND, q, mp, TIMOD_ID);
1225 /* ONC_PLUS EXTRACT START */
1226                         putnext(q, mp);
1227                         break;
1228                 }
1229 
1230 /* ONC_PLUS EXTRACT END */
1231             case T_CONN_CON:
1232                 mutex_enter(&tp->tim_mutex);
1233                 if (tp->tim_peercred != NULL)
1234                         crfree(tp->tim_peercred);
1235                 tp->tim_peercred = msg_getcred(mp, &tp->tim_cpid);
1236                 if (tp->tim_peercred != NULL)
1237                         crhold(tp->tim_peercred);
1238                 mutex_exit(&tp->tim_mutex);
1239 
1240                 tilog("timodrproc: Got T_CONN_CON\n", 0);
1241 
1242                 tp->tim_flags &= ~CONNWAIT;
1243                 putnext(q, mp);
1244                 break;
1245 
1246             case T_DISCON_IND: {
1247                 struct T_discon_ind *disp;
1248                 struct T_conn_ind *conp;
1249                 mblk_t *pbp = NULL;
1250 


1323                                 tp->tim_provinfo->tpi_capability = PI_YES;
1324                         PI_PROVUNLOCK(tp->tim_provinfo);
1325 
1326                         /* Reset possible pending timeout */
1327                         if (tp->tim_tcap_timoutid != 0) {
1328                                 (void) quntimeout(q, tp->tim_tcap_timoutid);
1329                                 tp->tim_tcap_timoutid = 0;
1330                         }
1331 
1332                         tca = (struct T_capability_ack *)mp->b_rptr;
1333 
1334                         if (tca->CAP_bits1 & TC1_INFO)
1335                                 timodprocessinfo(q, tp, &tca->INFO_ack);
1336 
1337                         tim_send_reply(q, mp, tp, T_CAPABILITY_REQ);
1338                 }
1339                 break;
1340             }
1341             break;
1342 
1343 /* ONC_PLUS EXTRACT START */
1344         case M_FLUSH:
1345 
1346                 tilog("timodrproc: Got M_FLUSH\n", 0);
1347 
1348                 if (*mp->b_rptr & FLUSHR) {
1349                         if (*mp->b_rptr & FLUSHBAND)
1350                                 flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
1351                         else
1352                                 flushq(q, FLUSHDATA);
1353                 }
1354                 putnext(q, mp);
1355                 break;
1356 /* ONC_PLUS EXTRACT END */
1357 
1358         case M_IOCACK:
1359             iocbp = (struct iocblk *)mp->b_rptr;
1360 
1361             tilog("timodrproc: Got M_IOCACK\n", 0);
1362 
1363             if (iocbp->ioc_cmd == TI_GETMYNAME) {
1364 
1365                 /*
1366                  * Transport provider supports this ioctl,
1367                  * so I don't have to.
1368                  */
1369                 if ((tp->tim_flags & DO_MYNAME) != 0) {
1370                         tp->tim_flags &= ~DO_MYNAME;
1371                         PI_PROVLOCK(tp->tim_provinfo);
1372                         tp->tim_provinfo->tpi_myname = PI_YES;
1373                         PI_PROVUNLOCK(tp->tim_provinfo);
1374                 }
1375 
1376                 ASSERT(tp->tim_mymaxlen >= 0);


1412                         mblk_t *bp;
1413 
1414                         bp = tp->tim_consave;
1415                         while (bp != NULL) {
1416                                 nbp = bp->b_next;
1417                                 bp->b_next = NULL;
1418                                 freemsg(bp);
1419                                 bp = nbp;
1420                         }
1421                         tp->tim_consave = NULL;
1422                 }
1423                 /* tim_iocsave may already be overwritten. */
1424                 if (tp->tim_saved_prim == -1) {
1425                         freemsg(tp->tim_iocsave);
1426                         tp->tim_iocsave = NULL;
1427                 }
1428             }
1429             putnext(q, mp);
1430             break;
1431 
1432 /* ONC_PLUS EXTRACT START */
1433         case M_IOCNAK:
1434 
1435                 tilog("timodrproc: Got M_IOCNAK\n", 0);
1436 
1437                 iocbp = (struct iocblk *)mp->b_rptr;
1438                 if (((iocbp->ioc_cmd == TI_GETMYNAME) ||
1439                     (iocbp->ioc_cmd == TI_GETPEERNAME)) &&
1440                     ((iocbp->ioc_error == EINVAL) || (iocbp->ioc_error == 0))) {
1441                         PI_PROVLOCK(tp->tim_provinfo);
1442                         if (iocbp->ioc_cmd == TI_GETMYNAME) {
1443                                 if (tp->tim_provinfo->tpi_myname == PI_DONTKNOW)
1444                                         tp->tim_provinfo->tpi_myname = PI_NO;
1445                         } else if (iocbp->ioc_cmd == TI_GETPEERNAME) {
1446                                 if (tp->tim_provinfo->tpi_peername == PI_DONTKNOW)
1447                                         tp->tim_provinfo->tpi_peername = PI_NO;
1448                         }
1449                         PI_PROVUNLOCK(tp->tim_provinfo);
1450                         /* tim_iocsave may already be overwritten. */
1451                         if ((tp->tim_iocsave != NULL) &&
1452                             (tp->tim_saved_prim == -1)) {
1453                                 freemsg(mp);
1454                                 mp = tp->tim_iocsave;
1455                                 tp->tim_iocsave = NULL;
1456                                 tp->tim_flags |= NAMEPROC;
1457                                 if (ti_doname(WR(q), mp) != DONAME_CONT) {
1458                                         tp->tim_flags &= ~NAMEPROC;
1459                                 }
1460                                 break;
1461                         }
1462                 }
1463                 putnext(q, mp);
1464                 break;
1465 /* ONC_PLUS EXTRACT END */
1466         }
1467 
1468         return (0);
1469 }
1470 
1471 /* ONC_PLUS EXTRACT START */
1472 /*
1473  * timodwput -  Module write put procedure.  This is called from
1474  *              the module, driver, or stream head upstream/downstream.
1475  *              Handles M_FLUSH, M_DATA and some M_PROTO (T_DATA_REQ,
1476  *              and T_UNITDATA_REQ) messages. All others are queued to
1477  *              be handled by the service procedures.
1478  */
1479 
1480 static void
1481 timodwput(queue_t *q, mblk_t *mp)
1482 {
1483         union T_primitives *pptr;
1484         struct tim_tim *tp;
1485         struct iocblk *iocbp;
1486 
1487         /*
1488          * Enqueue normal-priority messages if our queue already
1489          * holds some messages for deferred processing but don't
1490          * enqueue those M_IOCTLs which will result in an
1491          * M_PCPROTO (ie, high priority) message being created.
1492          */
1493 /* ONC_PLUS EXTRACT END */
1494         if (q->q_first != 0 && mp->b_datap->db_type < QPCTL) {
1495                 if (mp->b_datap->db_type == M_IOCTL) {
1496                         iocbp = (struct iocblk *)mp->b_rptr;
1497                         switch (iocbp->ioc_cmd) {
1498                         default:
1499                                 (void) putq(q, mp);
1500                                 return;
1501 
1502                         case TI_GETINFO:
1503                         case TI_SYNC:
1504                         case TI_CAPABILITY:
1505                                 break;
1506                         }
1507                 } else {
1508                         (void) putq(q, mp);
1509                         return;
1510                 }
1511         }
1512 /* ONC_PLUS EXTRACT START */
1513         /*
1514          * Inline processing of data (to avoid additional procedure call).
1515          * Rest is handled in timodwproc.
1516          */
1517 
1518         switch (mp->b_datap->db_type) {
1519         case M_DATA:
1520                 tp = (struct tim_tim *)q->q_ptr;
1521                 ASSERT(tp);
1522                 if (tp->tim_flags & CLTS) {
1523                         mblk_t  *tmp;
1524 
1525                         if ((tmp = tim_filladdr(q, mp, B_FALSE)) == NULL) {
1526                                 (void) putq(q, mp);
1527                                 break;
1528                         } else {
1529                                 mp = tmp;
1530                         }
1531                 }
1532                 if (bcanputnext(q, mp->b_band))
1533                         putnext(q, mp);
1534                 else
1535                         (void) putq(q, mp);
1536                 break;
1537         case M_PROTO:
1538         case M_PCPROTO:
1539                 pptr = (union T_primitives *)mp->b_rptr;
1540                 switch (pptr->type) {
1541 /* ONC_PLUS EXTRACT END */
1542                 case T_UNITDATA_REQ:
1543                         tp = (struct tim_tim *)q->q_ptr;
1544                         ASSERT(tp);
1545                         if (tp->tim_flags & CLTS) {
1546                                 mblk_t  *tmp;
1547 
1548                                 tmp = tim_filladdr(q, mp, B_FALSE);
1549                                 if (tmp == NULL) {
1550                                         (void) putq(q, mp);
1551                                         break;
1552                                 } else {
1553                                         mp = tmp;
1554                                 }
1555                         }
1556                         if (bcanputnext(q, mp->b_band))
1557                                 putnext(q, mp);
1558                         else
1559                                 (void) putq(q, mp);
1560                         break;
1561 
1562                 case T_DATA_REQ:
1563                 case T_EXDATA_REQ:
1564                         if (bcanputnext(q, mp->b_band))
1565                                 putnext(q, mp);
1566                         else
1567                                 (void) putq(q, mp);
1568                         break;
1569                 default:
1570                         (void) timodwproc(q, mp);
1571                         break;
1572                 }
1573                 break;
1574 /* ONC_PLUS EXTRACT START */
1575         default:
1576                 (void) timodwproc(q, mp);
1577                 break;
1578         }
1579 }
1580 /*
1581  * timodwsrv -  Module write queue service procedure.
1582  *              This is called when messages are placed on an empty queue,
1583  *              when high priority messages are placed on the queue, and
1584  *              when flow control restrictions subside.  This code used to
1585  *              be included in a put procedure, but it was moved to a
1586  *              service procedure because several points were added where
1587  *              memory allocation could fail, and there is no reasonable
1588  *              recovery mechanism from the put procedure.
1589  */
1590 static void
1591 timodwsrv(queue_t *q)
1592 {
1593         mblk_t *mp;
1594 


1610 /*
1611  * Common routine to process write side messages
1612  */
1613 
1614 static int
1615 timodwproc(queue_t *q, mblk_t *mp)
1616 {
1617         union T_primitives *pptr;
1618         struct tim_tim *tp;
1619         uint32_t auditing = AU_AUDITING();
1620         mblk_t *tmp;
1621         struct iocblk *iocbp;
1622         int error;
1623 
1624         tp = (struct tim_tim *)q->q_ptr;
1625 
1626         switch (mp->b_datap->db_type) {
1627         default:
1628                 putnext(q, mp);
1629                 break;
1630 /* ONC_PLUS EXTRACT END */
1631 
1632         case M_DATA:
1633                 if (tp->tim_flags & CLTS) {
1634                         if ((tmp = tim_filladdr(q, mp, B_TRUE)) == NULL) {
1635                                 return (1);
1636                         } else {
1637                                 mp = tmp;
1638                         }
1639                 }
1640                 if (!bcanputnext(q, mp->b_band)) {
1641                         (void) putbq(q, mp);
1642                         return (1);
1643                 }
1644                 putnext(q, mp);
1645                 break;
1646 
1647 /* ONC_PLUS EXTRACT START */
1648         case M_IOCTL:
1649 
1650                 iocbp = (struct iocblk *)mp->b_rptr;
1651                 TILOG("timodwproc: Got M_IOCTL(%d)\n", iocbp->ioc_cmd);
1652 
1653                 ASSERT(MBLKL(mp) == sizeof (struct iocblk));
1654 
1655                 /*
1656                  * TPI requires we await response to a previously sent message
1657                  * before handling another, put it back on the head of queue.
1658                  * Since putbq() may see QWANTR unset when called from the
1659                  * service procedure, the queue must be explicitly scheduled
1660                  * for service, as no backenable will occur for this case.
1661                  * tim_ioctl_retry() sets a timer to handle the qenable.
1662                  */
1663                 if (tp->tim_flags & WAITIOCACK) {
1664                         TILOG("timodwproc: putbq M_IOCTL(%d)\n",
1665                             iocbp->ioc_cmd);
1666                         (void) putbq(q, mp);
1667                         /* Called from timodwsrv() and messages on queue */
1668                         if (!(q->q_flag & QWANTR))
1669                                 tim_ioctl_retry(q);
1670                         return (1);
1671                 }
1672 /* ONC_PLUS EXTRACT END */
1673 
1674                 switch (iocbp->ioc_cmd) {
1675                 default:
1676                         putnext(q, mp);
1677                         break;
1678 
1679                 case _I_GETPEERCRED:
1680                         if ((tp->tim_flags & COTS) == 0) {
1681                                 miocnak(q, mp, 0, ENOTSUP);
1682                         } else {
1683                                 mblk_t *cmp = mp->b_cont;
1684                                 k_peercred_t *kp = NULL;
1685 
1686                                 mutex_enter(&tp->tim_mutex);
1687                                 if (cmp != NULL &&
1688                                     iocbp->ioc_flag == IOC_NATIVE &&
1689                                     (tp->tim_flags &
1690                                     (CONNWAIT|LOCORDREL|REMORDREL)) == 0 &&
1691                                     tp->tim_peercred != NULL &&
1692                                     DB_TYPE(cmp) == M_DATA &&


1902                                 /*
1903                                  * It could happen when timod is awaiting ack
1904                                  * for TI_GETPEERNAME/TI_GETMYNAME.
1905                                  */
1906                                 if (tp->tim_iocsave != NULL) {
1907                                         freemsg(tp->tim_iocsave);
1908                                         tp->tim_iocsave = NULL;
1909                                         tp->tim_saved_prim = -1;
1910                                 }
1911                                 break;
1912 
1913                         default:
1914                                 cmn_err(CE_PANIC,
1915                                     "timodwproc: unknown tpi_capability value "
1916                                     "%d\n", tp->tim_provinfo->tpi_capability);
1917                                 break;
1918                         }
1919                 }
1920                 break;
1921 
1922 /* ONC_PLUS EXTRACT START */
1923                 case TI_GETMYNAME:
1924 
1925                         tilog("timodwproc: Got TI_GETMYNAME\n", 0);
1926 
1927                         if (tp->tim_provinfo->tpi_myname == PI_YES) {
1928                                 putnext(q, mp);
1929                                 break;
1930                         }
1931                         goto getname;
1932 
1933                 case TI_GETPEERNAME:
1934 
1935                         tilog("timodwproc: Got TI_GETPEERNAME\n", 0);
1936 
1937                         if (tp->tim_provinfo->tpi_peername == PI_YES) {
1938                                 putnext(q, mp);
1939                                 break;
1940                         }
1941 getname:
1942                         if ((tmp = copymsg(mp)) == NULL) {


1972                         return (1);
1973                 }
1974 
1975                 pptr = (union T_primitives *)mp->b_rptr;
1976                 switch (pptr->type) {
1977                 default:
1978                         putnext(q, mp);
1979                         break;
1980 
1981                 case T_EXDATA_REQ:
1982                 case T_DATA_REQ:
1983                         if (pptr->type == T_EXDATA_REQ)
1984                                 tilog("timodwproc: Got T_EXDATA_REQ\n", 0);
1985 
1986                 if (!bcanputnext(q, mp->b_band)) {
1987                         (void) putbq(q, mp);
1988                         return (1);
1989                 }
1990                 putnext(q, mp);
1991                 break;
1992 /* ONC_PLUS EXTRACT END */
1993 
1994                 case T_UNITDATA_REQ:
1995                         if (tp->tim_flags & CLTS) {
1996                                 tmp = tim_filladdr(q, mp, B_TRUE);
1997                                 if (tmp == NULL) {
1998                                         return (1);
1999                                 } else {
2000                                         mp = tmp;
2001                                 }
2002                         }
2003                         if (auditing)
2004                                 audit_sock(T_UNITDATA_REQ, q, mp, TIMOD_ID);
2005                 if (!bcanputnext(q, mp->b_band)) {
2006                                 (void) putbq(q, mp);
2007                                 return (1);
2008                         }
2009                         putnext(q, mp);
2010                         break;
2011 
2012 /* ONC_PLUS EXTRACT START */
2013                 case T_CONN_REQ: {
2014                         struct T_conn_req *reqp = (struct T_conn_req *)
2015                             mp->b_rptr;
2016                         void *p;
2017 
2018                         tilog("timodwproc: Got T_CONN_REQ\n", 0);
2019 
2020                         if (MBLKL(mp) < sizeof (struct T_conn_req)) {
2021                                 merror(q, mp, EPROTO);
2022                                 return (1);
2023                         }
2024 
2025                         if (tp->tim_flags & DO_PEERNAME) {
2026                                 if (!MBLKIN(mp, reqp->DEST_offset,
2027                                     reqp->DEST_length)) {
2028                                         merror(q, mp, EPROTO);
2029                                         return (1);
2030                                 }
2031                                 ASSERT(reqp->DEST_length >= 0);
2032                                 mutex_enter(&tp->tim_mutex);


2038                                                 tilog("timodwproc: kmem_alloc "
2039                                                     "failed, attempting "
2040                                                     "recovery\n", 0);
2041                                                 tim_recover(q, mp,
2042                                                     reqp->DEST_length);
2043                                                 return (1);
2044                                         }
2045                                         if (tp->tim_peermaxlen)
2046                                                 kmem_free(tp->tim_peername,
2047                                                     tp->tim_peermaxlen);
2048                                         tp->tim_peername = p;
2049                                         tp->tim_peermaxlen = reqp->DEST_length;
2050                                 }
2051                                 tp->tim_peerlen = reqp->DEST_length;
2052                                 p = mp->b_rptr + reqp->DEST_offset;
2053                                 bcopy(p, tp->tim_peername, tp->tim_peerlen);
2054                                 mutex_exit(&tp->tim_mutex);
2055                         }
2056                         if (tp->tim_flags & COTS)
2057                                 tp->tim_flags |= CONNWAIT;
2058 /* ONC_PLUS EXTRACT END */
2059                         if (auditing)
2060                                 audit_sock(T_CONN_REQ, q, mp, TIMOD_ID);
2061 /* ONC_PLUS EXTRACT START */
2062                 putnext(q, mp);
2063                 break;
2064                 }
2065 
2066                 case O_T_CONN_RES:
2067                 case T_CONN_RES: {
2068                         struct T_conn_res *resp;
2069                         struct T_conn_ind *indp;
2070                         mblk_t *pmp = NULL;
2071                         mblk_t *nbp;
2072 
2073                         if (MBLKL(mp) < sizeof (struct T_conn_res) ||
2074                             (tp->tim_flags & WAITIOCACK)) {
2075                                 merror(q, mp, EPROTO);
2076                                 return (1);
2077                         }
2078 
2079                         resp = (struct T_conn_res *)mp->b_rptr;
2080                         for (tmp = tp->tim_consave; tmp != NULL;
2081                             tmp = tmp->b_next) {


2102                         /*
2103                          * Construct a list with:
2104                          *      nbp - copy of user's original request
2105                          *      tmp - the extracted T_conn_ind
2106                          */
2107                         nbp->b_cont = tmp;
2108                         /*
2109                          * tim_iocsave may be non-NULL when timod is awaiting
2110                          * ack for TI_GETPEERNAME/TI_GETMYNAME.
2111                          */
2112                         freemsg(tp->tim_iocsave);
2113                         tp->tim_iocsave = nbp;
2114                         tp->tim_saved_prim = pptr->type;
2115                         tp->tim_flags |= WAIT_CONNRESACK | WAITIOCACK;
2116 
2117                 cresout:
2118                         putnext(q, mp);
2119                         break;
2120                 }
2121 
2122 /* ONC_PLUS EXTRACT END */
2123                 case T_DISCON_REQ: {
2124                         struct T_discon_req *disp;
2125                         struct T_conn_ind *conp;
2126                         mblk_t *pmp = NULL;
2127 
2128                         if (MBLKL(mp) < sizeof (struct T_discon_req)) {
2129                                 merror(q, mp, EPROTO);
2130                                 return (1);
2131                         }
2132 
2133                         disp = (struct T_discon_req *)mp->b_rptr;
2134                         tp->tim_flags &= ~(CONNWAIT|LOCORDREL|REMORDREL);
2135                         tim_clear_peer(tp);
2136 
2137                         /*
2138                          * If we are already connected, there won't
2139                          * be any messages on tim_consave.
2140                          */
2141                         for (tmp = tp->tim_consave; tmp; tmp = tmp->b_next) {
2142                                 conp = (struct T_conn_ind *)tmp->b_rptr;


2158 
2159                 case T_ORDREL_REQ:
2160                         if (tp->tim_flags & REMORDREL) {
2161                                 tp->tim_flags &= ~(LOCORDREL|REMORDREL);
2162                                 tim_clear_peer(tp);
2163                         } else {
2164                                 tp->tim_flags |= LOCORDREL;
2165                         }
2166                         putnext(q, mp);
2167                         break;
2168 
2169                 case T_CAPABILITY_REQ:
2170                         tilog("timodwproc: Got T_CAPABILITY_REQ\n", 0);
2171                         /*
2172                          * XXX: We may know at this point whether transport
2173                          * provides T_CAPABILITY_REQ or not and we may utilise
2174                          * this knowledge here.
2175                          */
2176                         putnext(q, mp);
2177                         break;
2178 /* ONC_PLUS EXTRACT START */
2179                 }
2180                 break;
2181         case M_FLUSH:
2182 
2183                 tilog("timodwproc: Got M_FLUSH\n", 0);
2184 
2185                 if (*mp->b_rptr & FLUSHW) {
2186                         if (*mp->b_rptr & FLUSHBAND)
2187                                 flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
2188                         else
2189                                 flushq(q, FLUSHDATA);
2190                 }
2191                 putnext(q, mp);
2192                 break;
2193         }
2194 
2195         return (0);
2196 }
2197 
2198 static void


2429                 cqp->cq_addr = (caddr_t)STRUCT_FGETP(sb, buf);
2430                 cqp->cq_size = STRUCT_FGET(sb, len);
2431                 cqp->cq_flag = 0;
2432                 mp->b_datap->db_type = M_COPYOUT;
2433                 mp->b_cont = bp;
2434                 STRUCT_FSET(sb, len, 0); /* copy the strbuf next time around */
2435                 qreply(q, mp);
2436                 ret = DONAME_CONT;
2437                 break;
2438 
2439         default:
2440                 tilog("ti_doname: freeing bad message type = %d\n",
2441                     mp->b_datap->db_type);
2442                 freemsg(mp);
2443                 ret = DONAME_FAIL;
2444                 break;
2445         }
2446         return (ret);
2447 }
2448 
2449 /* ONC_PLUS EXTRACT END */
2450 
2451 /*
2452  * Fill in the address of a connectionless data packet if a connect
2453  * had been done on this endpoint.
2454  */
2455 static mblk_t *
2456 tim_filladdr(queue_t *q, mblk_t *mp, boolean_t dorecover)
2457 {
2458         mblk_t *bp;
2459         struct tim_tim *tp;
2460         struct T_unitdata_req *up;
2461         struct T_unitdata_req *nup;
2462         size_t plen;
2463 
2464         tp = (struct tim_tim *)q->q_ptr;
2465         if (mp->b_datap->db_type == M_DATA) {
2466                 mutex_enter(&tp->tim_mutex);
2467                 bp = allocb(sizeof (struct T_unitdata_req) + tp->tim_peerlen,
2468                     BPRI_MED);
2469                 if (bp != NULL) {


2563         tim_cnt--;
2564 
2565         rw_exit(&tim_list_rwlock);
2566 }
2567 
2568 static struct tim_tim *
2569 tim_findlink(t_uscalar_t id)
2570 {
2571         struct tim_tim  *tp;
2572 
2573         ASSERT(rw_lock_held(&tim_list_rwlock));
2574 
2575         for (tp = tim_hash[TIM_HASH(id)]; tp != NULL; tp = tp->tim_next) {
2576                 if (tp->tim_acceptor == id) {
2577                         break;
2578                 }
2579         }
2580         return (tp);
2581 }
2582 
2583 /* ONC_PLUS EXTRACT START */
2584 static void
2585 tim_recover(queue_t *q, mblk_t *mp, t_scalar_t size)
2586 {
2587         struct tim_tim  *tp;
2588         bufcall_id_t    bid;
2589         timeout_id_t    tid;
2590 
2591         tp = (struct tim_tim *)q->q_ptr;
2592 
2593         /*
2594          * Avoid re-enabling the queue.
2595          */
2596         if (mp->b_datap->db_type == M_PCPROTO)
2597                 mp->b_datap->db_type = M_PROTO;
2598         noenable(q);
2599         (void) putbq(q, mp);
2600 
2601         /*
2602          * Make sure there is at most one outstanding request per queue.
2603          */


2674                          */
2675                         if ((bp->b_datap->db_type == M_PROTO) &&
2676                             ((bp->b_wptr - bp->b_rptr) >=
2677                             sizeof (struct T_exdata_ind)) &&
2678                             (((struct T_exdata_ind *)bp->b_rptr)->PRIM_type
2679                             == T_EXDATA_IND)) {
2680                                 /* bp is T_EXDATA_IND */
2681                                 mutex_exit(QLOCK(rq));
2682                                 releasestr(q); /* decrement sd_refcnt  */
2683                                 return (1); /* expdata is on a read queue */
2684                         }
2685                         bp = bp->b_next; /* next message */
2686                 }
2687                 mutex_exit(QLOCK(rq));
2688                 rq = rq->q_next;     /* next upstream queue */
2689         } while (rq != NULL);
2690         releasestr(q);
2691         return (0);             /* no expdata on read queues */
2692 }
2693 
2694 /* ONC_PLUS EXTRACT END */
2695 static void
2696 tim_tcap_timer(void *q_ptr)
2697 {
2698         queue_t *q = (queue_t *)q_ptr;
2699         struct tim_tim *tp = (struct tim_tim *)q->q_ptr;
2700 
2701         ASSERT(tp != NULL && tp->tim_tcap_timoutid != 0);
2702         ASSERT((tp->tim_flags & TI_CAP_RECVD) != 0);
2703 
2704         tp->tim_tcap_timoutid = 0;
2705         TILOG("tim_tcap_timer: fired\n", 0);
2706         tim_tcap_genreply(q, tp);
2707 }
2708 
2709 /*
2710  * tim_tcap_genreply() is called either from timeout routine or when
2711  * T_ERROR_ACK is received. In both cases it means that underlying
2712  * transport doesn't provide T_CAPABILITY_REQ.
2713  */
2714 static void


   1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */

  21 /*
  22  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*      Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T     */
  26 /*        All Rights Reserved   */
  27 
  28 
  29 /*
  30  * Transport Interface Library cooperating module - issue 2
  31  */
  32 

  33 #include <sys/param.h>
  34 #include <sys/types.h>
  35 #include <sys/stream.h>
  36 #include <sys/stropts.h>
  37 #include <sys/strsubr.h>
  38 #define _SUN_TPI_VERSION 2
  39 #include <sys/tihdr.h>
  40 #include <sys/timod.h>
  41 #include <sys/suntpi.h>
  42 #include <sys/debug.h>
  43 #include <sys/strlog.h>
  44 #include <sys/errno.h>
  45 #include <sys/cred.h>
  46 #include <sys/cmn_err.h>
  47 #include <sys/kmem.h>
  48 #include <sys/sysmacros.h>
  49 #include <sys/ddi.h>
  50 #include <sys/sunddi.h>
  51 #include <sys/strsun.h>
  52 #include <c2/audit.h>


 176  *
 177  * There may be 3 states for transport:
 178  *
 179  * 1) It provides T_CAPABILITY_REQ
 180  * 2) It does not provide T_CAPABILITY_REQ
 181  * 3) It is not known yet whether transport provides T_CAPABILITY_REQ or not.
 182  *
 183  * It is assumed that the underlying transport either provides
 184  * T_CAPABILITY_REQ or not and this does not changes during the
 185  * system lifetime.
 186  *
 187  */
 188 #define PEEK_RDQ_EXPIND 0x0001  /* look for expinds on stream rd queues */
 189 #define WAITIOCACK      0x0002  /* waiting for info for ioctl act       */
 190 #define CLTS            0x0004  /* connectionless transport             */
 191 #define COTS            0x0008  /* connection-oriented transport        */
 192 #define CONNWAIT        0x0010  /* waiting for connect confirmation     */
 193 #define LOCORDREL       0x0020  /* local end has orderly released       */
 194 #define REMORDREL       0x0040  /* remote end had orderly released      */
 195 #define NAMEPROC        0x0080  /* processing a NAME ioctl              */

 196 #define DO_MYNAME       0x0100  /* timod handles TI_GETMYNAME           */

 197 #define DO_PEERNAME     0x0200  /* timod handles TI_GETPEERNAME         */
 198 #define TI_CAP_RECVD    0x0400  /* TI_CAPABILITY received               */
 199 #define CAP_WANTS_INFO  0x0800  /* TI_CAPABILITY has TC1_INFO set       */
 200 #define WAIT_IOCINFOACK 0x1000  /* T_INFO_REQ generated from ioctl      */
 201 #define WAIT_CONNRESACK 0x2000  /* waiting for T_OK_ACK to T_CONN_RES   */
 202 
 203 
 204 /* Debugging facilities */
 205 /*
 206  * Logging needed for debugging timod should only appear in DEBUG kernel.
 207  */
 208 #ifdef DEBUG
 209 #define TILOG(msg, arg)         tilog((msg), (arg))
 210 #define TILOGP(msg, arg)        tilogp((msg), (arg))
 211 #else
 212 #define TILOG(msg, arg)
 213 #define TILOGP(msg, arg)
 214 #endif
 215 
 216 


 292 #define TIM_HASH(id) (((uintptr_t)(id) >> 8) % TIM_HASH_SIZE)
 293 #else
 294 #define TIM_HASH(id) ((uintptr_t)(id) % TIM_HASH_SIZE)
 295 #endif  /* _ILP32 */
 296 static struct tim_tim   *tim_hash[TIM_HASH_SIZE];
 297 int             tim_cnt = 0;
 298 
 299 static void tilog(char *, t_scalar_t);
 300 static void tilogp(char *, uintptr_t);
 301 static mblk_t *tim_filladdr(queue_t *, mblk_t *, boolean_t);
 302 static void tim_addlink(struct tim_tim  *);
 303 static void tim_dellink(struct tim_tim  *);
 304 static struct tim_tim *tim_findlink(t_uscalar_t);
 305 static void tim_recover(queue_t *, mblk_t *, t_scalar_t);
 306 static void tim_ioctl_retry(queue_t *);
 307 
 308 int dotilog = 0;
 309 
 310 #define TIMOD_ID        3
 311 

 312 static int timodopen(queue_t *, dev_t *, int, int, cred_t *);

 313 static int timodclose(queue_t *, int, cred_t *);
 314 static void timodwput(queue_t *, mblk_t *);
 315 static void timodrput(queue_t *, mblk_t *);

 316 static void timodrsrv(queue_t *);

 317 static void timodwsrv(queue_t *);

 318 static int timodrproc(queue_t *, mblk_t *);
 319 static int timodwproc(queue_t *, mblk_t *);

 320 
 321 /* stream data structure definitions */
 322 
 323 static struct module_info timod_info =
 324         {TIMOD_ID, "timod", 0, INFPSZ, 512, 128};
 325 static struct qinit timodrinit = {
 326         (int (*)())timodrput,
 327         (int (*)())timodrsrv,
 328         timodopen,
 329         timodclose,
 330         nulldev,
 331         &timod_info,
 332         NULL
 333 };
 334 static struct qinit timodwinit = {
 335         (int (*)())timodwput,
 336         (int (*)())timodwsrv,
 337         timodopen,
 338         timodclose,
 339         nulldev,
 340         &timod_info,
 341         NULL
 342 };
 343 static struct streamtab timinfo = { &timodrinit, &timodwinit, NULL, NULL };
 344 

 345 /*
 346  * timodopen -  open routine gets called when the module gets pushed
 347  *              onto the stream.
 348  */
 349 /*ARGSUSED*/
 350 static int
 351 timodopen(
 352         queue_t *q,
 353         dev_t *devp,
 354         int flag,
 355         int sflag,
 356         cred_t *crp)
 357 {
 358         struct tim_tim *tp;
 359         struct stroptions *sop;
 360         mblk_t *bp;
 361 
 362         ASSERT(q != NULL);
 363 
 364         if (q->q_ptr) {


 460 }
 461 
 462 static void
 463 tim_buffer(void *arg)
 464 {
 465         queue_t *q = arg;
 466         struct tim_tim *tp = (struct tim_tim *)q->q_ptr;
 467 
 468         ASSERT(tp);
 469 
 470         if (q->q_flag & QREADR) {
 471                 ASSERT(tp->tim_rbufcid);
 472                 tp->tim_rbufcid = 0;
 473         } else {
 474                 ASSERT(tp->tim_wbufcid);
 475                 tp->tim_wbufcid = 0;
 476         }
 477         enableok(q);
 478         qenable(q);
 479 }

 480 
 481 /*
 482  * timodclose - This routine gets called when the module gets popped
 483  * off of the stream.
 484  */
 485 /*ARGSUSED*/
 486 static int
 487 timodclose(
 488         queue_t *q,
 489         int flag,
 490         cred_t *crp)
 491 {
 492         struct tim_tim *tp;
 493         mblk_t *mp;
 494         mblk_t *nmp;
 495 
 496         ASSERT(q != NULL);
 497 
 498         tp = (struct tim_tim *)q->q_ptr;
 499         q->q_ptr = NULL;


 608                 switch (pptr->type) {
 609                 case T_EXDATA_IND:
 610                 case T_DATA_IND:
 611                 case T_UNITDATA_IND:
 612                         if (bcanputnext(q, mp->b_band))
 613                                 putnext(q, mp);
 614                         else
 615                                 (void) putq(q, mp);
 616                         break;
 617                 default:
 618                         (void) timodrproc(q, mp);
 619                         break;
 620                 }
 621                 break;
 622         default:
 623                 (void) timodrproc(q, mp);
 624                 break;
 625         }
 626 }
 627 

 628 /*
 629  * timodrsrv -  Module read queue service procedure.  This is called when
 630  *              messages are placed on an empty queue, when high priority
 631  *              messages are placed on the queue, and when flow control
 632  *              restrictions subside.  This code used to be included in a
 633  *              put procedure, but it was moved to a service procedure
 634  *              because several points were added where memory allocation
 635  *              could fail, and there is no reasonable recovery mechanism
 636  *              from the put procedure.
 637  */
 638 /*ARGSUSED*/
 639 static void
 640 timodrsrv(queue_t *q)
 641 {

 642         mblk_t *mp;
 643         struct tim_tim *tp;
 644 
 645         ASSERT(q != NULL);
 646 
 647         tp = (struct tim_tim *)q->q_ptr;
 648         if (!tp)
 649                 return;
 650 
 651         while ((mp = getq(q)) != NULL) {
 652                 if (timodrproc(q, mp)) {
 653                         /*
 654                          * timodrproc did a putbq - stop processing
 655                          * messages.
 656                          */
 657                         return;
 658                 }
 659         }

 660 }
 661 
 662 /*
 663  * Perform common processing when a T_CAPABILITY_ACK or T_INFO_ACK
 664  * arrive.  Set the queue properties and adjust the tim_flags according
 665  * to the service type.
 666  */
 667 static void
 668 timodprocessinfo(queue_t *q, struct tim_tim *tp, struct T_info_ack *tia)
 669 {
 670         TILOG("timodprocessinfo: strqset(%d)\n", tia->TIDU_size);
 671         (void) strqset(q, QMAXPSZ, 0, tia->TIDU_size);
 672         (void) strqset(OTHERQ(q), QMAXPSZ, 0, tia->TIDU_size);
 673 
 674         if ((tia->SERV_type == T_COTS) || (tia->SERV_type == T_COTS_ORD))
 675                 tp->tim_flags = (tp->tim_flags & ~CLTS) | COTS;
 676         else if (tia->SERV_type == T_CLTS)
 677                 tp->tim_flags = (tp->tim_flags & ~COTS) | CLTS;
 678 }
 679 
 680 static int
 681 timodrproc(queue_t *q, mblk_t *mp)
 682 {
 683         uint32_t auditing = AU_AUDITING();
 684         union T_primitives *pptr;
 685         struct tim_tim *tp;
 686         struct iocblk *iocbp;
 687         mblk_t *nbp;
 688         size_t blen;

 689 
 690         tp = (struct tim_tim *)q->q_ptr;
 691 

 692         switch (mp->b_datap->db_type) {
 693         default:
 694                 putnext(q, mp);
 695                 break;
 696 
 697         case M_ERROR:
 698                 TILOG("timodrproc: Got M_ERROR, flags = %x\n", tp->tim_flags);
 699                 /*
 700                  * There is no specified standard response for driver when it
 701                  * receives unknown message type and M_ERROR is one
 702                  * possibility. If we send T_CAPABILITY_REQ down and transport
 703                  * provider responds with M_ERROR we assume that it doesn't
 704                  * understand this message type. This assumption may be
 705                  * sometimes incorrect (transport may reply with M_ERROR for
 706                  * some other reason) but there is no way for us to distinguish
 707                  * between different cases. In the worst case timod and everyone
 708                  * else sharing global transport description with it may end up
 709                  * emulating T_CAPABILITY_REQ.
 710                  */
 711 


 752                          * was too short, then the message would have
 753                          * already been putnext'd, and would thus
 754                          * never appear here.  Just the same, the code
 755                          * below handles the impossible case since
 756                          * it's easy to do and saves future
 757                          * maintainers from unfortunate accidents.
 758                          */
 759                         ASSERT(mp->b_datap->db_type == M_PROTO);
 760                         if (mp->b_datap->db_type == M_PROTO &&
 761                             !bcanputnext(q, mp->b_band)) {
 762                                 (void) putbq(q, mp);
 763                                 return (1);
 764                         }
 765                         putnext(q, mp);
 766                         break;
 767                 }
 768 
 769                 pptr = (union T_primitives *)mp->b_rptr;
 770                 switch (pptr->type) {
 771                 default:

 772 
 773                         if (auditing)
 774                                 audit_sock(T_UNITDATA_IND, q, mp, TIMOD_ID);

 775                         putnext(q, mp);
 776                         break;

 777 
 778                 case T_ERROR_ACK:
 779                         /* Restore db_type - recover() might have changed it */
 780                         mp->b_datap->db_type = M_PCPROTO;
 781                         if (blen < sizeof (struct T_error_ack)) {
 782                                 putnext(q, mp);
 783                                 break;
 784                         }
 785 
 786                         tilog("timodrproc: Got T_ERROR_ACK, flags = %x\n",
 787                             tp->tim_flags);
 788 
 789                         if ((tp->tim_flags & WAIT_CONNRESACK) &&
 790                             tp->tim_saved_prim == pptr->error_ack.ERROR_prim) {
 791                                 tp->tim_flags &=
 792                                     ~(WAIT_CONNRESACK | WAITIOCACK);
 793                                 freemsg(tp->tim_iocsave);
 794                                 tp->tim_iocsave = NULL;
 795                                 tp->tim_saved_prim = -1;
 796                                 putnext(q, mp);


 866                                         ntp->tim_peermaxlen = indp->SRC_length;
 867                                 }
 868                                 ntp->tim_peerlen = indp->SRC_length;
 869                                 ptr = (caddr_t)indp + indp->SRC_offset;
 870                                 bcopy(ptr, ntp->tim_peername, ntp->tim_peerlen);
 871 
 872                                 mutex_exit(&ntp->tim_mutex);
 873 
 874                         cresackout:
 875                                 rw_exit(&tim_list_rwlock);
 876                                 tp->tim_flags &=
 877                                     ~(WAIT_CONNRESACK | WAITIOCACK);
 878                                 freemsg(tp->tim_iocsave);
 879                                 tp->tim_iocsave = NULL;
 880                                 tp->tim_saved_prim = -1;
 881                         }
 882 
 883                         tim_send_reply(q, mp, tp, pptr->ok_ack.CORRECT_prim);
 884                         break;
 885 

 886                 case T_BIND_ACK: {
 887                         struct T_bind_ack *ackp =
 888                             (struct T_bind_ack *)mp->b_rptr;
 889 
 890                         /* Restore db_type - recover() might have changed it */
 891                         mp->b_datap->db_type = M_PCPROTO;
 892                         if (blen < sizeof (*ackp)) {
 893                                 putnext(q, mp);
 894                                 break;
 895                         }
 896 
 897                         /* save negotiated backlog */
 898                         tp->tim_backlog = ackp->CONIND_number;
 899 
 900                         if (((tp->tim_flags & WAITIOCACK) == 0) ||
 901                             ((tp->tim_saved_prim != O_T_BIND_REQ) &&
 902                             (tp->tim_saved_prim != T_BIND_REQ))) {
 903                                 putnext(q, mp);
 904                                 break;
 905                         }


 929                                         ASSERT(tp->tim_mymaxlen >= 0);
 930                                         if (tp->tim_mymaxlen != NULL) {
 931                                                 kmem_free(tp->tim_myname,
 932                                                     tp->tim_mymaxlen);
 933                                         }
 934                                         tp->tim_myname = p;
 935                                         tp->tim_mymaxlen = ackp->ADDR_length;
 936                                 }
 937                                 tp->tim_mylen = ackp->ADDR_length;
 938                                 bcopy(mp->b_rptr + ackp->ADDR_offset,
 939                                     tp->tim_myname, tp->tim_mylen);
 940                         }
 941                         tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
 942                         tp->tim_iocsave = NULL;
 943                         tp->tim_saved_prim = -1;
 944                         tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
 945                             TI_CAP_RECVD | CAP_WANTS_INFO);
 946                         break;
 947                 }
 948 

 949                 case T_OPTMGMT_ACK:
 950 
 951                         tilog("timodrproc: Got T_OPTMGMT_ACK\n", 0);
 952 
 953                         /* Restore db_type - recover() might have change it */
 954                         mp->b_datap->db_type = M_PCPROTO;
 955 
 956                         if (((tp->tim_flags & WAITIOCACK) == 0) ||
 957                             ((tp->tim_saved_prim != T_SVR4_OPTMGMT_REQ) &&
 958                             (tp->tim_saved_prim != T_OPTMGMT_REQ))) {
 959                                 putnext(q, mp);
 960                         } else {
 961                                 ASSERT(tp->tim_iocsave != NULL);
 962                                 tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
 963                                 tp->tim_iocsave = NULL;
 964                                 tp->tim_saved_prim = -1;
 965                                 tp->tim_flags &= ~(WAITIOCACK |
 966                                     WAIT_IOCINFOACK | TI_CAP_RECVD |
 967                                     CAP_WANTS_INFO);
 968                         }


1161                                 }
1162                                 mp->b_wptr += 2*sizeof (uint32_t);
1163                         }
1164                         tim_ioctl_send_reply(q, tp->tim_iocsave, mp);
1165                         tp->tim_iocsave = NULL;
1166                         tp->tim_saved_prim = -1;
1167                         tp->tim_flags &= ~(WAITIOCACK | WAIT_IOCINFOACK |
1168                             TI_CAP_RECVD | CAP_WANTS_INFO);
1169                         break;
1170                 }
1171             }
1172 
1173             putnext(q, mp);
1174             break;
1175 
1176             case T_ADDR_ACK:
1177                 tilog("timodrproc: Got T_ADDR_ACK\n", 0);
1178                 tim_send_reply(q, mp, tp, T_ADDR_REQ);
1179                 break;
1180 

1181                 case T_CONN_IND: {
1182                         struct T_conn_ind *tcip =
1183                             (struct T_conn_ind *)mp->b_rptr;
1184 
1185                         tilog("timodrproc: Got T_CONN_IND\n", 0);
1186 
1187                         if (blen >= sizeof (*tcip) &&
1188                             MBLKIN(mp, tcip->SRC_offset, tcip->SRC_length)) {
1189                                 if (((nbp = dupmsg(mp)) != NULL) ||
1190                                     ((nbp = copymsg(mp)) != NULL)) {
1191                                         nbp->b_next = tp->tim_consave;
1192                                         tp->tim_consave = nbp;
1193                                 } else {
1194                                         tim_recover(q, mp,
1195                                             (t_scalar_t)sizeof (mblk_t));
1196                                         return (1);
1197                                 }
1198                         }

1199                         if (auditing)
1200                                 audit_sock(T_CONN_IND, q, mp, TIMOD_ID);

1201                         putnext(q, mp);
1202                         break;
1203                 }
1204 

1205             case T_CONN_CON:
1206                 mutex_enter(&tp->tim_mutex);
1207                 if (tp->tim_peercred != NULL)
1208                         crfree(tp->tim_peercred);
1209                 tp->tim_peercred = msg_getcred(mp, &tp->tim_cpid);
1210                 if (tp->tim_peercred != NULL)
1211                         crhold(tp->tim_peercred);
1212                 mutex_exit(&tp->tim_mutex);
1213 
1214                 tilog("timodrproc: Got T_CONN_CON\n", 0);
1215 
1216                 tp->tim_flags &= ~CONNWAIT;
1217                 putnext(q, mp);
1218                 break;
1219 
1220             case T_DISCON_IND: {
1221                 struct T_discon_ind *disp;
1222                 struct T_conn_ind *conp;
1223                 mblk_t *pbp = NULL;
1224 


1297                                 tp->tim_provinfo->tpi_capability = PI_YES;
1298                         PI_PROVUNLOCK(tp->tim_provinfo);
1299 
1300                         /* Reset possible pending timeout */
1301                         if (tp->tim_tcap_timoutid != 0) {
1302                                 (void) quntimeout(q, tp->tim_tcap_timoutid);
1303                                 tp->tim_tcap_timoutid = 0;
1304                         }
1305 
1306                         tca = (struct T_capability_ack *)mp->b_rptr;
1307 
1308                         if (tca->CAP_bits1 & TC1_INFO)
1309                                 timodprocessinfo(q, tp, &tca->INFO_ack);
1310 
1311                         tim_send_reply(q, mp, tp, T_CAPABILITY_REQ);
1312                 }
1313                 break;
1314             }
1315             break;
1316 

1317         case M_FLUSH:
1318 
1319                 tilog("timodrproc: Got M_FLUSH\n", 0);
1320 
1321                 if (*mp->b_rptr & FLUSHR) {
1322                         if (*mp->b_rptr & FLUSHBAND)
1323                                 flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
1324                         else
1325                                 flushq(q, FLUSHDATA);
1326                 }
1327                 putnext(q, mp);
1328                 break;

1329 
1330         case M_IOCACK:
1331             iocbp = (struct iocblk *)mp->b_rptr;
1332 
1333             tilog("timodrproc: Got M_IOCACK\n", 0);
1334 
1335             if (iocbp->ioc_cmd == TI_GETMYNAME) {
1336 
1337                 /*
1338                  * Transport provider supports this ioctl,
1339                  * so I don't have to.
1340                  */
1341                 if ((tp->tim_flags & DO_MYNAME) != 0) {
1342                         tp->tim_flags &= ~DO_MYNAME;
1343                         PI_PROVLOCK(tp->tim_provinfo);
1344                         tp->tim_provinfo->tpi_myname = PI_YES;
1345                         PI_PROVUNLOCK(tp->tim_provinfo);
1346                 }
1347 
1348                 ASSERT(tp->tim_mymaxlen >= 0);


1384                         mblk_t *bp;
1385 
1386                         bp = tp->tim_consave;
1387                         while (bp != NULL) {
1388                                 nbp = bp->b_next;
1389                                 bp->b_next = NULL;
1390                                 freemsg(bp);
1391                                 bp = nbp;
1392                         }
1393                         tp->tim_consave = NULL;
1394                 }
1395                 /* tim_iocsave may already be overwritten. */
1396                 if (tp->tim_saved_prim == -1) {
1397                         freemsg(tp->tim_iocsave);
1398                         tp->tim_iocsave = NULL;
1399                 }
1400             }
1401             putnext(q, mp);
1402             break;
1403 

1404         case M_IOCNAK:
1405 
1406                 tilog("timodrproc: Got M_IOCNAK\n", 0);
1407 
1408                 iocbp = (struct iocblk *)mp->b_rptr;
1409                 if (((iocbp->ioc_cmd == TI_GETMYNAME) ||
1410                     (iocbp->ioc_cmd == TI_GETPEERNAME)) &&
1411                     ((iocbp->ioc_error == EINVAL) || (iocbp->ioc_error == 0))) {
1412                         PI_PROVLOCK(tp->tim_provinfo);
1413                         if (iocbp->ioc_cmd == TI_GETMYNAME) {
1414                                 if (tp->tim_provinfo->tpi_myname == PI_DONTKNOW)
1415                                         tp->tim_provinfo->tpi_myname = PI_NO;
1416                         } else if (iocbp->ioc_cmd == TI_GETPEERNAME) {
1417                                 if (tp->tim_provinfo->tpi_peername == PI_DONTKNOW)
1418                                         tp->tim_provinfo->tpi_peername = PI_NO;
1419                         }
1420                         PI_PROVUNLOCK(tp->tim_provinfo);
1421                         /* tim_iocsave may already be overwritten. */
1422                         if ((tp->tim_iocsave != NULL) &&
1423                             (tp->tim_saved_prim == -1)) {
1424                                 freemsg(mp);
1425                                 mp = tp->tim_iocsave;
1426                                 tp->tim_iocsave = NULL;
1427                                 tp->tim_flags |= NAMEPROC;
1428                                 if (ti_doname(WR(q), mp) != DONAME_CONT) {
1429                                         tp->tim_flags &= ~NAMEPROC;
1430                                 }
1431                                 break;
1432                         }
1433                 }
1434                 putnext(q, mp);
1435                 break;

1436         }
1437 
1438         return (0);
1439 }
1440 

1441 /*
1442  * timodwput -  Module write put procedure.  This is called from
1443  *              the module, driver, or stream head upstream/downstream.
1444  *              Handles M_FLUSH, M_DATA and some M_PROTO (T_DATA_REQ,
1445  *              and T_UNITDATA_REQ) messages. All others are queued to
1446  *              be handled by the service procedures.
1447  */
1448 
1449 static void
1450 timodwput(queue_t *q, mblk_t *mp)
1451 {
1452         union T_primitives *pptr;
1453         struct tim_tim *tp;
1454         struct iocblk *iocbp;
1455 
1456         /*
1457          * Enqueue normal-priority messages if our queue already
1458          * holds some messages for deferred processing but don't
1459          * enqueue those M_IOCTLs which will result in an
1460          * M_PCPROTO (ie, high priority) message being created.
1461          */

1462         if (q->q_first != 0 && mp->b_datap->db_type < QPCTL) {
1463                 if (mp->b_datap->db_type == M_IOCTL) {
1464                         iocbp = (struct iocblk *)mp->b_rptr;
1465                         switch (iocbp->ioc_cmd) {
1466                         default:
1467                                 (void) putq(q, mp);
1468                                 return;
1469 
1470                         case TI_GETINFO:
1471                         case TI_SYNC:
1472                         case TI_CAPABILITY:
1473                                 break;
1474                         }
1475                 } else {
1476                         (void) putq(q, mp);
1477                         return;
1478                 }
1479         }

1480         /*
1481          * Inline processing of data (to avoid additional procedure call).
1482          * Rest is handled in timodwproc.
1483          */
1484 
1485         switch (mp->b_datap->db_type) {
1486         case M_DATA:
1487                 tp = (struct tim_tim *)q->q_ptr;
1488                 ASSERT(tp);
1489                 if (tp->tim_flags & CLTS) {
1490                         mblk_t  *tmp;
1491 
1492                         if ((tmp = tim_filladdr(q, mp, B_FALSE)) == NULL) {
1493                                 (void) putq(q, mp);
1494                                 break;
1495                         } else {
1496                                 mp = tmp;
1497                         }
1498                 }
1499                 if (bcanputnext(q, mp->b_band))
1500                         putnext(q, mp);
1501                 else
1502                         (void) putq(q, mp);
1503                 break;
1504         case M_PROTO:
1505         case M_PCPROTO:
1506                 pptr = (union T_primitives *)mp->b_rptr;
1507                 switch (pptr->type) {

1508                 case T_UNITDATA_REQ:
1509                         tp = (struct tim_tim *)q->q_ptr;
1510                         ASSERT(tp);
1511                         if (tp->tim_flags & CLTS) {
1512                                 mblk_t  *tmp;
1513 
1514                                 tmp = tim_filladdr(q, mp, B_FALSE);
1515                                 if (tmp == NULL) {
1516                                         (void) putq(q, mp);
1517                                         break;
1518                                 } else {
1519                                         mp = tmp;
1520                                 }
1521                         }
1522                         if (bcanputnext(q, mp->b_band))
1523                                 putnext(q, mp);
1524                         else
1525                                 (void) putq(q, mp);
1526                         break;
1527 
1528                 case T_DATA_REQ:
1529                 case T_EXDATA_REQ:
1530                         if (bcanputnext(q, mp->b_band))
1531                                 putnext(q, mp);
1532                         else
1533                                 (void) putq(q, mp);
1534                         break;
1535                 default:
1536                         (void) timodwproc(q, mp);
1537                         break;
1538                 }
1539                 break;

1540         default:
1541                 (void) timodwproc(q, mp);
1542                 break;
1543         }
1544 }
1545 /*
1546  * timodwsrv -  Module write queue service procedure.
1547  *              This is called when messages are placed on an empty queue,
1548  *              when high priority messages are placed on the queue, and
1549  *              when flow control restrictions subside.  This code used to
1550  *              be included in a put procedure, but it was moved to a
1551  *              service procedure because several points were added where
1552  *              memory allocation could fail, and there is no reasonable
1553  *              recovery mechanism from the put procedure.
1554  */
1555 static void
1556 timodwsrv(queue_t *q)
1557 {
1558         mblk_t *mp;
1559 


1575 /*
1576  * Common routine to process write side messages
1577  */
1578 
1579 static int
1580 timodwproc(queue_t *q, mblk_t *mp)
1581 {
1582         union T_primitives *pptr;
1583         struct tim_tim *tp;
1584         uint32_t auditing = AU_AUDITING();
1585         mblk_t *tmp;
1586         struct iocblk *iocbp;
1587         int error;
1588 
1589         tp = (struct tim_tim *)q->q_ptr;
1590 
1591         switch (mp->b_datap->db_type) {
1592         default:
1593                 putnext(q, mp);
1594                 break;

1595 
1596         case M_DATA:
1597                 if (tp->tim_flags & CLTS) {
1598                         if ((tmp = tim_filladdr(q, mp, B_TRUE)) == NULL) {
1599                                 return (1);
1600                         } else {
1601                                 mp = tmp;
1602                         }
1603                 }
1604                 if (!bcanputnext(q, mp->b_band)) {
1605                         (void) putbq(q, mp);
1606                         return (1);
1607                 }
1608                 putnext(q, mp);
1609                 break;
1610 

1611         case M_IOCTL:
1612 
1613                 iocbp = (struct iocblk *)mp->b_rptr;
1614                 TILOG("timodwproc: Got M_IOCTL(%d)\n", iocbp->ioc_cmd);
1615 
1616                 ASSERT(MBLKL(mp) == sizeof (struct iocblk));
1617 
1618                 /*
1619                  * TPI requires we await response to a previously sent message
1620                  * before handling another, put it back on the head of queue.
1621                  * Since putbq() may see QWANTR unset when called from the
1622                  * service procedure, the queue must be explicitly scheduled
1623                  * for service, as no backenable will occur for this case.
1624                  * tim_ioctl_retry() sets a timer to handle the qenable.
1625                  */
1626                 if (tp->tim_flags & WAITIOCACK) {
1627                         TILOG("timodwproc: putbq M_IOCTL(%d)\n",
1628                             iocbp->ioc_cmd);
1629                         (void) putbq(q, mp);
1630                         /* Called from timodwsrv() and messages on queue */
1631                         if (!(q->q_flag & QWANTR))
1632                                 tim_ioctl_retry(q);
1633                         return (1);
1634                 }

1635 
1636                 switch (iocbp->ioc_cmd) {
1637                 default:
1638                         putnext(q, mp);
1639                         break;
1640 
1641                 case _I_GETPEERCRED:
1642                         if ((tp->tim_flags & COTS) == 0) {
1643                                 miocnak(q, mp, 0, ENOTSUP);
1644                         } else {
1645                                 mblk_t *cmp = mp->b_cont;
1646                                 k_peercred_t *kp = NULL;
1647 
1648                                 mutex_enter(&tp->tim_mutex);
1649                                 if (cmp != NULL &&
1650                                     iocbp->ioc_flag == IOC_NATIVE &&
1651                                     (tp->tim_flags &
1652                                     (CONNWAIT|LOCORDREL|REMORDREL)) == 0 &&
1653                                     tp->tim_peercred != NULL &&
1654                                     DB_TYPE(cmp) == M_DATA &&


1864                                 /*
1865                                  * It could happen when timod is awaiting ack
1866                                  * for TI_GETPEERNAME/TI_GETMYNAME.
1867                                  */
1868                                 if (tp->tim_iocsave != NULL) {
1869                                         freemsg(tp->tim_iocsave);
1870                                         tp->tim_iocsave = NULL;
1871                                         tp->tim_saved_prim = -1;
1872                                 }
1873                                 break;
1874 
1875                         default:
1876                                 cmn_err(CE_PANIC,
1877                                     "timodwproc: unknown tpi_capability value "
1878                                     "%d\n", tp->tim_provinfo->tpi_capability);
1879                                 break;
1880                         }
1881                 }
1882                 break;
1883 

1884                 case TI_GETMYNAME:
1885 
1886                         tilog("timodwproc: Got TI_GETMYNAME\n", 0);
1887 
1888                         if (tp->tim_provinfo->tpi_myname == PI_YES) {
1889                                 putnext(q, mp);
1890                                 break;
1891                         }
1892                         goto getname;
1893 
1894                 case TI_GETPEERNAME:
1895 
1896                         tilog("timodwproc: Got TI_GETPEERNAME\n", 0);
1897 
1898                         if (tp->tim_provinfo->tpi_peername == PI_YES) {
1899                                 putnext(q, mp);
1900                                 break;
1901                         }
1902 getname:
1903                         if ((tmp = copymsg(mp)) == NULL) {


1933                         return (1);
1934                 }
1935 
1936                 pptr = (union T_primitives *)mp->b_rptr;
1937                 switch (pptr->type) {
1938                 default:
1939                         putnext(q, mp);
1940                         break;
1941 
1942                 case T_EXDATA_REQ:
1943                 case T_DATA_REQ:
1944                         if (pptr->type == T_EXDATA_REQ)
1945                                 tilog("timodwproc: Got T_EXDATA_REQ\n", 0);
1946 
1947                 if (!bcanputnext(q, mp->b_band)) {
1948                         (void) putbq(q, mp);
1949                         return (1);
1950                 }
1951                 putnext(q, mp);
1952                 break;

1953 
1954                 case T_UNITDATA_REQ:
1955                         if (tp->tim_flags & CLTS) {
1956                                 tmp = tim_filladdr(q, mp, B_TRUE);
1957                                 if (tmp == NULL) {
1958                                         return (1);
1959                                 } else {
1960                                         mp = tmp;
1961                                 }
1962                         }
1963                         if (auditing)
1964                                 audit_sock(T_UNITDATA_REQ, q, mp, TIMOD_ID);
1965                 if (!bcanputnext(q, mp->b_band)) {
1966                                 (void) putbq(q, mp);
1967                                 return (1);
1968                         }
1969                         putnext(q, mp);
1970                         break;
1971 

1972                 case T_CONN_REQ: {
1973                         struct T_conn_req *reqp = (struct T_conn_req *)
1974                             mp->b_rptr;
1975                         void *p;
1976 
1977                         tilog("timodwproc: Got T_CONN_REQ\n", 0);
1978 
1979                         if (MBLKL(mp) < sizeof (struct T_conn_req)) {
1980                                 merror(q, mp, EPROTO);
1981                                 return (1);
1982                         }
1983 
1984                         if (tp->tim_flags & DO_PEERNAME) {
1985                                 if (!MBLKIN(mp, reqp->DEST_offset,
1986                                     reqp->DEST_length)) {
1987                                         merror(q, mp, EPROTO);
1988                                         return (1);
1989                                 }
1990                                 ASSERT(reqp->DEST_length >= 0);
1991                                 mutex_enter(&tp->tim_mutex);


1997                                                 tilog("timodwproc: kmem_alloc "
1998                                                     "failed, attempting "
1999                                                     "recovery\n", 0);
2000                                                 tim_recover(q, mp,
2001                                                     reqp->DEST_length);
2002                                                 return (1);
2003                                         }
2004                                         if (tp->tim_peermaxlen)
2005                                                 kmem_free(tp->tim_peername,
2006                                                     tp->tim_peermaxlen);
2007                                         tp->tim_peername = p;
2008                                         tp->tim_peermaxlen = reqp->DEST_length;
2009                                 }
2010                                 tp->tim_peerlen = reqp->DEST_length;
2011                                 p = mp->b_rptr + reqp->DEST_offset;
2012                                 bcopy(p, tp->tim_peername, tp->tim_peerlen);
2013                                 mutex_exit(&tp->tim_mutex);
2014                         }
2015                         if (tp->tim_flags & COTS)
2016                                 tp->tim_flags |= CONNWAIT;

2017                         if (auditing)
2018                                 audit_sock(T_CONN_REQ, q, mp, TIMOD_ID);

2019                 putnext(q, mp);
2020                 break;
2021                 }
2022 
2023                 case O_T_CONN_RES:
2024                 case T_CONN_RES: {
2025                         struct T_conn_res *resp;
2026                         struct T_conn_ind *indp;
2027                         mblk_t *pmp = NULL;
2028                         mblk_t *nbp;
2029 
2030                         if (MBLKL(mp) < sizeof (struct T_conn_res) ||
2031                             (tp->tim_flags & WAITIOCACK)) {
2032                                 merror(q, mp, EPROTO);
2033                                 return (1);
2034                         }
2035 
2036                         resp = (struct T_conn_res *)mp->b_rptr;
2037                         for (tmp = tp->tim_consave; tmp != NULL;
2038                             tmp = tmp->b_next) {


2059                         /*
2060                          * Construct a list with:
2061                          *      nbp - copy of user's original request
2062                          *      tmp - the extracted T_conn_ind
2063                          */
2064                         nbp->b_cont = tmp;
2065                         /*
2066                          * tim_iocsave may be non-NULL when timod is awaiting
2067                          * ack for TI_GETPEERNAME/TI_GETMYNAME.
2068                          */
2069                         freemsg(tp->tim_iocsave);
2070                         tp->tim_iocsave = nbp;
2071                         tp->tim_saved_prim = pptr->type;
2072                         tp->tim_flags |= WAIT_CONNRESACK | WAITIOCACK;
2073 
2074                 cresout:
2075                         putnext(q, mp);
2076                         break;
2077                 }
2078 

2079                 case T_DISCON_REQ: {
2080                         struct T_discon_req *disp;
2081                         struct T_conn_ind *conp;
2082                         mblk_t *pmp = NULL;
2083 
2084                         if (MBLKL(mp) < sizeof (struct T_discon_req)) {
2085                                 merror(q, mp, EPROTO);
2086                                 return (1);
2087                         }
2088 
2089                         disp = (struct T_discon_req *)mp->b_rptr;
2090                         tp->tim_flags &= ~(CONNWAIT|LOCORDREL|REMORDREL);
2091                         tim_clear_peer(tp);
2092 
2093                         /*
2094                          * If we are already connected, there won't
2095                          * be any messages on tim_consave.
2096                          */
2097                         for (tmp = tp->tim_consave; tmp; tmp = tmp->b_next) {
2098                                 conp = (struct T_conn_ind *)tmp->b_rptr;


2114 
2115                 case T_ORDREL_REQ:
2116                         if (tp->tim_flags & REMORDREL) {
2117                                 tp->tim_flags &= ~(LOCORDREL|REMORDREL);
2118                                 tim_clear_peer(tp);
2119                         } else {
2120                                 tp->tim_flags |= LOCORDREL;
2121                         }
2122                         putnext(q, mp);
2123                         break;
2124 
2125                 case T_CAPABILITY_REQ:
2126                         tilog("timodwproc: Got T_CAPABILITY_REQ\n", 0);
2127                         /*
2128                          * XXX: We may know at this point whether transport
2129                          * provides T_CAPABILITY_REQ or not and we may utilise
2130                          * this knowledge here.
2131                          */
2132                         putnext(q, mp);
2133                         break;

2134                 }
2135                 break;
2136         case M_FLUSH:
2137 
2138                 tilog("timodwproc: Got M_FLUSH\n", 0);
2139 
2140                 if (*mp->b_rptr & FLUSHW) {
2141                         if (*mp->b_rptr & FLUSHBAND)
2142                                 flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
2143                         else
2144                                 flushq(q, FLUSHDATA);
2145                 }
2146                 putnext(q, mp);
2147                 break;
2148         }
2149 
2150         return (0);
2151 }
2152 
2153 static void


2384                 cqp->cq_addr = (caddr_t)STRUCT_FGETP(sb, buf);
2385                 cqp->cq_size = STRUCT_FGET(sb, len);
2386                 cqp->cq_flag = 0;
2387                 mp->b_datap->db_type = M_COPYOUT;
2388                 mp->b_cont = bp;
2389                 STRUCT_FSET(sb, len, 0); /* copy the strbuf next time around */
2390                 qreply(q, mp);
2391                 ret = DONAME_CONT;
2392                 break;
2393 
2394         default:
2395                 tilog("ti_doname: freeing bad message type = %d\n",
2396                     mp->b_datap->db_type);
2397                 freemsg(mp);
2398                 ret = DONAME_FAIL;
2399                 break;
2400         }
2401         return (ret);
2402 }
2403 

2404 
2405 /*
2406  * Fill in the address of a connectionless data packet if a connect
2407  * had been done on this endpoint.
2408  */
2409 static mblk_t *
2410 tim_filladdr(queue_t *q, mblk_t *mp, boolean_t dorecover)
2411 {
2412         mblk_t *bp;
2413         struct tim_tim *tp;
2414         struct T_unitdata_req *up;
2415         struct T_unitdata_req *nup;
2416         size_t plen;
2417 
2418         tp = (struct tim_tim *)q->q_ptr;
2419         if (mp->b_datap->db_type == M_DATA) {
2420                 mutex_enter(&tp->tim_mutex);
2421                 bp = allocb(sizeof (struct T_unitdata_req) + tp->tim_peerlen,
2422                     BPRI_MED);
2423                 if (bp != NULL) {


2517         tim_cnt--;
2518 
2519         rw_exit(&tim_list_rwlock);
2520 }
2521 
2522 static struct tim_tim *
2523 tim_findlink(t_uscalar_t id)
2524 {
2525         struct tim_tim  *tp;
2526 
2527         ASSERT(rw_lock_held(&tim_list_rwlock));
2528 
2529         for (tp = tim_hash[TIM_HASH(id)]; tp != NULL; tp = tp->tim_next) {
2530                 if (tp->tim_acceptor == id) {
2531                         break;
2532                 }
2533         }
2534         return (tp);
2535 }
2536 

2537 static void
2538 tim_recover(queue_t *q, mblk_t *mp, t_scalar_t size)
2539 {
2540         struct tim_tim  *tp;
2541         bufcall_id_t    bid;
2542         timeout_id_t    tid;
2543 
2544         tp = (struct tim_tim *)q->q_ptr;
2545 
2546         /*
2547          * Avoid re-enabling the queue.
2548          */
2549         if (mp->b_datap->db_type == M_PCPROTO)
2550                 mp->b_datap->db_type = M_PROTO;
2551         noenable(q);
2552         (void) putbq(q, mp);
2553 
2554         /*
2555          * Make sure there is at most one outstanding request per queue.
2556          */


2627                          */
2628                         if ((bp->b_datap->db_type == M_PROTO) &&
2629                             ((bp->b_wptr - bp->b_rptr) >=
2630                             sizeof (struct T_exdata_ind)) &&
2631                             (((struct T_exdata_ind *)bp->b_rptr)->PRIM_type
2632                             == T_EXDATA_IND)) {
2633                                 /* bp is T_EXDATA_IND */
2634                                 mutex_exit(QLOCK(rq));
2635                                 releasestr(q); /* decrement sd_refcnt  */
2636                                 return (1); /* expdata is on a read queue */
2637                         }
2638                         bp = bp->b_next; /* next message */
2639                 }
2640                 mutex_exit(QLOCK(rq));
2641                 rq = rq->q_next;     /* next upstream queue */
2642         } while (rq != NULL);
2643         releasestr(q);
2644         return (0);             /* no expdata on read queues */
2645 }
2646 

2647 static void
2648 tim_tcap_timer(void *q_ptr)
2649 {
2650         queue_t *q = (queue_t *)q_ptr;
2651         struct tim_tim *tp = (struct tim_tim *)q->q_ptr;
2652 
2653         ASSERT(tp != NULL && tp->tim_tcap_timoutid != 0);
2654         ASSERT((tp->tim_flags & TI_CAP_RECVD) != 0);
2655 
2656         tp->tim_tcap_timoutid = 0;
2657         TILOG("tim_tcap_timer: fired\n", 0);
2658         tim_tcap_genreply(q, tp);
2659 }
2660 
2661 /*
2662  * tim_tcap_genreply() is called either from timeout routine or when
2663  * T_ERROR_ACK is received. In both cases it means that underlying
2664  * transport doesn't provide T_CAPABILITY_REQ.
2665  */
2666 static void