+soshutdown(so, how)
+ struct socket *so;
+ int how;
+{
+
+ how++;
+ if (how & FREAD) {
+ int s = splimp();
+ socantrcvmore(so);
+ sbflush(&so->so_rcv);
+ splx(s);
+ }
+ if (how & FWRITE)
+ return ((*so->so_proto->pr_usrreq)(so, PRU_SHUTDOWN,
+ (struct mbuf *)0, (struct mbuf *)0));
+ return (0);
+}
+
+sosetopt(so, level, optname, m)
+ struct socket *so;
+ int level, optname;
+ struct mbuf *m;
+{
+
+ if (level != SOL_SOCKET)
+ return (EINVAL); /* XXX */
+ switch (optname) {
+
+ case SO_DEBUG:
+ case SO_KEEPALIVE:
+ case SO_DONTROUTE:
+ case SO_USELOOPBACK:
+ case SO_REUSEADDR:
+ so->so_options |= optname;
+ break;
+
+ case SO_LINGER:
+ if (m == NULL || m->m_len != sizeof (int))
+ return (EINVAL);
+ so->so_options |= SO_LINGER;
+ so->so_linger = *mtod(m, int *);
+ break;
+
+ case SO_DONTLINGER:
+ so->so_options &= ~SO_LINGER;
+ so->so_linger = 0;
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+
+sogetopt(so, level, optname, m)
+ struct socket *so;
+ int level, optname;
+ struct mbuf *m;
+{
+
+ if (level != SOL_SOCKET)
+ return (EINVAL); /* XXX */
+ switch (optname) {
+
+ case SO_USELOOPBACK:
+ case SO_DONTROUTE:
+ case SO_DEBUG:
+ case SO_KEEPALIVE:
+ case SO_LINGER:
+ case SO_REUSEADDR:
+ if ((so->so_options & optname) == 0)
+ return (ENOPROTOOPT);
+ if (optname == SO_LINGER && m != NULL) {
+ *mtod(m, int *) = so->so_linger;
+ m->m_len = sizeof (so->so_linger);
+ }
+ break;
+
+ default:
+ return (EINVAL);
+ }
+ return (0);
+}
+