+ stat = in_pcballoc(&pcbinfo->nat_dummy_socket, pcbinfo, p);
+ if (stat)
+ panic("in_pcb_nat_init: can't alloc fakepcb err=%\n", stat);
+ pcbinfo->nat_dummy_pcb = pcbinfo->nat_dummy_socket.so_pcb;
+}
+
+/* Mechanism used to defer the memory release of PCBs
+ * The pcb list will contain the pcb until the ripper can clean it up if
+ * the following conditions are met: 1) state "DEAD", 2) wantcnt is STOPUSING
+ * 3) usecount is null
+ * This function will be called to either mark the pcb as
+*/
+int
+in_pcb_checkstate(struct inpcb *pcb, int mode, int locked)
+
+{
+
+ volatile UInt32 *wantcnt = (volatile UInt32 *)&pcb->inp_wantcnt;
+ UInt32 origwant;
+ UInt32 newwant;
+
+ switch (mode) {
+
+ case WNT_STOPUSING: /* try to mark the pcb as ready for recycling */
+
+ /* compareswap with STOPUSING, if success we're good, if it's in use, will be marked later */
+
+ if (locked == 0)
+ socket_lock(pcb->inp_socket, 1);
+ pcb->inp_state = INPCB_STATE_DEAD;
+stopusing:
+ if (pcb->inp_socket->so_usecount < 0)
+ panic("in_pcb_checkstate STOP pcb=%x so=%x usecount is negative\n", pcb, pcb->inp_socket);
+ if (locked == 0)
+ socket_unlock(pcb->inp_socket, 1);
+
+ origwant = *wantcnt;
+ if ((UInt16) origwant == 0xffff ) /* should stop using */
+ return (WNT_STOPUSING);
+ newwant = 0xffff;
+ if ((UInt16) origwant == 0) {/* try to mark it as unsuable now */
+ OSCompareAndSwap(origwant, newwant, (UInt32 *) wantcnt) ;
+ }
+ return (WNT_STOPUSING);
+ break;
+
+ case WNT_ACQUIRE: /* try to increase reference to pcb */
+ /* if WNT_STOPUSING should bail out */
+ /*
+ * if socket state DEAD, try to set count to STOPUSING, return failed
+ * otherwise increase cnt
+ */
+ do {
+ origwant = *wantcnt;
+ if ((UInt16) origwant == 0xffff ) {/* should stop using */
+// printf("in_pcb_checkstate: ACQ PCB was STOPUSING while release. odd pcb=%x\n", pcb);
+ return (WNT_STOPUSING);
+ }
+ newwant = origwant + 1;
+ } while (!OSCompareAndSwap(origwant, newwant, (UInt32 *) wantcnt));
+ return (WNT_ACQUIRE);
+ break;
+
+ case WNT_RELEASE: /* release reference. if result is null and pcb state is DEAD,
+ set wanted bit to STOPUSING
+ */
+
+ if (locked == 0)
+ socket_lock(pcb->inp_socket, 1);
+
+ do {
+ origwant = *wantcnt;
+ if ((UInt16) origwant == 0x0 )
+ panic("in_pcb_checkstate pcb=%x release with zero count", pcb);
+ if ((UInt16) origwant == 0xffff ) {/* should stop using */
+#if TEMPDEBUG
+ printf("in_pcb_checkstate: REL PCB was STOPUSING while release. odd pcb=%x\n", pcb);
+#endif
+ if (locked == 0)
+ socket_unlock(pcb->inp_socket, 1);
+ return (WNT_STOPUSING);
+ }
+ newwant = origwant - 1;
+ } while (!OSCompareAndSwap(origwant, newwant, (UInt32 *) wantcnt));
+
+ if (pcb->inp_state == INPCB_STATE_DEAD)
+ goto stopusing;
+ if (pcb->inp_socket->so_usecount < 0)
+ panic("in_pcb_checkstate RELEASE pcb=%x so=%x usecount is negative\n", pcb, pcb->inp_socket);
+
+ if (locked == 0)
+ socket_unlock(pcb->inp_socket, 1);
+ return (WNT_RELEASE);
+ break;
+
+ default:
+
+ panic("in_pcb_checkstate: so=%x not a valid state =%x\n", pcb->inp_socket, mode);
+ }
+
+ /* NOTREACHED */
+ return (mode);