/* * Get a netgraph message */ static ssize_t ng_MessageIn(struct physical *p, char *buf, size_t sz) { char msgbuf[sizeof(struct ng_mesg) * 2 + NG_MSGBUFSZ]; struct ngdevice *dev = device2ng(p->handler); struct ng_mesg *rep = (struct ng_mesg *)msgbuf; char path[NG_PATHSIZ]; size_t len; #ifdef BROKEN_SELECT struct timeval t; fd_set *r; int ret; if (dev->cs < 0) return 0; if ((r = mkfdset()) == NULL) { log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); return -1; } zerofdset(r); FD_SET(dev->cs, r); t.tv_sec = t.tv_usec = 0; ret = select(dev->cs + 1, r, NULL, NULL, &t); free(r); if (ret <= 0) return 0; #endif if (NgRecvAsciiMsg(dev->cs, rep, sizeof msgbuf, path)) { log_Printf(LogWARN, "%s: NgRecvAsciiMsg: %s\n", dev->dev.name, strerror(errno)); return -1; } /* XXX: Should we check rep->header.version ? */ if (sz == 0) log_Printf(LogWARN, "%s: Unexpected message: %s\n", dev->dev.name, rep->header.cmdstr); else { log_Printf(LogDEBUG, "%s: Received message: %s\n", dev->dev.name, rep->header.cmdstr); len = strlen(rep->header.cmdstr); if (sz > len) sz = len; memcpy(buf, rep->header.cmdstr, sz); } return sz; }
static void DoLoop(struct bundle *bundle) { fd_set *rfds, *wfds, *efds; int i, nfds, nothing_done; if ((rfds = mkfdset()) == NULL) { log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); return; } if ((wfds = mkfdset()) == NULL) { log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); free(rfds); return; } if ((efds = mkfdset()) == NULL) { log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); free(rfds); free(wfds); return; } for (; !bundle_IsDead(bundle); bundle_CleanDatalinks(bundle)) { nfds = 0; zerofdset(rfds); zerofdset(wfds); zerofdset(efds); /* All our datalinks, the tun device and the MP socket */ descriptor_UpdateSet(&bundle->desc, rfds, wfds, efds, &nfds); /* All our prompts and the diagnostic socket */ descriptor_UpdateSet(&server.desc, rfds, NULL, NULL, &nfds); bundle_CleanDatalinks(bundle); if (bundle_IsDead(bundle)) /* Don't select - we'll be here forever */ break; /* * It's possible that we've had a signal since we last checked. If * we don't check again before calling select(), we may end up stuck * after having missed the event.... sig_Handle() tries to be as * quick as possible if nothing is likely to have happened. * This is only really likely if we block in open(... O_NONBLOCK) * which will happen with a misconfigured device. */ if (sig_Handle()) continue; i = select(nfds, rfds, wfds, efds, NULL); if (i < 0 && errno != EINTR) { log_Printf(LogERROR, "DoLoop: select(): %s\n", strerror(errno)); if (log_IsKept(LogTIMER)) { struct timeval t; for (i = 0; i <= nfds; i++) { if (FD_ISSET(i, rfds)) { log_Printf(LogTIMER, "Read set contains %d\n", i); FD_CLR(i, rfds); t.tv_sec = t.tv_usec = 0; if (select(nfds, rfds, wfds, efds, &t) != -1) { log_Printf(LogTIMER, "The culprit !\n"); break; } } if (FD_ISSET(i, wfds)) { log_Printf(LogTIMER, "Write set contains %d\n", i); FD_CLR(i, wfds); t.tv_sec = t.tv_usec = 0; if (select(nfds, rfds, wfds, efds, &t) != -1) { log_Printf(LogTIMER, "The culprit !\n"); break; } } if (FD_ISSET(i, efds)) { log_Printf(LogTIMER, "Error set contains %d\n", i); FD_CLR(i, efds); t.tv_sec = t.tv_usec = 0; if (select(nfds, rfds, wfds, efds, &t) != -1) { log_Printf(LogTIMER, "The culprit !\n"); break; } } } } break; } log_Printf(LogTIMER, "Select returns %d\n", i); sig_Handle(); if (i <= 0) continue; for (i = 0; i <= nfds; i++) if (FD_ISSET(i, efds)) { log_Printf(LogPHASE, "Exception detected on descriptor %d\n", i); /* We deal gracefully with link descriptor exceptions */ if (!bundle_Exception(bundle, i)) { log_Printf(LogERROR, "Exception cannot be handled !\n"); break; } } if (i <= nfds) break; nothing_done = 1; if (descriptor_IsSet(&server.desc, rfds)) { descriptor_Read(&server.desc, bundle, rfds); nothing_done = 0; } if (descriptor_IsSet(&bundle->desc, rfds)) { descriptor_Read(&bundle->desc, bundle, rfds); nothing_done = 0; } if (descriptor_IsSet(&bundle->desc, wfds)) if (descriptor_Write(&bundle->desc, bundle, wfds) <= 0 && nothing_done) { /* * This is disastrous. The OS has told us that something is * writable, and all our write()s have failed. Rather than * going back immediately to do our UpdateSet()s and select(), * we sleep for a bit to avoid gobbling up all cpu time. */ struct timeval t; t.tv_sec = 0; t.tv_usec = 100000; select(0, NULL, NULL, NULL, &t); } } log_Printf(LogDEBUG, "DoLoop done.\n"); }
static void ether_MessageIn(struct etherdevice *dev) { char msgbuf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)]; struct ng_mesg *rep = (struct ng_mesg *)msgbuf; struct ngpppoe_sts *sts = (struct ngpppoe_sts *)(msgbuf + sizeof *rep); char *end, unknown[14], sessionid[5]; const char *msg; struct timeval t; fd_set *r; u_long slot; int asciilen, ret; if (dev->cs < 0) return; if ((r = mkfdset()) == NULL) { log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n"); return; } while (1) { zerofdset(r); FD_SET(dev->cs, r); t.tv_sec = t.tv_usec = 0; ret = select(dev->cs + 1, r, NULL, NULL, &t); if (ret <= 0) break; if (NgRecvMsg(dev->cs, rep, sizeof msgbuf, NULL) <= 0) break; if (rep->header.version != NG_VERSION) { log_Printf(LogWARN, "%ld: Unexpected netgraph version, expected %ld\n", (long)rep->header.version, (long)NG_VERSION); break; } if (rep->header.typecookie != NGM_PPPOE_COOKIE) { log_Printf(LogWARN, "%ld: Unexpected netgraph cookie, expected %ld\n", (long)rep->header.typecookie, (long)NGM_PPPOE_COOKIE); break; } asciilen = 0; switch (rep->header.cmd) { case NGM_PPPOE_SET_FLAG: msg = "SET_FLAG"; break; case NGM_PPPOE_CONNECT: msg = "CONNECT"; break; case NGM_PPPOE_LISTEN: msg = "LISTEN"; break; case NGM_PPPOE_OFFER: msg = "OFFER"; break; case NGM_PPPOE_SUCCESS: msg = "SUCCESS"; break; case NGM_PPPOE_FAIL: msg = "FAIL"; break; case NGM_PPPOE_CLOSE: msg = "CLOSE"; break; case NGM_PPPOE_GET_STATUS: msg = "GET_STATUS"; break; case NGM_PPPOE_ACNAME: msg = "ACNAME"; if (setenv("ACNAME", sts->hook, 1) != 0) log_Printf(LogWARN, "setenv: cannot set ACNAME=%s: %m", sts->hook); asciilen = rep->header.arglen; break; case NGM_PPPOE_SESSIONID: msg = "SESSIONID"; snprintf(sessionid, sizeof sessionid, "%04x", *(u_int16_t *)sts); if (setenv("SESSIONID", sessionid, 1) != 0) syslog(LOG_WARNING, "setenv: cannot set SESSIONID=%s: %m", sessionid); /* Use this in preference to our interface index */ slot = strtoul(sessionid, &end, 16); if (end != sessionid && *end == '\0') dev->slot = slot; break; default: snprintf(unknown, sizeof unknown, "<%d>", (int)rep->header.cmd); msg = unknown; break; } if (asciilen) log_Printf(LogPHASE, "Received NGM_PPPOE_%s (hook \"%.*s\")\n", msg, asciilen, sts->hook); else log_Printf(LogPHASE, "Received NGM_PPPOE_%s\n", msg); switch (rep->header.cmd) { case NGM_PPPOE_SUCCESS: dev->connected = CARRIER_OK; break; case NGM_PPPOE_FAIL: case NGM_PPPOE_CLOSE: dev->connected = CARRIER_LOST; break; } } free(r); }