static cache_t * reclaim_cache(head_t *chp, int dev) { /* * Reclaim a cache element: * * This routine is used to: [a] free the oldest element from * the cache headed at "chp" and return the address of the * corresponding "cache_t" struct (iff dev == -1), or [b] free all * elements on the cache headed at "chp" that belong to the * indicated "dev"ice. */ cache_t *cap, *cxp; cache_t *cpp = (cache_t *)chp; while ((cap = cpp->link[Prev]) != (cache_t *)chp) { /* * We follow the cache's LRU chain from oldest to * newest member. This ensures that we remove only * the oldest element when we're called with a * negative "dev" argument. */ if ((dev == -1) || (dev == cap->dev)) { /* * This is one of the (perhaps the only) * elements we're supposed to free. Remove it * from both the LRU list and its associated * hash chain. Then free the data bound the * the cache_t element and, if "dev" is * not -1, the element itself! */ cap->link[Prev]->link[Next] = cap->link[Next]; cap->link[Next]->link[Prev] = cap->link[Prev]; if ((cxp = cap->link[Hash+Prev]) != 0) cxp->link[Hash+Next] = cap->link[Hash+Next]; else *(cap->chn) = cap->link[Hash+Next]; if ((cxp = cap->link[Hash+Next]) != 0) cxp->link[Hash+Prev] = cap->link[Hash+Prev]; bkmem_free((caddr_t)cap->data, cap->size); if (dev == -1) return (cap); bkmem_free((caddr_t)cap, chp->size); chp->count -= 1; } else { /* * Skip this element, it's not one of the * ones we want to free up. */ cpp = cap; } }; return (0); }
static int st_recv(void) { char *tmp; char *buf; int buf_len, ret; if (g_sock_fd == NO_OPENED_SOCKET) { printf("! No socket opened\n"); return (-1); } if ((tmp = strtok(NULL, " ")) == NULL) { printf("! No buffer len given\n"); return (-1); } buf_len = atoi(tmp); if ((buf = bkmem_zalloc(buf_len)) == NULL) { printf("! Cannot allocate buffer: %d\n", errno); return (-1); } if ((ret = st_local_recv(g_sock_fd, buf, buf_len, 0)) <= 0) { if (ret == 0) { printf("@ EOF received: %d\n", errno); return (0); } printf("! Cannot recv: %d\n", errno); return (-1); } printf("@ Bytes received: %d\n", ret); hexdump(buf, ret); bkmem_free(buf, buf_len); return (0); }
int set_bcache(fileid_t *fp) { /* * Insert Disk Block Cache Entry: * * In this case, we actually read the requested block into a * dynamically allocated buffer before inserting it into the * cache. If the read fails, we return a non-zero value. * * The search keys for disk blocks are the block number and * buffer size. The data associated with each entry is the * corresponding data buffer. */ bc_t *bcp; if (fp->fi_memp = bkmem_alloc(x_len = fp->fi_count)) { /* * We were able to succesffully allocate an input * buffer, now read the data into it. */ if (diskread(fp) != 0) { /* * I/O error on read. Free the input buffer, * print an error message, and bail out. */ bkmem_free(fp->fi_memp, x_len); printf("disk read error\n"); return (-1); } x_blkno = fp->fi_blocknum; x_dev = fp->fi_devp->di_dcookie; bcp = (bc_t *) set_cache(&bc_hash[BC_HASH(x_dev, x_blkno, x_len)], &bc_head, 0); bcp->bc_blk = x_blkno; bcp->bc_hdr.dev = x_dev; bcp->bc_hdr.size = x_len; bcp->bc_hdr.data = (void *)fp->fi_memp; } else { /* * We could be a bit more convervative here by * calling "set_cache" before we try to allocate a * buffer (thereby giving us a chance to re-use a * previously allocated buffer) but the error recovery * is a bit trickier, and if we're that short on memory * we'll have trouble elsewhere anyway! */ prom_panic("can't read - no memory"); } return (0); }
static int st_recvfrom(void) { char *tmp; char *buf; int buf_len, ret; struct sockaddr_in from; socklen_t fromlen; if (g_sock_fd == NO_OPENED_SOCKET) { printf("! No socket opened\n"); return (-1); } if ((tmp = strtok(NULL, " ")) == NULL) { printf("! No buffer len given\n"); return (-1); } buf_len = atoi(tmp); if ((buf = bkmem_zalloc(buf_len)) == NULL) { printf("! Cannot allocate buffer: %d\n", errno); return (-1); } fromlen = sizeof (from); if ((ret = st_local_recvfrom(g_sock_fd, buf, buf_len, 0, (struct sockaddr *)&from, &fromlen)) <= 0) { if (ret == 0) { printf("@ EOF received: %d\n", errno); return (0); } printf("! Cannot recv: %d\n", errno); return (-1); } printf("@ Bytes received from %s/%d: %d\n", inet_ntoa(from.sin_addr), ntohs(from.sin_port), ret); hexdump(buf, ret); bkmem_free(buf, buf_len); return (0); }
/* * our version of brpc_call(). We cache in portnumber in to->sin_port for * your convenience. to and from addresses are taken and received in network * order. */ enum clnt_stat brpc_call( rpcprog_t prog, /* rpc program number to call. */ rpcvers_t vers, /* rpc program version */ rpcproc_t proc, /* rpc procedure to call */ xdrproc_t in_xdr, /* routine to serialize arguments */ caddr_t args, /* arg vector for remote call */ xdrproc_t out_xdr, /* routine to deserialize results */ caddr_t ret, /* addr of buf to place results in */ int rexmit, /* retransmission interval (secs) */ int wait_time, /* how long (secs) to wait (resp) */ struct sockaddr_in *to, /* destination */ struct sockaddr_in *from_who, /* responder's port/address */ uint_t auth) /* type of auth wanted. */ { int s; char hostname[MAXHOSTNAMELEN]; struct sockaddr_in from; /* us. */ socklen_t from_len; XDR xmit_xdrs, rcv_xdrs; /* xdr memory */ AUTH *xmit_auth; /* our chosen auth cookie */ gid_t fake_gids = 1; /* fake gids list for auth_unix */ caddr_t trm_msg, rcv_msg; /* outgoing/incoming rpc mesgs */ struct rpc_msg reply; /* our reply msg header */ int trm_len, rcv_len; struct rpc_err rpc_error; /* to store RPC errors in on rcv. */ static uint_t xid; /* current xid */ uint_t xmit_len; /* How much of the buffer we used */ int nrefreshes = 2; /* # of times to refresh cred */ int flags = 0; /* send flags */ uint_t xdelay; int errors, preserve_errno; uint32_t timeout; socklen_t optlen; xmit_auth = NULL; trm_len = mac_get_mtu(); trm_msg = bkmem_alloc(trm_len); rcv_msg = bkmem_alloc(NFSBUF_SIZE); if (trm_msg == NULL || rcv_msg == NULL) { errno = ENOMEM; rpc_error.re_status = RPC_CANTSEND; goto gt_error; } if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { rpc_error.re_status = RPC_CANTSEND; goto gt_error; } if (dontroute) { (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, (const void *)&dontroute, sizeof (dontroute)); } if (to->sin_addr.s_addr == cached_destination.s_addr) { optlen = sizeof (timeout); (void) getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, &optlen); } else { cached_destination.s_addr = htonl(INADDR_ANY); } /* Bind our endpoint. */ from.sin_family = AF_INET; ipv4_getipaddr(&from.sin_addr); from.sin_addr.s_addr = htonl(from.sin_addr.s_addr); from.sin_port = get_source_port(B_TRUE); if (bind(s, (struct sockaddr *)&from, sizeof (from)) < 0) { rpc_error.re_status = RPC_CANTSEND; goto gt_error; } bzero((caddr_t)&rpc_error, sizeof (struct rpc_err)); /* initialize reply's rpc_msg struct, so we can decode later. */ reply.acpted_rply.ar_verf = _null_auth; /* struct copy */ reply.acpted_rply.ar_results.where = ret; reply.acpted_rply.ar_results.proc = out_xdr; if (ntohs(to->sin_port) == 0) { /* snag the udp port we need. */ if ((to->sin_port = (in_port_t)bpmap_getport(prog, vers, &(rpc_error.re_status), to, NULL)) == 0) goto gt_error; to->sin_port = htons(to->sin_port); } /* generate xid - increment */ if (xid == 0) xid = (uint_t)(prom_gettime() / 1000) + 1; else xid++; /* set up outgoing pkt as xdr modified. */ xdrmem_create(&xmit_xdrs, trm_msg, trm_len, XDR_ENCODE); /* setup rpc header */ if (rpc_hdr(&xmit_xdrs, xid, prog, vers, proc) != TRUE) { dprintf("brpc_call: cannot setup rpc header.\n"); rpc_error.re_status = RPC_FAILED; goto gt_error; } /* setup authentication */ switch (auth) { case AUTH_NONE: xmit_auth = authnone_create(); break; case AUTH_UNIX: /* * Assumes we've configured the stack and thus know our * IP address/hostname, either by using DHCP or rarp/bootparams. */ gethostname(hostname, sizeof (hostname)); xmit_auth = authunix_create(hostname, 0, 1, 1, &fake_gids); break; default: dprintf("brpc_call: Unsupported authentication type: %d\n", auth); rpc_error.re_status = RPC_AUTHERROR; goto gt_error; /*NOTREACHED*/ } /* * rpc_hdr puts everything in the xmit buffer for the header * EXCEPT the proc. Put it, and our authentication info into * it now, serializing as we go. We will be at the place where * we left off. */ xmit_xdrs.x_op = XDR_ENCODE; if ((XDR_PUTINT32(&xmit_xdrs, (int32_t *)&proc) == FALSE) || (AUTH_MARSHALL(xmit_auth, &xmit_xdrs, NULL) == FALSE) || ((*in_xdr)(&xmit_xdrs, args) == FALSE)) { rpc_error.re_status = RPC_CANTENCODEARGS; goto gt_error; } else xmit_len = (int)XDR_GETPOS(&xmit_xdrs); /* for sendto */ /* * Right now the outgoing packet should be all serialized and * ready to go... Set up timers. */ xdelay = (rexmit == 0) ? RPC_REXMIT_MSEC : (rexmit * 1000); (void) setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&xdelay, sizeof (xdelay)); wait_time = (wait_time == 0) ? RPC_RCVWAIT_MSEC : (wait_time * 1000); wait_time += prom_gettime(); /* * send out the request. The first item in the receive buffer will * be the xid. Check if it is correct. */ errors = 0; rpc_error.re_status = RPC_TIMEDOUT; do { if (sendto(s, trm_msg, xmit_len, flags, (struct sockaddr *)to, sizeof (struct sockaddr_in)) < 0) { /* * If errno is set to ETIMEDOUT, return * with RPC status as RPC_TIMEDOUT. Calling * funciton will take care of this error by * retrying the RPC call. */ if (errno == ETIMEDOUT) { rpc_error.re_status = RPC_TIMEDOUT; } else { rpc_error.re_status = RPC_CANTSEND; } goto gt_error; } from_len = sizeof (struct sockaddr_in); while ((rcv_len = recvfrom(s, rcv_msg, NFSBUF_SIZE, MSG_DONTWAIT, (struct sockaddr *)from_who, &from_len)) > 0 || errors < RPC_ALLOWABLE_ERRORS) { if (rcv_len < 0) { if (errno == EWOULDBLOCK || errno == ETIMEDOUT) { break; /* timeout */ } rpc_error.re_status = RPC_CANTRECV; goto gt_error; } if (ntohl(*((uint32_t *)(rcv_msg))) != xid) { dprintf("brpc_call: xid: 0x%x != 0x%x\n", *(uint32_t *)(rcv_msg), xid); continue; } /* * Let's deserialize the data into our 'ret' buffer. */ xdrmem_create(&rcv_xdrs, rcv_msg, rcv_len, XDR_DECODE); if (xdr_replymsg(&rcv_xdrs, &reply) == FALSE) { rpc_error.re_status = RPC_CANTDECODERES; goto gt_error; } _seterr_reply(&reply, &rpc_error); switch (rpc_error.re_status) { case RPC_SUCCESS: /* * XXX - validate for unix and none * always return true. */ if (AUTH_VALIDATE(xmit_auth, &reply.acpted_rply.ar_verf) == FALSE) { rpc_error.re_status = RPC_AUTHERROR; rpc_error.re_why = AUTH_INVALIDRESP; errors++; } if (reply.acpted_rply.ar_verf.oa_base != 0) { xmit_xdrs.x_op = XDR_FREE; (void) xdr_opaque_auth( &xmit_xdrs, &reply.acpted_rply.ar_verf); } break; case RPC_AUTHERROR: /* * Let's see if our credentials need * refreshing */ if (nrefreshes > 0 && AUTH_REFRESH(xmit_auth, NULL, NULL)) { nrefreshes--; } errors++; break; case RPC_PROCUNAVAIL: /* * Might be a silly portmapper implementation * erroneously responding to our rpc broadcast * indirect portmapper call. For this * particular case, we don't increment the * error counter because we want to keep * sifting for successful replies... */ if (to->sin_addr.s_addr != ntohl(INADDR_BROADCAST)) errors++; break; case RPC_PROGVERSMISMATCH: /* * Successfully talked to server, but they * don't speak our lingo. */ goto gt_error; default: /* Just keep trying till there's no data... */ errors++; break; } if (rpc_error.re_status != RPC_SUCCESS) { dprintf("brpc_call: from: %s, error: ", inet_ntoa(from_who->sin_addr)); rpc_disperr(&rpc_error); } else break; } /* * If we're having trouble reassembling datagrams, let the * application know ASAP so that it can take the appropriate * actions. */ } while (rpc_error.re_status != RPC_SUCCESS && errno != ETIMEDOUT && prom_gettime() < wait_time); gt_error: if (xmit_auth != NULL) AUTH_DESTROY(xmit_auth); if (trm_msg != NULL) bkmem_free(trm_msg, trm_len); if (rcv_msg != NULL) bkmem_free(rcv_msg, NFSBUF_SIZE); if (rpc_error.re_status != RPC_SUCCESS) rpc_disperr(&rpc_error); /* * socket calls reset errno. Since we want to hold onto the errno * value if it is ETIMEDOUT to communicate to our caller that this * RPC_TIMEDOUT situation is due to a stack problem (we're getting * a reply, but the stack simply can't assemble it.), we need to * preserve errno's value over the socket_close(). */ preserve_errno = (errno == ETIMEDOUT) ? errno : 0; (void) socket_close(s); errno = preserve_errno; return (rpc_error.re_status); }
/* * To act as an echo server. Note that it assumes the address and * netmask have been set. */ static int st_echo(void) { char *tmp; int listen_fd, newfd; int echo_port; struct sockaddr_in addr; socklen_t addr_size; int backlog = 20; char *buf; int buf_len, ret, snd_cnt; tmp = strtok(NULL, " "); if (tmp == NULL) { printf("! No echo port given\n"); return (-1); } echo_port = atoi(tmp); tmp = strtok(NULL, " "); if (tmp == NULL) { printf("! No buffer size given\n"); return (-1); } buf_len = atoi(tmp); /* Create local socket for echo server */ if ((listen_fd = st_local_socket(AF_INET, SOCK_STREAM, 0)) < 0) { printf("! Error in opening TCP socket: %d\n", errno); return (-1); } else { printf("@ Local TCP socket opened\n"); } /* Bind local socket */ addr.sin_family = AF_INET; addr.sin_port = htons(echo_port); addr.sin_addr.s_addr = INADDR_ANY; if (st_local_bind(listen_fd, (struct sockaddr *)&addr, sizeof (addr)) < 0) { printf("! Bind failed: %d\n", errno); return (-1); } if (st_local_listen(listen_fd, backlog) < 0) { printf("! Listen failed: %d\n", errno); return (-1); } addr_size = sizeof (addr); if ((newfd = st_local_accept(listen_fd, (struct sockaddr *)&addr, &addr_size)) < 0) { printf("! Accept failed: %d\n", errno); (void) st_local_socket_close(listen_fd); return (-1); } printf("@ Accepted connection: %s/%d\n", inet_ntoa(addr.sin_addr), ntohs(addr.sin_port)); (void) st_local_socket_close(listen_fd); if ((buf = bkmem_zalloc(buf_len)) == NULL) { printf("! Cannot allocate buffer: %d\n", errno); (void) st_local_socket_close(newfd); return (-1); } while ((ret = st_local_recv(newfd, buf, buf_len, 0)) > 0) { printf("@ Bytes received: %d\n", ret); hexdump(buf, ret); if ((snd_cnt = st_local_send(newfd, buf, ret, 0)) < ret) { printf("! Send failed: %d\n", errno); bkmem_free(buf, buf_len); return (-1); } printf("@ Sent %d bytes\n", snd_cnt); } (void) st_local_socket_close(newfd); if (ret < 0) { printf("! Cannot recv: %d\n", errno); bkmem_free(buf, buf_len); return (-1); } else { return (0); } }
/* * Handle a IP datagram addressed to our MAC address or to the link * layer broadcast address. Also respond to ARP requests. Generates * inetgrams as long as there's data and the mac level IP timeout timer * hasn't expired. As soon as there is no data, we try for * IBD_INPUT_ATTEMPTS for more, then exit the loop, even if there is time * left, since we expect to have data waiting for us when we're called, we just * don't know how much. * * We workaround slow proms (some proms have hard sleeps for as much as 3msec) * even though there are is data waiting. * * Returns the total number of MEDIA_LVL frames placed on the socket. * Caller is expected to free up the inetgram resources. */ static int ibd_input(int index) { struct inetgram *inp; ipoib_ptxhdr_t *eh; int frames = 0; /* successful frames */ int attempts = 0; /* failed attempts after success */ int16_t len = 0, data_len; uint32_t timeout, reltime; uint32_t pre_pr, post_pr; /* prom_read interval */ #ifdef DEBUG int failures = 0; /* total failures */ int total_attempts = 0; /* total prom_read */ int no_data = 0; /* no data in prom */ int arps = 0; /* arp requests processed */ uint32_t tot_pr = 0; /* prom_read time */ uint32_t tot_pc = 0; /* inetgram creation time */ uint32_t pre_pc; uint32_t now; #endif /* DEBUG */ if (!initialized) prom_panic("IPoIB device is not initialized."); if ((reltime = sockets[index].in_timeout) == 0) reltime = mac_state.mac_in_timeout; timeout = prom_gettime() + reltime; do { if (frames > IBD_MAX_FRAMES) { /* someone is trying a denial of service attack */ break; } /* * The following is being paranoid about possible bugs * where prom_read() returns a nonzero length, even when * it's not read a packet; it zeroes out the header to * compensate. Paranoia from calvin prom (V2) days. */ bzero(mac_state.mac_buf, sizeof (ipoib_ptxhdr_t)); /* * Prom_read() will return 0 or -2 if no data is present. A * return value of -1 means an error has occurred. We adjust * the timeout by calling the time spent in prom_read() "free". * prom_read() returns the number of bytes actually read, but * will only copy "len" bytes into our buffer. Adjust in * case the MTU is wrong. */ pre_pr = prom_gettime(); len = prom_read(mac_state.mac_dev, mac_state.mac_buf, mac_state.mac_mtu, 0, NETWORK); post_pr = prom_gettime(); timeout += (post_pr - pre_pr); #ifdef DEBUG tot_pr += (post_pr - pre_pr); total_attempts++; #endif /* DEBUG */ if (len > mac_state.mac_mtu) { dprintf("ibd_input: adjusting MTU %d -> %d\n", mac_state.mac_mtu, len); bkmem_free(mac_state.mac_buf, mac_state.mac_mtu); mac_state.mac_mtu = len; mac_state.mac_buf = bkmem_alloc(mac_state.mac_mtu); if (mac_state.mac_buf == NULL) { prom_panic("ibd_input: Cannot reallocate " "netbuf memory."); } len = 0; /* pretend there was no data */ } if (len == -1) { #ifdef DEBUG failures++; #endif /* DEBUG */ break; } if (len == 0 || len == -2) { if (frames != 0) attempts++; #ifdef DEBUG no_data++; #endif /* DEBUG */ continue; } eh = (ipoib_ptxhdr_t *)mac_state.mac_buf; if (eh->ipoib_rhdr.ipoib_type == ntohs(ETHERTYPE_IP) && len >= (sizeof (ipoib_ptxhdr_t) + sizeof (struct ip))) { int offset; #ifdef DEBUG pre_pc = prom_gettime(); #endif /* DEBUG */ inp = (struct inetgram *)bkmem_zalloc( sizeof (struct inetgram)); if (inp == NULL) { errno = ENOMEM; return (frames == 0 ? -1 : frames); } offset = sizeof (ipoib_ptxhdr_t); data_len = len - offset; inp->igm_mp = allocb(data_len, 0); if (inp->igm_mp == NULL) { errno = ENOMEM; bkmem_free((caddr_t)inp, sizeof (struct inetgram)); return (frames == 0 ? -1 : frames); } bcopy((caddr_t)(mac_state.mac_buf + offset), inp->igm_mp->b_rptr, data_len); inp->igm_mp->b_wptr += data_len; inp->igm_level = NETWORK_LVL; add_grams(&sockets[index].inq, inp); frames++; attempts = 0; #ifdef DEBUG tot_pc += prom_gettime() - pre_pc; #endif /* DEBUG */ continue; } if (eh->ipoib_rhdr.ipoib_type == ntohs(ETHERTYPE_ARP) && len >= sizeof (struct arp_packet)) { struct in_addr ip; struct ibd_arp *ea; #ifdef DEBUG printf("ibd_input: ARP message received\n"); arps++; #endif /* DEBUG */ ea = (struct ibd_arp *)(mac_state.mac_buf + sizeof (ipoib_ptxhdr_t)); if (ea->arp_pro != ntohs(ETHERTYPE_IP)) continue; ipv4_getipaddr(&ip); ip.s_addr = ntohl(ip.s_addr); if (ea->arp_op == ntohs(ARPOP_REQUEST) && ip.s_addr != INADDR_ANY && (bcmp((caddr_t)ea->arp_tpa, (caddr_t)&ip, sizeof (struct in_addr)) == 0)) { ea->arp_op = htons(ARPOP_REPLY); bcopy((caddr_t)&ea->arp_sha, (caddr_t)&eh->ipoib_dest, IPOIB_ADDRL); bcopy((caddr_t)&ea->arp_sha, (caddr_t)&ea->arp_tha, IPOIB_ADDRL); bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, sizeof (struct in_addr)); bcopy(mac_state.mac_addr_buf, (caddr_t)&ea->arp_sha, mac_state.mac_addr_len); bcopy((caddr_t)&ip, (caddr_t)ea->arp_spa, sizeof (struct in_addr)); (void) prom_write(mac_state.mac_dev, mac_state.mac_buf, sizeof (struct arp_packet), 0, NETWORK); /* don't charge for ARP replies */ timeout += reltime; } } } while (attempts < IBD_INPUT_ATTEMPTS && #ifdef DEBUG (now = prom_gettime()) < timeout); #else prom_gettime() < timeout); #endif /* DEBUG */ #ifdef DEBUG printf("ibd_input(%d): T/S/N/A/F/P/M: %d/%d/%d/%d/%d/%d/%d " "T/O: %d < %d = %s\n", index, total_attempts, frames, no_data, arps, failures, tot_pr, tot_pc, now, timeout, (now < timeout) ? "TRUE" : "FALSE"); #endif /* DEBUG */ return (frames); }
static void memlist_free(struct memlist *buf) { bkmem_free(buf, sizeof (struct memlist)); }