1*8041Sroot /* uipc_socket.c 4.49 82/09/04 */ 24786Swnj 34786Swnj #include "../h/param.h" 44829Swnj #include "../h/systm.h" 54786Swnj #include "../h/dir.h" 64786Swnj #include "../h/user.h" 74829Swnj #include "../h/proc.h" 84829Swnj #include "../h/file.h" 94786Swnj #include "../h/inode.h" 104829Swnj #include "../h/buf.h" 114786Swnj #include "../h/mbuf.h" 124829Swnj #include "../h/protosw.h" 134829Swnj #include "../h/socket.h" 144829Swnj #include "../h/socketvar.h" 154916Swnj #include "../h/stat.h" 165281Sroot #include "../h/ioctl.h" 175095Swnj #include "../net/in.h" 185095Swnj #include "../net/in_systm.h" 196355Ssam #include "../net/route.h" 207747Sroot #include "../h/uio.h" 214786Swnj 224786Swnj /* 234890Swnj * Socket support routines. 244890Swnj * 254890Swnj * DEAL WITH INTERRUPT NOTIFICATION. 264786Swnj */ 274786Swnj 284786Swnj /* 294786Swnj * Create a socket. 304786Swnj */ 314927Swnj socreate(aso, type, asp, asa, options) 324786Swnj struct socket **aso; 334786Swnj int type; 344927Swnj struct sockproto *asp; 354927Swnj struct sockaddr *asa; 364829Swnj int options; 374786Swnj { 384786Swnj register struct protosw *prp; 394786Swnj register struct socket *so; 404786Swnj struct mbuf *m; 414890Swnj int pf, proto, error; 424786Swnj 434786Swnj /* 444890Swnj * Use process standard protocol/protocol family if none 454890Swnj * specified by address argument. 464786Swnj */ 474927Swnj if (asp == 0) { 484890Swnj pf = PF_INET; /* should be u.u_protof */ 494786Swnj proto = 0; 504786Swnj } else { 514927Swnj pf = asp->sp_family; 524927Swnj proto = asp->sp_protocol; 534786Swnj } 544786Swnj 554786Swnj /* 564890Swnj * If protocol specified, look for it, otherwise 574890Swnj * for a protocol of the correct type in the right family. 584890Swnj */ 594890Swnj if (proto) 604890Swnj prp = pffindproto(pf, proto); 614890Swnj else 624890Swnj prp = pffindtype(pf, type); 634890Swnj if (prp == 0) 644890Swnj return (EPROTONOSUPPORT); 654890Swnj 664890Swnj /* 674786Swnj * Get a socket structure. 684786Swnj */ 694890Swnj m = m_getclr(M_WAIT); 704786Swnj if (m == 0) 714786Swnj return (ENOBUFS); 724786Swnj so = mtod(m, struct socket *); 734829Swnj so->so_options = options; 747507Sroot if (options & SO_ACCEPTCONN) { 757507Sroot so->so_q = so; 767507Sroot so->so_q0 = so; 777507Sroot so->so_qlimit = (so->so_options & SO_NEWFDONCONN) ? 5 : 1; 787507Sroot } 796214Swnj so->so_state = 0; 806214Swnj if (u.u_uid == 0) 816214Swnj so->so_state = SS_PRIV; 824786Swnj 834786Swnj /* 844890Swnj * Attach protocol to socket, initializing 854890Swnj * and reserving resources. 864786Swnj */ 874786Swnj so->so_proto = prp; 884979Swnj error = (*prp->pr_usrreq)(so, PRU_ATTACH, 0, asa); 894979Swnj if (error) { 907507Sroot so->so_state |= SS_NOFDREF; 917180Swnj sofree(so); 924890Swnj return (error); 934786Swnj } 944786Swnj *aso = so; 954786Swnj return (0); 964786Swnj } 974786Swnj 984916Swnj sofree(so) 994916Swnj struct socket *so; 1004916Swnj { 1014916Swnj 1027507Sroot if (so->so_head) { 1037507Sroot if (!soqremque(so, 0) && !soqremque(so, 1)) 1047507Sroot panic("sofree dq"); 1057507Sroot so->so_head = 0; 1067507Sroot } 1077507Sroot if (so->so_pcb || (so->so_state & SS_NOFDREF) == 0) 1084950Swnj return; 1094950Swnj sbrelease(&so->so_snd); 1104950Swnj sbrelease(&so->so_rcv); 1114971Swnj (void) m_free(dtom(so)); 1124916Swnj } 1134916Swnj 1144786Swnj /* 1154890Swnj * Close a socket on last file table reference removal. 1164890Swnj * Initiate disconnect if connected. 1174890Swnj * Free socket when disconnect complete. 1184829Swnj */ 1195580Sroot soclose(so, exiting) 1204829Swnj register struct socket *so; 1215580Sroot int exiting; 1224829Swnj { 1234890Swnj int s = splnet(); /* conservative */ 1244829Swnj 1257507Sroot if (so->so_options & SO_ACCEPTCONN) { 1267507Sroot while (so->so_q0 != so) 1277507Sroot soclose(so->so_q0, 1); 1287507Sroot while (so->so_q != so) 1297507Sroot soclose(so->so_q, 1); 1307507Sroot } 1314890Swnj if (so->so_pcb == 0) 1324890Swnj goto discard; 1336259Sroot if (exiting) 1346259Sroot so->so_options |= SO_KEEPALIVE; 1354890Swnj if (so->so_state & SS_ISCONNECTED) { 1364890Swnj if ((so->so_state & SS_ISDISCONNECTING) == 0) { 1374927Swnj u.u_error = sodisconnect(so, (struct sockaddr *)0); 1384890Swnj if (u.u_error) { 1395580Sroot if (exiting) 1405580Sroot goto drop; 1414890Swnj splx(s); 1424890Swnj return; 1434890Swnj } 1444890Swnj } 1455388Sroot if ((so->so_options & SO_DONTLINGER) == 0) { 1465281Sroot if ((so->so_state & SS_ISDISCONNECTING) && 1476214Swnj (so->so_state & SS_NBIO) && 1485580Sroot exiting == 0) { 1495281Sroot u.u_error = EINPROGRESS; 1505281Sroot splx(s); 1515281Sroot return; 1525281Sroot } 1535580Sroot /* should use tsleep here, for at most linger */ 1545281Sroot while (so->so_state & SS_ISCONNECTED) 1555281Sroot sleep((caddr_t)&so->so_timeo, PZERO+1); 1564890Swnj } 1574890Swnj } 1585580Sroot drop: 1596880Ssam if (so->so_pcb) { 1606880Ssam u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_DETACH, 0, 0); 1616880Ssam if (exiting == 0 && u.u_error) { 1626880Ssam splx(s); 1636880Ssam return; 1646880Ssam } 1656880Ssam } 1664890Swnj discard: 1677507Sroot so->so_state |= SS_NOFDREF; 1684950Swnj sofree(so); 1694890Swnj splx(s); 1704829Swnj } 1714829Swnj 1724916Swnj /*ARGSUSED*/ 1734890Swnj sostat(so, sb) 1744829Swnj struct socket *so; 1754890Swnj struct stat *sb; 1764829Swnj { 1774829Swnj 1785303Sroot bzero((caddr_t)sb, sizeof (*sb)); /* XXX */ 1795303Sroot return (0); /* XXX */ 1804829Swnj } 1814829Swnj 1824829Swnj /* 1834927Swnj * Accept connection on a socket. 1844927Swnj */ 1854927Swnj soaccept(so, asa) 1864927Swnj struct socket *so; 1874927Swnj struct sockaddr *asa; 1884927Swnj { 1894927Swnj int s = splnet(); 1904927Swnj int error; 1914927Swnj 1924927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_ACCEPT, 0, (caddr_t)asa); 1934927Swnj splx(s); 1944927Swnj return (error); 1954927Swnj } 1964927Swnj 1974927Swnj /* 1984890Swnj * Connect socket to a specified address. 1994890Swnj * If already connected or connecting, then avoid 2004890Swnj * the protocol entry, to keep its job simpler. 2014786Swnj */ 2024927Swnj soconnect(so, asa) 2034786Swnj struct socket *so; 2044927Swnj struct sockaddr *asa; 2054786Swnj { 2064890Swnj int s = splnet(); 2074890Swnj int error; 2084786Swnj 2094890Swnj if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING)) { 2104890Swnj error = EISCONN; 2114890Swnj goto bad; 2124890Swnj } 2134927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_CONNECT, 0, (caddr_t)asa); 2144890Swnj bad: 2154890Swnj splx(s); 2164890Swnj return (error); 2174786Swnj } 2184786Swnj 2194786Swnj /* 2204890Swnj * Disconnect from a socket. 2214890Swnj * Address parameter is from system call for later multicast 2224890Swnj * protocols. Check to make sure that connected and no disconnect 2234890Swnj * in progress (for protocol's sake), and then invoke protocol. 2244786Swnj */ 2254927Swnj sodisconnect(so, asa) 2264786Swnj struct socket *so; 2274927Swnj struct sockaddr *asa; 2284786Swnj { 2294890Swnj int s = splnet(); 2304890Swnj int error; 2314786Swnj 2324890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2334890Swnj error = ENOTCONN; 2344890Swnj goto bad; 2354890Swnj } 2364890Swnj if (so->so_state & SS_ISDISCONNECTING) { 2374890Swnj error = EALREADY; 2384890Swnj goto bad; 2394890Swnj } 2404927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_DISCONNECT, 0, asa); 2414890Swnj bad: 2424890Swnj splx(s); 2434890Swnj return (error); 2444786Swnj } 2454786Swnj 2464786Swnj /* 2474890Swnj * Send on a socket. 2484890Swnj * If send must go all at once and message is larger than 2494890Swnj * send buffering, then hard error. 2504890Swnj * Lock against other senders. 2514890Swnj * If must go all at once and not enough room now, then 2524890Swnj * inform user that this would block and do nothing. 2534786Swnj */ 2547827Sroot sosend(so, asa, uio) 2554786Swnj register struct socket *so; 2564927Swnj struct sockaddr *asa; 2577827Sroot struct uio *uio; 2584786Swnj { 2594890Swnj struct mbuf *top = 0; 2604890Swnj register struct mbuf *m, **mp = ⊤ 2614916Swnj register u_int len; 2624916Swnj int error = 0, space, s; 2634786Swnj 2647827Sroot if (sosendallatonce(so) && uio->uio_resid > so->so_snd.sb_hiwat) 2654890Swnj return (EMSGSIZE); 2666419Sroot #ifdef notdef 2676419Sroot /* NEED TO PREVENT BUSY WAITING IN SELECT FOR WRITING */ 2686214Swnj if ((so->so_snd.sb_flags & SB_LOCK) && (so->so_state & SS_NBIO)) 2694890Swnj return (EWOULDBLOCK); 2706419Sroot #endif 2716419Sroot restart: 2724890Swnj sblock(&so->so_snd); 2734890Swnj #define snderr(errno) { error = errno; splx(s); goto release; } 2744890Swnj 275*8041Sroot u.u_ru.ru_msgsnd++; 2766419Sroot again: 2774890Swnj s = splnet(); 2786419Sroot if (so->so_state & SS_CANTSENDMORE) { 2796419Sroot psignal(u.u_procp, SIGPIPE); 2806419Sroot snderr(EPIPE); 2816419Sroot } 2825168Swnj if (so->so_error) { 2835168Swnj error = so->so_error; 2846419Sroot so->so_error = 0; /* ??? */ 2855168Swnj splx(s); 2865168Swnj goto release; 2875168Swnj } 2884890Swnj if ((so->so_state & SS_ISCONNECTED) == 0) { 2894890Swnj if (so->so_proto->pr_flags & PR_CONNREQUIRED) 2904890Swnj snderr(ENOTCONN); 2914927Swnj if (asa == 0) 2924890Swnj snderr(EDESTADDRREQ); 2934890Swnj } 2944890Swnj if (top) { 2954927Swnj error = (*so->so_proto->pr_usrreq)(so, PRU_SEND, top, asa); 2966419Sroot top = 0; 2974890Swnj if (error) { 2984890Swnj splx(s); 2994786Swnj goto release; 3004786Swnj } 3014890Swnj mp = ⊤ 3024786Swnj } 3037827Sroot if (uio->uio_resid == 0) { 3044979Swnj splx(s); 3054979Swnj goto release; 3064979Swnj } 3075018Swnj space = sbspace(&so->so_snd); 3087827Sroot if (space <= 0 || sosendallatonce(so) && space < uio->uio_resid) { 3096214Swnj if (so->so_state & SS_NBIO) 3104890Swnj snderr(EWOULDBLOCK); 3114890Swnj sbunlock(&so->so_snd); 3124890Swnj sbwait(&so->so_snd); 3134890Swnj splx(s); 3146419Sroot goto restart; 3154786Swnj } 3164890Swnj splx(s); 3177827Sroot while (uio->uio_resid > 0 && space > 0) { 3187827Sroot register struct iovec *iov = uio->uio_iov; 3197827Sroot 3207827Sroot if (iov->iov_len == 0) { 3217827Sroot uio->uio_iov++; 3227827Sroot uio->uio_iovcnt--; 3237827Sroot if (uio->uio_iovcnt < 0) 3247827Sroot panic("sosend"); 3257827Sroot continue; 3267827Sroot } 3274890Swnj MGET(m, 1); 3284890Swnj if (m == NULL) { 3296419Sroot error = ENOBUFS; /* SIGPIPE? */ 3304890Swnj goto release; 3314786Swnj } 3327827Sroot if (iov->iov_len >= CLBYTES && space >= CLBYTES) { 3334890Swnj register struct mbuf *p; 3345095Swnj MCLGET(p, 1); 3354890Swnj if (p == 0) 3364890Swnj goto nopages; 3374890Swnj m->m_off = (int)p - (int)m; 3385095Swnj len = CLBYTES; 3394890Swnj } else { 3404786Swnj nopages: 3414890Swnj m->m_off = MMINOFF; 3427827Sroot len = MIN(MLEN, iov->iov_len); 3434786Swnj } 3447827Sroot uiomove(mtod(m, caddr_t), len, UIO_WRITE, uio); 3454890Swnj m->m_len = len; 3464890Swnj *mp = m; 3474890Swnj mp = &m->m_next; 3485018Swnj space = sbspace(&so->so_snd); 3494786Swnj } 3504890Swnj goto again; 3514890Swnj 3524786Swnj release: 3534890Swnj sbunlock(&so->so_snd); 3546419Sroot if (top) 3556419Sroot m_freem(top); 3564786Swnj return (error); 3574786Swnj } 3584786Swnj 3597747Sroot soreceive(so, asa, uio) 3604786Swnj register struct socket *so; 3614927Swnj struct sockaddr *asa; 3627747Sroot struct uio *uio; 3634786Swnj { 3647747Sroot register struct iovec *iov; 3654786Swnj register struct mbuf *m, *n; 3664916Swnj u_int len; 3677827Sroot int eor, s, error = 0; 3684786Swnj 3694890Swnj restart: 3704890Swnj sblock(&so->so_rcv); 3714890Swnj s = splnet(); 3724890Swnj 3734890Swnj #define rcverr(errno) { error = errno; splx(s); goto release; } 3744786Swnj if (so->so_rcv.sb_cc == 0) { 3755168Swnj if (so->so_error) { 3765168Swnj error = so->so_error; 3775168Swnj so->so_error = 0; 3785168Swnj splx(s); 3795168Swnj goto release; 3805168Swnj } 3814890Swnj if (so->so_state & SS_CANTRCVMORE) { 3824890Swnj splx(s); 3834890Swnj goto release; 3844890Swnj } 3855015Sroot if ((so->so_state & SS_ISCONNECTED) == 0 && 3865015Sroot (so->so_proto->pr_flags & PR_CONNREQUIRED)) 3875015Sroot rcverr(ENOTCONN); 3886214Swnj if (so->so_state & SS_NBIO) 3895168Swnj rcverr(EWOULDBLOCK); 3904890Swnj sbunlock(&so->so_rcv); 3914971Swnj sbwait(&so->so_rcv); 3925012Swnj splx(s); 3934890Swnj goto restart; 3944786Swnj } 395*8041Sroot u.u_ru.ru_msgrcv++; 3964829Swnj m = so->so_rcv.sb_mb; 3974786Swnj if (m == 0) 3984786Swnj panic("receive"); 3995039Swnj if (so->so_proto->pr_flags & PR_ADDR) { 4005039Swnj if (m->m_len != sizeof (struct sockaddr)) 4015039Swnj panic("soreceive addr"); 4025039Swnj if (asa) 4035039Swnj bcopy(mtod(m, caddr_t), (caddr_t)asa, sizeof (*asa)); 4045039Swnj so->so_rcv.sb_cc -= m->m_len; 4055039Swnj so->so_rcv.sb_mbcnt -= MSIZE; 4065018Swnj m = m_free(m); 4074890Swnj if (m == 0) 4084890Swnj panic("receive 2"); 4095018Swnj so->so_rcv.sb_mb = m; 4104890Swnj } 4114786Swnj eor = 0; 4124786Swnj do { 4137827Sroot if (uio->uio_resid <= 0) 4147747Sroot break; 4157827Sroot len = uio->uio_resid; 4167747Sroot so->so_state &= ~SS_RCVATMARK; 4177747Sroot if (so->so_oobmark && len > so->so_oobmark) 4187747Sroot len = so->so_oobmark; 4197747Sroot if (len > m->m_len) 4207747Sroot len = m->m_len; 4214786Swnj splx(s); 4227827Sroot uiomove(mtod(m, caddr_t), (int)len, UIO_READ, uio); 4234786Swnj s = splnet(); 4244786Swnj if (len == m->m_len) { 4256091Sroot eor = (int)m->m_act; 4266091Sroot sbfree(&so->so_rcv, m); 4276091Sroot so->so_rcv.sb_mb = m->m_next; 4284786Swnj MFREE(m, n); 4294786Swnj } else { 4304786Swnj m->m_off += len; 4314786Swnj m->m_len -= len; 4324829Swnj so->so_rcv.sb_cc -= len; 4334786Swnj } 4347747Sroot if (so->so_oobmark) { 4357747Sroot so->so_oobmark -= len; 4367747Sroot if (so->so_oobmark == 0) { 4377747Sroot so->so_state |= SS_RCVATMARK; 4387747Sroot break; 4397747Sroot } 4407747Sroot } 4417747Sroot } while ((m = so->so_rcv.sb_mb) && !eor); 4424786Swnj if ((so->so_proto->pr_flags & PR_ATOMIC) && eor == 0) 4434786Swnj do { 4444786Swnj if (m == 0) 4454890Swnj panic("receive 3"); 4464890Swnj sbfree(&so->so_rcv, m); 4474786Swnj eor = (int)m->m_act; 4484786Swnj so->so_rcv.sb_mb = m->m_next; 4494786Swnj MFREE(m, n); 4504890Swnj m = n; 4514786Swnj } while (eor == 0); 4524890Swnj if ((so->so_proto->pr_flags & PR_WANTRCVD) && so->so_pcb) 4534890Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVD, 0, 0); 4544890Swnj release: 4554916Swnj sbunlock(&so->so_rcv); 4564890Swnj splx(s); 4574916Swnj return (error); 4584786Swnj } 4594786Swnj 4605423Swnj sohasoutofband(so) 4615423Swnj struct socket *so; 4625423Swnj { 4635423Swnj 4645423Swnj if (so->so_pgrp == 0) 4655423Swnj return; 4665423Swnj if (so->so_pgrp > 0) 4675423Swnj gsignal(so->so_pgrp, SIGURG); 4685429Swnj else { 4695429Swnj struct proc *p = pfind(-so->so_pgrp); 4705429Swnj 4715429Swnj if (p) 4725429Swnj psignal(p, SIGURG); 4735429Swnj } 4745423Swnj } 4755423Swnj 4764916Swnj /*ARGSUSED*/ 4777627Ssam soioctl(so, cmd, data) 4784829Swnj register struct socket *so; 4794829Swnj int cmd; 4807627Ssam register char *data; 4814786Swnj { 4824786Swnj 4835358Sroot switch (cmd) { 4844829Swnj 4857627Ssam case FIONBIO: 4867627Ssam if (*(int *)data) 4876214Swnj so->so_state |= SS_NBIO; 4885388Sroot else 4896214Swnj so->so_state &= ~SS_NBIO; 4905388Sroot return; 4915388Sroot 4927627Ssam case FIOASYNC: 4937627Ssam if (*(int *)data) 4946214Swnj so->so_state |= SS_ASYNC; 4955388Sroot else 4966214Swnj so->so_state &= ~SS_ASYNC; 4975388Sroot return; 4985388Sroot 4997627Ssam case SIOCSKEEP: 5007627Ssam if (*(int *)data) 5017507Sroot so->so_options &= ~SO_KEEPALIVE; 5027507Sroot else 5037491Ssam so->so_options |= SO_KEEPALIVE; 5045388Sroot return; 5055388Sroot 5067627Ssam case SIOCGKEEP: 5077627Ssam *(int *)data = (so->so_options & SO_KEEPALIVE) != 0; 5085388Sroot return; 5095388Sroot 5107627Ssam case SIOCSLINGER: 5117627Ssam so->so_linger = *(int *)data; 5125388Sroot if (so->so_linger) 5135388Sroot so->so_options &= ~SO_DONTLINGER; 5145388Sroot else 5155388Sroot so->so_options |= SO_DONTLINGER; 5165388Sroot return; 5175388Sroot 5187627Ssam case SIOCGLINGER: 5197627Ssam *(int *)data = so->so_linger; 5205423Swnj return; 5215388Sroot 5227627Ssam case SIOCSPGRP: 5237627Ssam so->so_pgrp = *(int *)data; 5247627Ssam return; 5255423Swnj 5267627Ssam case SIOCGPGRP: 5277627Ssam *(int *)data = so->so_pgrp; 5287627Ssam return; 5297627Ssam 5305281Sroot case SIOCDONE: { 5317627Ssam int flags = *(int *)data; 5327627Ssam 5335388Sroot flags++; 5345281Sroot if (flags & FREAD) { 5355281Sroot int s = splimp(); 5365281Sroot socantrcvmore(so); 5375281Sroot sbflush(&so->so_rcv); 5386140Ssam splx(s); 5395281Sroot } 5405281Sroot if (flags & FWRITE) 5415404Swnj u.u_error = (*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN, (struct mbuf *)0, 0); 5425281Sroot return; 5434829Swnj } 5445281Sroot 5455423Swnj case SIOCSENDOOB: { 5467627Ssam char oob = *(char *)data; 5475423Swnj struct mbuf *m; 5487627Ssam 5495423Swnj m = m_get(M_DONTWAIT); 5505423Swnj if (m == 0) { 5515423Swnj u.u_error = ENOBUFS; 5525423Swnj return; 5535423Swnj } 5545423Swnj m->m_off = MMINOFF; 5557627Ssam m->m_len = sizeof (char); 5567627Ssam *mtod(m, char *) = oob; 5575423Swnj (*so->so_proto->pr_usrreq)(so, PRU_SENDOOB, m, 0); 5585423Swnj return; 5595281Sroot } 5605423Swnj 5615423Swnj case SIOCRCVOOB: { 5625423Swnj struct mbuf *m = m_get(M_DONTWAIT); 5637627Ssam 5645423Swnj if (m == 0) { 5655423Swnj u.u_error = ENOBUFS; 5665423Swnj return; 5675423Swnj } 5685423Swnj m->m_off = MMINOFF; *mtod(m, caddr_t) = 0; 5695423Swnj (*so->so_proto->pr_usrreq)(so, PRU_RCVOOB, m, 0); 5707627Ssam *(char *)data = *mtod(m, char *); 5717627Ssam (void) m_free(m); 5725423Swnj return; 5735423Swnj } 5745423Swnj 5757627Ssam case SIOCATMARK: 5767627Ssam *(int *)data = (so->so_state&SS_RCVATMARK) != 0; 5775423Swnj return; 5786355Ssam 5796355Ssam /* routing table update calls */ 5806355Ssam case SIOCADDRT: 5816355Ssam case SIOCDELRT: 5826355Ssam if (!suser()) 5836355Ssam return; 5847627Ssam u.u_error = rtrequest(cmd, (struct rtentry *)data); 5856355Ssam return; 5866355Ssam 5875445Swnj /* type/protocol specific ioctls */ 5885423Swnj } 5895445Swnj u.u_error = EOPNOTSUPP; 5904786Swnj } 591