+ register struct rawcb *rp = sotorawcb(so);
+ register int error = 0;
+
+ if (req == PRU_CONTROL)
+ return (EOPNOTSUPP);
+ if (rights && rights->m_len) {
+ error = EOPNOTSUPP;
+ goto release;
+ }
+ if (rp == 0 && req != PRU_ATTACH) {
+ error = EINVAL;
+ goto release;
+ }
+ switch (req) {
+
+ /*
+ * Allocate a raw control block and fill in the
+ * necessary info to allow packets to be routed to
+ * the appropriate raw interface routine.
+ */
+ case PRU_ATTACH:
+ if ((so->so_state & SS_PRIV) == 0) {
+ error = EACCES;
+ break;
+ }
+ if (rp) {
+ error = EINVAL;
+ break;
+ }
+ error = raw_attach(so, (int)nam);
+ break;
+
+ /*
+ * Destroy state just before socket deallocation.
+ * Flush data or not depending on the options.
+ */
+ case PRU_DETACH:
+ if (rp == 0) {
+ error = ENOTCONN;
+ break;
+ }
+ raw_detach(rp);
+ break;
+
+ /*
+ * If a socket isn't bound to a single address,
+ * the raw input routine will hand it anything
+ * within that protocol family (assuming there's
+ * nothing else around it should go to).
+ */
+ case PRU_CONNECT:
+ if (rp->rcb_flags & RAW_FADDR) {
+ error = EISCONN;
+ break;
+ }
+ raw_connaddr(rp, nam);
+ soisconnected(so);
+ break;
+
+ case PRU_CONNECT2:
+ error = EOPNOTSUPP;
+ goto release;
+
+ case PRU_BIND:
+ if (rp->rcb_flags & RAW_LADDR) {
+ error = EINVAL; /* XXX */
+ break;
+ }
+ error = raw_bind(so, nam);
+ break;
+
+ case PRU_DISCONNECT:
+ if ((rp->rcb_flags & RAW_FADDR) == 0) {
+ error = ENOTCONN;
+ break;
+ }
+ raw_disconnect(rp);
+ soisdisconnected(so);
+ break;
+
+ /*
+ * Mark the connection as being incapable of further input.
+ */
+ case PRU_SHUTDOWN:
+ socantsendmore(so);
+ break;
+
+ /*
+ * Ship a packet out. The appropriate raw output
+ * routine handles any massaging necessary.
+ */
+ case PRU_SEND:
+ if (nam) {
+ if (rp->rcb_flags & RAW_FADDR) {
+ error = EISCONN;
+ break;
+ }
+ raw_connaddr(rp, nam);
+ } else if ((rp->rcb_flags & RAW_FADDR) == 0) {
+ error = ENOTCONN;
+ break;
+ }
+ error = (*so->so_proto->pr_output)(m, so);
+ m = NULL;
+ if (nam)
+ rp->rcb_flags &= ~RAW_FADDR;
+ break;
+
+ case PRU_ABORT:
+ raw_disconnect(rp);
+ sofree(so);
+ soisdisconnected(so);
+ break;
+
+ case PRU_SENSE:
+ /*
+ * stat: don't bother with a blocksize.
+ */
+ return (0);
+
+ /*
+ * Not supported.
+ */
+ case PRU_RCVOOB:
+ case PRU_RCVD:
+ return(EOPNOTSUPP);
+
+ case PRU_LISTEN:
+ case PRU_ACCEPT:
+ case PRU_SENDOOB:
+ error = EOPNOTSUPP;
+ break;
+
+ case PRU_SOCKADDR:
+ bcopy((caddr_t)&rp->rcb_laddr, mtod(nam, caddr_t),
+ sizeof (struct sockaddr));
+ nam->m_len = sizeof (struct sockaddr);
+ break;