long netifread(struct netif *nif, struct chan *c, void *a, long n, uint32_t offset) { int i, j; struct netfile *f; char *p; if (c->qid.type & QTDIR) return devdirread(c, a, n, (struct dirtab *)nif, 0, netifgen); switch (NETTYPE(c->qid.path)) { case Ndataqid: f = nif->f[NETID(c->qid.path)]; return qread(f->in, a, n); case Nctlqid: return readnum(offset, a, n, NETID(c->qid.path), NUMSIZE); case Nstatqid: p = kzmalloc(READSTR, 0); if (p == NULL) return 0; j = snprintf(p, READSTR, "in: %d\n", nif->inpackets); j += snprintf(p + j, READSTR - j, "link: %d\n", nif->link); j += snprintf(p + j, READSTR - j, "out: %d\n", nif->outpackets); j += snprintf(p + j, READSTR - j, "crc errs: %d\n", nif->crcs); j += snprintf(p + j, READSTR - j, "overflows: %d\n", nif->overflows); j += snprintf(p + j, READSTR - j, "soft overflows: %d\n", nif->soverflows); j += snprintf(p + j, READSTR - j, "framing errs: %d\n", nif->frames); j += snprintf(p + j, READSTR - j, "buffer errs: %d\n", nif->buffs); j += snprintf(p + j, READSTR - j, "output errs: %d\n", nif->oerrs); j += snprintf(p + j, READSTR - j, "prom: %d\n", nif->prom); j += snprintf(p + j, READSTR - j, "mbps: %d\n", nif->mbps); j += snprintf(p + j, READSTR - j, "addr: "); for (i = 0; i < nif->alen; i++) j += snprintf(p + j, READSTR - j, "%02.2x", nif->addr[i]); snprintf(p + j, READSTR - j, "\n"); n = readstr(offset, a, n, p); kfree(p); return n; case Naddrqid: p = kzmalloc(READSTR, 0); if (p == NULL) return 0; j = 0; for (i = 0; i < nif->alen; i++) j += snprintf(p + j, READSTR - j, "%02.2x", nif->addr[i]); n = readstr(offset, a, n, p); kfree(p); return n; case Ntypeqid: f = nif->f[NETID(c->qid.path)]; return readnum(offset, a, n, f->type, NUMSIZE); case Nifstatqid: return 0; } error(Ebadarg); return -1; /* not reached */ }
void ipifcinit(struct Fs *f) { struct Proto *ipifc; ipifc = kzmalloc(sizeof(struct Proto), 0); ipifc->name = "ipifc"; ipifc->connect = ipifcconnect; ipifc->announce = NULL; ipifc->bind = ipifcbind; ipifc->state = ipifcstate; ipifc->create = ipifccreate; ipifc->close = ipifcclose; ipifc->rcv = NULL; ipifc->ctl = ipifcctl; ipifc->advise = NULL; ipifc->stats = ipifcstats; ipifc->inuse = ipifcinuse; ipifc->local = ipifclocal; ipifc->ipproto = -1; ipifc->nc = Maxmedia; ipifc->ptclsize = sizeof(struct Ipifc); f->ipifc = ipifc; /* hack for ipifcremroute, findipifc, ... */ f->self = kzmalloc(sizeof(struct Ipselftab), 0); /* hack for ipforme */ qlock_init(&f->self->qlock); Fsproto(f, ipifc); }
/* * add to self routing cache * called with c locked */ static void addselfcache(struct Fs *f, struct Ipifc *ifc, struct Iplifc *lifc, uint8_t * a, int type) { struct Ipself *p; struct Iplink *lp; int h; qlock(&f->self->qlock); /* see if the address already exists */ h = hashipa(a); for (p = f->self->hash[h]; p; p = p->next) if (memcmp(a, p->a, IPaddrlen) == 0) break; /* allocate a local address and add to hash chain */ if (p == NULL) { p = kzmalloc(sizeof(*p), 0); ipmove(p->a, a); p->type = type; p->next = f->self->hash[h]; f->self->hash[h] = p; /* if the null address, accept all packets */ if (ipcmp(a, v4prefix) == 0 || ipcmp(a, IPnoaddr) == 0) f->self->acceptall = 1; } /* look for a link for this lifc */ for (lp = p->link; lp; lp = lp->selflink) if (lp->lifc == lifc) break; /* allocate a lifc-to-local link and link to both */ if (lp == NULL) { lp = kzmalloc(sizeof(*lp), 0); kref_init(&lp->ref, fake_release, 1); lp->lifc = lifc; lp->self = p; lp->selflink = p->link; p->link = lp; lp->lifclink = lifc->link; lifc->link = lp; /* add to routing table */ if (isv4(a)) v4addroute(f, tifc, a + IPv4off, IPallbits + IPv4off, a + IPv4off, type); else v6addroute(f, tifc, a, IPallbits, a, type); if ((type & Rmulti) && ifc->m->addmulti != NULL) (*ifc->m->addmulti) (ifc, a, lifc->local); } else { kref_get(&lp->ref, 1); } qunlock(&f->self->qlock); }
struct cname *newcname(char *s) { struct cname *n; int i; n = kzmalloc(sizeof(*n), 0); i = strlen(s); n->len = i; n->alen = i + CNAMESLOP; n->s = kzmalloc(n->alen, 0); memmove(n->s, s, i + 1); kref_init(&n->ref, __cname_release, 1); return n; }
static int growfd(struct fgrp *f, int fd) { int n; struct chan **nfd, **ofd; if (fd < f->nfd) { return 0; } /* want to grow by a reasonable amount (delta), but also make sure we can * handle the fd we're asked for */ n = MAX(f->nfd, fd + 1) + DELTAFD; if (n > MAXNFD) n = MAXNFD; if (fd >= n) { set_errno(EMFILE); set_errstr("Asked for FD %d, more than %d\n", fd, MAXNFD); return -1; } nfd = kzmalloc(n * sizeof(struct chan *), 0); if (nfd == NULL) { set_errno(ENOMEM); set_errstr("Failed to growfd for FD %d, OOM\n", fd); return -1; } ofd = f->fd; memmove(nfd, ofd, f->nfd * sizeof(struct chan *)); f->fd = nfd; f->nfd = n; kfree(ofd); return 0; }
STATIC int fat_open(filesystem *fs, const char *path, fs_handle *out, int fl, mode_t mode) { fat_fs_device_data *d = (fat_fs_device_data *) fs->device_data; fat_entry *e = fat_search_entry(d->hdr, d->type, path); if (!e) return -ENOENT; /* file not found */ fat_file_handle *h = kzmalloc(sizeof(fat_file_handle)); if (!h) return -ENOMEM; h->fs = fs; h->fops.read = fat_read; h->fops.seek = fat_seek; h->fops.stat = fat_stat64; h->fops.write = NULL; h->fops.exlock = fat_file_exlock; h->fops.exunlock = fat_file_exunlock; h->fops.shlock = fat_file_shlock; h->fops.shunlock = fat_file_shunlock; h->e = e; h->pos = 0; h->curr_cluster = fat_get_first_cluster(e); *out = h; return 0; }
static struct route *allocroute(int type) { struct route *r; int n; struct route **l; if (type & Rv4) { n = sizeof(struct RouteTree) + sizeof(struct V4route); l = &v4freelist; } else { n = sizeof(struct RouteTree) + sizeof(struct V6route); l = &v6freelist; } r = *l; if (r != NULL) { *l = r->rt.mid; } else { r = kzmalloc(n, 0); if (r == NULL) panic("out of routing nodes"); } memset(r, 0, n); r->rt.type = type; r->rt.ifc = NULL; kref_init(&r->rt.kref, fake_release, 1); return r; }
static int rootwstat(struct chan *c, uint8_t *m_buf, int m_buf_sz) { struct dirtab *file = &roottab[c->qid.path]; struct dir *dir; int m_sz; /* TODO: some security check, Eperm on error */ /* common trick in wstats. we want the dir and any strings in the M. the * strings are smaller than entire M (strings plus other M). the strings * will be placed right after the dir (dir[1]) */ dir = kzmalloc(sizeof(struct dir) + m_buf_sz, KMALLOC_WAIT); m_sz = convM2D(m_buf, m_buf_sz, &dir[0], (char*)&dir[1]); if (!m_sz) { kfree(dir); error(ENODATA, ERROR_FIXME); } /* TODO: handle more things than just the mode */ if (!emptystr(dir->name)) printk("[%s] attempted rename of %s to %s\n", __FUNCTION__, file->name, dir->name); /* strncpy for this btw */ if (dir->mode != ~0UL) file->perm = dir->mode | (file->qid.type == QTDIR ? DMDIR : 0); kfree(dir); return m_sz; }
/* * parse a command written to a device */ struct cmdbuf *parsecmd(char *p, int n) { ERRSTACK(1); struct cmdbuf *volatile cb; int nf; char *sp; nf = ncmdfield(p, n); /* allocate Cmdbuf plus string pointers plus copy of string including \0 */ sp = kzmalloc(sizeof(*cb) + nf * sizeof(char *) + n + 1, 0); cb = (struct cmdbuf *)sp; cb->f = (char **)(&cb[1]); cb->buf = (char *)(&cb->f[nf]); if (current != NULL && waserror()) { kfree(cb); nexterror(); } memmove(cb->buf, p, n); if (current != NULL) poperror(); /* dump new line and null terminate */ if (n > 0 && cb->buf[n - 1] == '\n') n--; cb->buf[n] = '\0'; cb->nf = tokenize(cb->buf, cb->f, nf - 1); cb->f[cb->nf] = NULL; return cb; }
int netifwstat(struct ether *nif, struct chan *c, uint8_t * db, int n) { struct dir *dir; struct netfile *f; int m; f = nif->f[NETID(c->qid.path)]; if (f == 0) { set_errno(ENOENT); error(Enonexist); } if (netown(f, current->user, OWRITE) < 0) error(Eperm); dir = kzmalloc(sizeof(struct dir) + n, 0); m = convM2D(db, n, &dir[0], (char *)&dir[1]); if (m == 0) { kfree(dir); error(Eshortstat); } if (!emptystr(dir[0].uid)) strncpy(f->owner, dir[0].uid, KNAMELEN); if (dir[0].mode != ~0UL) f->mode = dir[0].mode; kfree(dir); return m; }
static int pipewstat(struct chan *c, uint8_t *dp, int n) { ERRSTACK(2); struct dir *d; Pipe *p; int d1; if (c->qid.type & QTDIR) error(EPERM, ERROR_FIXME); p = c->aux; if (strcmp(current->user, p->user) != 0) error(EPERM, ERROR_FIXME); d = kzmalloc(sizeof(*d) + n, 0); if (waserror()) { kfree(d); nexterror(); } n = convM2D(dp, n, d, (char *)&d[1]); if (n == 0) error(ENODATA, ERROR_FIXME); d1 = NETTYPE(c->qid.path) == Qdata1; if (!emptystr(d->name)) { validwstatname(d->name); if (strlen(d->name) >= KNAMELEN) error(ENAMETOOLONG, ERROR_FIXME); if (strncmp(p->pipedir[1 + !d1].name, d->name, KNAMELEN) == 0) error(EEXIST, ERROR_FIXME); strncpy(p->pipedir[1 + d1].name, d->name, KNAMELEN); } if (d->mode != ~0UL) p->pipedir[d1 + 1].perm = d->mode & 0777; poperror(); kfree(d); return n; }
/* add a capability, throwing out any old ones */ static void addcap(uint8_t *hash) { struct Caphash *p, *t, **l; p = kzmalloc(sizeof(*p), 0); memmove(p->hash, hash, Hashlen); p->next = NULL; qlock(&capalloc.qlock); /* trim extras */ while (capalloc.nhash >= Maxhash) { t = capalloc.first; if (t == NULL) panic("addcap"); capalloc.first = t->next; kfree(t); capalloc.nhash--; } /* add new one */ for (l = &capalloc.first; *l != NULL; l = &(*l)->next) ; *l = p; capalloc.nhash++; qunlock(&capalloc.qlock); }
void netloginit(struct Fs *f) { f->alog = kzmalloc(sizeof(struct Netlog), 0); spinlock_init(&f->alog->lock); qlock_init(&f->alog->qlock); rendez_init(&f->alog->r); }
long devtabread(struct chan *c, void *buf, long n, int64_t off) { ERRSTACK(1); int i; struct dev *dev; char *alloc, *e, *p; alloc = kzmalloc(READSTR, KMALLOC_WAIT); if (alloc == NULL) error(ENOMEM, NULL); p = alloc; e = p + READSTR; for (i = 0; &devtab[i] < __devtabend; i++) { dev = &devtab[i]; printd("p %p e %p e-p %d\n", p, e, e - p); printd("do %d %s\n", i, dev->name); p += snprintf(p, e - p, "#%s\n", dev->name); } if (waserror()) { kfree(alloc); nexterror(); } n = readstr(off, buf, n, alloc); kfree(alloc); poperror(); return n; }
char *ipifcaddpref6(struct Ipifc *ifc, char **argv, int argc) { uint8_t onlink = 1; uint8_t autoflag = 1; uint64_t validlt = UINT64_MAX; uint64_t preflt = UINT64_MAX; uint64_t origint = NOW / 10 ^ 3; uint8_t prefix[IPaddrlen]; int plen = 64; struct Iplifc *lifc; char addr[40], preflen[6]; char *params[3]; switch (argc) { case 7: preflt = atoi(argv[6]); /* fall through */ case 6: validlt = atoi(argv[5]); /* fall through */ case 5: autoflag = atoi(argv[4]); /* fall through */ case 4: onlink = atoi(argv[3]); /* fall through */ case 3: plen = atoi(argv[2]); case 2: break; default: return Ebadarg; } if ((parseip(prefix, argv[1]) != 6) || (validlt < preflt) || (plen < 0) || (plen > 64) || (islinklocal(prefix)) ) return Ebadarg; lifc = kzmalloc(sizeof(struct Iplifc), 0); lifc->onlink = (onlink != 0); lifc->autoflag = (autoflag != 0); lifc->validlt = validlt; lifc->preflt = preflt; lifc->origint = origint; if (ifc->m->pref2addr != NULL) ifc->m->pref2addr(prefix, ifc->mac); else return Ebadarg; snprintf(addr, sizeof(addr), "%I", prefix); snprintf(preflen, sizeof(preflen), "/%d", plen); params[0] = "add"; params[1] = addr; params[2] = preflen; return ipifcadd(ifc, params, 3, 0, lifc); }
static struct perfmon_status *perfmon_alloc_status(void) { struct perfmon_status *pef = kzmalloc(sizeof(struct perfmon_status) + num_cores * sizeof(uint64_t), KMALLOC_WAIT); return pef; }
/* * create a pipe, no streams are created until an open */ static struct chan *pipeattach(char *spec) { ERRSTACK(2); Pipe *p; struct chan *c; c = devattach(devname(), spec); p = kzmalloc(sizeof(Pipe), 0); if (p == 0) error(ENOMEM, ERROR_FIXME); if (waserror()) { freepipe(p); nexterror(); } p->pipedir = kzmalloc(sizeof(pipedir), 0); if (p->pipedir == 0) error(ENOMEM, ERROR_FIXME); memmove(p->pipedir, pipedir, sizeof(pipedir)); kstrdup(&p->user, current->user); kref_init(&p->ref, pipe_release, 1); qlock_init(&p->qlock); p->q[0] = qopen(pipealloc.pipeqsize, Qcoalesce, 0, 0); if (p->q[0] == 0) error(ENOMEM, ERROR_FIXME); p->q[1] = qopen(pipealloc.pipeqsize, Qcoalesce, 0, 0); if (p->q[1] == 0) error(ENOMEM, ERROR_FIXME); poperror(); spin_lock(&(&pipealloc)->lock); p->path = ++pipealloc.path; spin_unlock(&(&pipealloc)->lock); c->qid.path = NETQID(2 * p->path, Qdir); c->qid.vers = 0; c->qid.type = QTDIR; c->aux = p; c->dev = 0; /* taps. */ SLIST_INIT(&p->data_taps[0]); /* already = 0; set to be futureproof */ SLIST_INIT(&p->data_taps[1]); spinlock_init(&p->tap_lock); return c; }
/* * keep track of multicast addresses */ static char *netmulti(struct ether *nif, struct netfile *f, uint8_t * addr, int add) { struct netaddr **l, *ap; int i; uint32_t h; if (nif->multicast == NULL) return "interface does not support multicast"; l = &nif->maddr; i = 0; for (ap = *l; ap; ap = *l) { if (memcmp(addr, ap->addr, nif->alen) == 0) break; i++; l = &ap->next; } if (add) { if (ap == 0) { /* TODO: AFAIK, this never gets freed. if we fix that, we can use a * kref too (instead of int ap->ref). */ *l = ap = kzmalloc(sizeof(*ap), 0); memmove(ap->addr, addr, nif->alen); ap->next = 0; ap->ref = 1; h = hash(addr, nif->alen); ap->hnext = nif->mhash[h]; nif->mhash[h] = ap; } else { ap->ref++; } if (ap->ref == 1) { nif->nmaddr++; nif->multicast(nif->arg, addr, 1); } if (i < 8 * sizeof(f->maddr)) { if ((f->maddr[i / 8] & (1 << (i % 8))) == 0) f->nmaddr++; f->maddr[i / 8] |= 1 << (i % 8); } } else { if (ap == 0 || ap->ref == 0) return 0; ap->ref--; if (ap->ref == 0) { nif->nmaddr--; nif->multicast(nif->arg, addr, 0); } if (i < 8 * sizeof(f->maddr)) { if ((f->maddr[i / 8] & (1 << (i % 8))) != 0) f->nmaddr--; f->maddr[i / 8] &= ~(1 << (i % 8)); } } return 0; }
/* * Atomically replace *p with copy of s */ void kstrdup(char **p, char *s) { int n; char *t, *prev; n = strlen(s) + 1; /* if it's a user, we can wait for memory; if not, something's very wrong */ if (current) { t = kzmalloc(n, 0); } else { t = kzmalloc(n, 0); if (t == NULL) panic("kstrdup: no memory"); } memmove(t, s, n); prev = *p; *p = t; kfree(prev); }
struct perfmon_session *perfmon_create_session(void) { struct perfmon_session *ps = kzmalloc(sizeof(struct perfmon_session), KMALLOC_WAIT); kref_init(&ps->ref, perfmon_release_session, 1); spinlock_init(&ps->lock); return ps; }
void arpinit(struct Fs *f) { f->arp = kzmalloc(sizeof(struct arp), MEM_WAIT); qlock_init(&f->arp->qlock); rendez_init(&f->arp->rxmtq); f->arp->f = f; f->arp->rxmt = NULL; f->arp->dropf = f->arp->dropl = NULL; ktask("rxmitproc", rxmitproc, f->arp); }
/* * Increment the reference count of a network device. * If id < 0, return an unused ether device. */ static int openfile(struct ether *nif, int id) { ERRSTACK(1); struct netfile *f, **fp, **efp; if (id >= 0) { f = nif->f[id]; if (f == 0) error(Enodev); qlock(&f->qlock); qreopen(f->in); f->inuse++; qunlock(&f->qlock); return id; } qlock(&nif->qlock); if (waserror()) { qunlock(&nif->qlock); nexterror(); } efp = &nif->f[nif->nfile]; for (fp = nif->f; fp < efp; fp++) { f = *fp; if (f == 0) { f = kzmalloc(sizeof(struct netfile), 0); if (f == 0) exhausted("memory"); /* since we lock before netifinit (if we ever call that...) */ qlock_init(&f->qlock); f->in = qopen(nif->limit, Qmsg, 0, 0); if (f->in == NULL) { kfree(f); exhausted("memory"); } *fp = f; qlock(&f->qlock); } else { qlock(&f->qlock); if (f->inuse) { qunlock(&f->qlock); continue; } } f->inuse = 1; qreopen(f->in); netown(f, current->user, 0); qunlock(&f->qlock); qunlock(&nif->qlock); poperror(); return fp - nif->f; } error(Enodev); return -1; /* not reached */ }
/* * set up a new network interface */ void netifinit(struct ether *nif, char *name, int nfile, uint32_t limit) { qlock_init(&nif->qlock); strlcpy(nif->name, name, KNAMELEN); nif->nfile = nfile; nif->f = kzmalloc(nfile * sizeof(struct netfile *), 0); if (nif->f) memset(nif->f, 0, nfile * sizeof(struct netfile *)); else nif->nfile = 0; nif->limit = limit; }
void udpinit(struct Fs *fs) { struct Proto *udp; udp = kzmalloc(sizeof(struct Proto), 0); udp->priv = kzmalloc(sizeof(Udppriv), 0); udp->name = "udp"; udp->connect = udpconnect; udp->announce = udpannounce; udp->ctl = udpctl; udp->state = udpstate; udp->create = udpcreate; udp->close = udpclose; udp->rcv = udpiput; udp->advise = udpadvise; udp->stats = udpstats; udp->ipproto = IP_UDPPROTO; udp->nc = Nchans; udp->newconv = udpnewconv; udp->ptclsize = sizeof(Udpcb); Fsproto(fs, udp); }
static struct perfmon_alloc *perfmon_create_alloc(const struct perfmon_event *pev) { int i; struct perfmon_alloc *pa = kzmalloc(sizeof(struct perfmon_alloc) + num_cores * sizeof(counter_t), KMALLOC_WAIT); kref_init(&pa->ref, perfmon_release_alloc, 1); pa->ev = *pev; for (i = 0; i < num_cores; i++) pa->cores_counters[i] = INVALID_COUNTER; return pa; }
static void loopbackbind(struct Ipifc *ifc, int unused_int, char **unused_char_pp_t) { LB *lb; lb = kzmalloc(sizeof(*lb), 0); lb->f = ifc->conv->p->f; /* TO DO: make queue size a function of kernel memory */ lb->q = qopen(128 * 1024, Qmsg, NULL, NULL); ifc->arg = lb; ifc->mbps = 1000; ktask("loopbackread", loopbackread, ifc); }
/* Initializes a process to run virtual machine contexts, returning the number * initialized, optionally setting errno */ int vmm_struct_init(struct proc *p, unsigned int nr_guest_pcores, struct vmm_gpcore_init *u_gpcis, int flags) { struct vmm *vmm = &p->vmm; unsigned int i; struct vmm_gpcore_init gpci; if (flags & ~VMM_ALL_FLAGS) { set_errstr("%s: flags is 0x%lx, VMM_ALL_FLAGS is 0x%lx\n", __func__, flags, VMM_ALL_FLAGS); set_errno(EINVAL); return 0; } vmm->flags = flags; if (!x86_supports_vmx) { set_errno(ENODEV); return 0; } qlock(&vmm->qlock); if (vmm->vmmcp) { set_errno(EINVAL); qunlock(&vmm->qlock); return 0; } /* Set this early, so cleanup checks the gpc array */ vmm->vmmcp = TRUE; nr_guest_pcores = MIN(nr_guest_pcores, num_cores); vmm->amd = 0; vmm->guest_pcores = kzmalloc(sizeof(void*) * nr_guest_pcores, KMALLOC_WAIT); for (i = 0; i < nr_guest_pcores; i++) { if (copy_from_user(&gpci, &u_gpcis[i], sizeof(struct vmm_gpcore_init))) { set_error(EINVAL, "Bad pointer %p for gps", u_gpcis); break; } vmm->guest_pcores[i] = create_guest_pcore(p, &gpci); /* If we failed, we'll clean it up when the process dies */ if (!vmm->guest_pcores[i]) { set_errno(ENOMEM); break; } } vmm->nr_guest_pcores = i; for (int i = 0; i < VMM_VMEXIT_NR_TYPES; i++) vmm->vmexits[i] = 0; qunlock(&vmm->qlock); return i; }
/* open a queue to be bypassed */ struct queue *qbypass(void (*bypass) (void *, struct block *), void *arg) { struct queue *q; q = kzmalloc(sizeof(struct queue), 0); if (q == 0) return 0; qinit_common(q); q->limit = 0; q->arg = arg; q->bypass = bypass; q->state = 0; return q; }
struct chan *devattach(int tc, char *spec) { struct chan *c; char *buf; c = newchan(); mkqid(&c->qid, 0, 0, QTDIR); c->type = devno(tc, 0); if (spec == NULL) spec = ""; /* 2 for #c, 1 for \0 */ buf = kzmalloc(2 + strlen(spec) + 1, KMALLOC_WAIT); snprintf(buf, sizeof(buf), "#%c%s", tc, spec); c->name = newcname(buf); kfree(buf); return c; }
/* * called by non-interrupt code */ struct queue *qopen(int limit, int msg, void (*kick) (void *), void *arg) { struct queue *q; q = kzmalloc(sizeof(struct queue), 0); if (q == 0) return 0; qinit_common(q); q->limit = q->inilim = limit; q->kick = kick; q->arg = arg; q->state = msg; q->state |= Qstarve; q->eof = 0; return q; }