+ register struct rawcb *rp = sotorawcb(so);
+ register int error = 0;
+
+ 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);
+ 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;
+ }
+ if (rp->rcb_route.ro_rt)
+ rtfree(rp->rcb_route.ro_rt);
+ 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;
+ }
+ /*
+ * Check for routing. If new foreign address, or
+ * no route presently in use, try to allocate new
+ * route. On failure, just hand packet to output
+ * routine anyway in case it can handle it.
+ */
+ if ((rp->rcb_flags & RAW_DONTROUTE) == 0)
+ if (!equal(rp->rcb_faddr, rp->rcb_route.ro_dst) ||
+ rp->rcb_route.ro_rt == 0) {
+ if (rp->rcb_route.ro_rt)
+ rtfree(rp->rcb_route.ro_rt);
+ rp->rcb_route.ro_dst = rp->rcb_faddr;
+ rtalloc(&rp->rcb_route);
+ }
+ 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_CONTROL:
+ m = NULL;
+ error = EOPNOTSUPP;
+ break;
+
+ /*
+ * Not supported.
+ */
+ case PRU_ACCEPT:
+ case PRU_RCVD:
+ case PRU_SENSE:
+ case PRU_RCVOOB:
+ 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;