2 * firewall.c - Packet filtering for diald.
4 * Copyright (c) 1994, 1995, 1996 Eric Schenk.
5 * All rights reserved. Please see the file LICENSE which should be
6 * distributed with this software for terms of use.
11 static FW_unit units[FW_NRUNIT];
12 static int initialized = 0;
13 int impulse_init_time = 0;
17 void del_connection(FW_Connection *);
20 * Initialize the units.
23 static void init_units(void)
27 for (i = 0; i < FW_NRUNIT; i++) {
29 units[i].filters = NULL;
31 units[i].connections = malloc(sizeof(FW_Connection));
33 units[i].nfilters = 0;
34 if (!units[i].connections) {
35 syslog(LOG_ERR,"Out of memory! AIIEEE!");
38 units[i].connections->next = units[i].connections->prev
39 = units[i].connections;
44 /* is the time given by "clock" in the given slot? */
46 static unsigned int in_slot(FW_Timeslot *slot, time_t *clock)
48 struct tm *ltime = localtime(clock);
49 int ctime = ltime->tm_hour*60*60+ltime->tm_min*60+ltime->tm_sec;
52 syslog(LOG_INFO,"slot check: %d %d %d %d",
53 ltime->tm_sec+ltime->tm_min*60+ltime->tm_hour*60*60, ltime->tm_wday,
54 ltime->tm_mday, ltime->tm_mon);
59 syslog(LOG_INFO,"slot def: %d %d %x %x %x",
60 slot->start, slot->end, slot->wday, slot->mday, slot->month);
62 if ((slot->start <= ctime)
63 && (ctime <= slot->end)
64 && (slot->wday & (1<<ltime->tm_wday))
65 && (slot->mday & (1<<(ltime->tm_mday-1)))
66 && (slot->month & (1<<ltime->tm_mon))) {
77 * return 0 if the given time is in the given slots active time set.
78 * Otherwise return the number of seconds until the slot is next active, or
79 * the number of seconds until the next occurance of 00:00 hours, whichever
83 static unsigned int slot_start_timeout(FW_Timeslot *slot, time_t *clock)
85 struct tm *ltime = localtime(clock);
88 if (in_slot(slot,clock)) return 0;
90 /* Ok, we are currently NOT in this slot's time range. */
92 ctime = ltime->tm_hour*60*60 + ltime->tm_min*60 + ltime->tm_sec;
93 mintime = 24*60*60 - ctime;
96 if ((slot->wday & (1<<ltime->tm_wday))
97 && (slot->mday & (1<<(ltime->tm_mday-1)))
98 && (slot->month & (1<<ltime->tm_mon))
99 && (slot->start >= ctime)) {
100 /* Ok, this slot disjunct occurs today */
101 if (mintime >= (slot->start - ctime))
102 mintime = slot->start - ctime;
111 * return 0 if the given time is not in the given slots active time set.
112 * Otherwise return the number of seconds until the slot times out, or
113 * the number of seconds until the next occurance of 00:00 hours, whichever
117 static unsigned int slot_end_timeout(FW_Timeslot *slot, time_t *clock)
119 struct tm *ltime = localtime(clock);
122 if (!in_slot(slot,clock)) return 0;
124 /* Ok, we are currently in this slot's time range. */
126 ctime = ltime->tm_hour*60*60 + ltime->tm_min*60 + ltime->tm_sec;
130 if ((slot->wday & (1<<ltime->tm_wday))
131 && (slot->mday & (1<<(ltime->tm_mday-1)))
132 && (slot->month & (1<<ltime->tm_mon))
133 && (slot->start <= ctime)
134 && (ctime <= slot->end)) {
135 /* Ok, this slot disjunct is active now */
136 int t = slot->end - ctime;
144 return 24*60*60 - ctime;
149 /* Find a connection in the queue */
150 static FW_Connection *find_connection(FW_unit *unit, FW_ID *id)
152 FW_Connection *c = unit->connections->next;
154 /* look for a connection that matches this one */
155 while (c != unit->connections) {
156 if (memcmp((unsigned char *)&c->id,
157 (unsigned char *)id,sizeof(FW_ID))==0)
161 if (c == unit->connections) {
169 * Add/update a connection in the queue.
172 static void add_connection(
173 FW_unit *unit, FW_Connection *c, FW_ID *id, unsigned int timeout, TCP_STATE lflags)
175 /* look for a connection that matches this one */
178 /* no matching connection, add one */
179 c = malloc(sizeof(FW_Connection));
181 syslog(LOG_ERR,"Out of memory! AIIEEE!");
185 init_timer(&c->timer);
186 c->tcp_state = lflags;
188 c->timer.data = (int)c;
189 c->timer.function = (void *)(int)del_connection;
190 c->next = unit->connections->next;
191 c->prev = unit->connections;
192 unit->connections->next->prev = c;
193 unit->connections->next = c;
194 c->timer.expires = timeout;
195 add_timer(&c->timer);
196 if (debug&DEBUG_CONNECTION_QUEUE)
197 syslog(LOG_INFO,"Adding connection %d @ %ld - timeout %d",(int)c,
201 /* found a matching connection, toss it's old timer */
203 /* reanimating a ghost? */
204 del_timer(&c->timer);
205 c->timer.expires = timeout;
206 add_timer(&c->timer);
207 if (debug&DEBUG_CONNECTION_QUEUE)
208 syslog(LOG_INFO,"Adding connection %d @ %ld - timeout %d",(int)c,
211 /* timeout = 0, so toss the connection */
212 del_timer(&c->timer);
219 * Get a connection out of a queue.
222 void del_connection(FW_Connection *c)
224 if (debug&DEBUG_CONNECTION_QUEUE)
225 syslog(LOG_INFO,"Deleting connection %d @ %ld",(int)c,time(0));
227 c->next->prev = c->prev;
228 c->prev->next = c->next;
232 void del_impulse(FW_unit *unit)
235 if (unit->impulse_mode) {
236 unit->impulse_mode = 0;
237 if (impulse_time > 0) {
238 unit->impulse.data = (int)unit;
239 unit->impulse.function = (void *)(int)del_impulse;
240 unit->impulse.expires = impulse_time;
241 if (debug&DEBUG_CONNECTION_QUEUE)
242 syslog(LOG_INFO,"Refreshing impulse generator: mode %d, time %ld @ %ld",unit->impulse_mode,unit->impulse.expires,time(0));
243 add_timer(&unit->impulse);
246 unit->impulse_mode = 1;
247 impulse_init_time = 0; /* zero the initial impulse time */
248 if (impulse_fuzz > 0) {
249 unit->impulse.data = (int)unit;
250 unit->impulse.function = (void *)(int)del_impulse;
251 unit->impulse.expires = impulse_fuzz;
252 if (debug&DEBUG_CONNECTION_QUEUE)
253 syslog(LOG_INFO,"Refreshing impulse generator: mode %d, time %ld @ %ld",unit->impulse_mode,unit->impulse.expires,time(0));
254 add_timer(&unit->impulse);
259 /* Check if a forcing rule currently applies to the connection */
261 static void fw_force_update(FW_unit *unit)
264 int timeout, mintime;
265 time_t clock = time(0);
267 /* check if the current forcing slot has expired */
268 if (unit->force_etime > clock) return;
275 if (fw->filt.type == FW_TYPE_UP || fw->filt.type == FW_TYPE_DOWN) {
276 /* check when the rule is next applicable */
277 timeout = slot_start_timeout(fw->filt.times,&clock);
280 /* first time at which a previous slot starts */
281 if (timeout < mintime)
285 /* time at which the current slot ends */
286 timeout = slot_end_timeout(fw->filt.times,&clock);
287 if (timeout < mintime)
293 if (fw->filt.type == FW_TYPE_UP)
300 next_rule: /* try the next filter */
304 unit->force_etime = clock + mintime;
307 /* Check if an impulse rule currently applies to the connection */
309 static void fw_impulse_update(FW_unit *unit, int force)
312 int timeout, mintime, itimeout, ifuzz, ftimeout;
313 time_t clock = time(0);
315 /* check if the current forcing slot has expired */
316 if (clock < unit->impulse_etime && !force) return;
325 if (fw->filt.type == FW_TYPE_IMPULSE) {
326 /* check when the rule is next applicable */
327 timeout = slot_start_timeout(fw->filt.times,&clock);
329 /* Will be applicable soon */
330 /* first time at which a previous slot starts
331 * (i.e. schedule changes) */
332 if (timeout < mintime)
336 /* time at which the current slot ends */
337 timeout = slot_end_timeout(fw->filt.times,&clock);
338 ifuzz = fw->filt.fuzz;
339 itimeout = fw->filt.timeout;
340 ftimeout = fw->filt.timeout2;
341 if (timeout < mintime)
349 next_rule: /* try the next filter */
352 unit->impulse_etime = clock + mintime;
354 del_timer(&unit->impulse);
355 if (unit->up && (itimeout > 0 || (force && ftimeout > 0))) {
356 /* place the current impulse generator into the impulse queue */
357 impulse_time = itimeout;
358 impulse_init_time = ftimeout;
359 impulse_fuzz = ifuzz;
360 unit->impulse_mode = 0;
361 unit->impulse.data = (int)unit;
362 unit->impulse.function = (void *)(int)del_impulse;
363 unit->impulse.expires = (force)?ftimeout:itimeout;
364 add_timer(&unit->impulse);
365 if (debug&DEBUG_CONNECTION_QUEUE)
366 syslog(LOG_INFO,"Refreshing impulse generator: mode %d, time %ld @ %ld",unit->impulse_mode,unit->impulse.expires,time(0));
370 static void log_packet(int accept, struct iphdr *pkt, int len, int rule)
372 char saddr[20], daddr[20];
374 int sport = 0, dport = 0;
375 struct tcphdr *tcp = (struct tcphdr *)((char *)pkt + 4*pkt->ihl);
376 struct udphdr *udp = (struct udphdr *)tcp;
378 addr.s_addr = pkt->saddr;
379 strcpy(saddr,inet_ntoa(addr));
380 addr.s_addr = pkt->daddr;
381 strcpy(daddr,inet_ntoa(addr));
383 if (pkt->protocol == IPPROTO_TCP || pkt->protocol == IPPROTO_UDP)
384 sport = ntohs(udp->source), dport = ntohs(udp->dest);
386 if (pkt->protocol == IPPROTO_TCP) {
388 "filter %s rule %d proto %d len %d seq %lx ack %lx flags %s%s%s%s%s%s packet %s,%d => %s,%d",
389 (accept)?"accepted":"ignored",rule,
392 ntohl(tcp->seq), ntohl(tcp->ack_seq),
393 (tcp->fin) ? " FIN" : "",
394 (tcp->syn) ? " SYN" : "",
395 (tcp->rst) ? " RST" : "",
396 (tcp->psh) ? " PUSH" : "",
397 (tcp->ack) ? " ACK" : "",
398 (tcp->urg) ? " URG" : "",
399 saddr, sport, daddr, dport);
402 "filter %s rule %d proto %d len %d packet %s,%d => %s,%d",
403 (accept)?"accepted":"ignored",rule,
406 saddr, sport, daddr, dport);
410 /* Check if we need to reorder IP addresses for cannonical ordering */
411 static int ip_direction(struct iphdr *pkt)
413 struct udphdr *udp = (struct udphdr *)((char *)pkt + 4*pkt->ihl);
414 if (ntohl(pkt->saddr) > ntohl(pkt->daddr)
415 || (ntohl(pkt->saddr) == ntohl(pkt->daddr) &&
416 (pkt->protocol == IPPROTO_TCP || pkt->protocol == IPPROTO_UDP)
417 && ntohs(udp->source) > ntohs(udp->dest)))
423 static void ip_swap_addrs(struct iphdr *pkt)
425 struct udphdr *udp = (struct udphdr *)((char *)pkt + 4*pkt->ihl);
427 unsigned short tport;
428 if (pkt->protocol == IPPROTO_TCP || pkt->protocol == IPPROTO_UDP) {
430 udp->source = udp->dest;
434 pkt->saddr = pkt->daddr;
438 void print_filter(FW_Filter *filter)
441 syslog(LOG_INFO,"filter: prl %d log %d type %d cnt %d tm %d",
442 filter->prule,filter->log,filter->type,
443 filter->count,filter->timeout);
444 for (i = 0; i < filter->count; i++) {
445 syslog(LOG_INFO," term: shift %d op %d off %d%c msk %x tst %x",
446 filter->terms[i].shift, filter->terms[i].op,
447 filter->terms[i].offset&0x7f,
448 (filter->terms[i].offset&0x80)?'d':'h',
449 filter->terms[i].mask, filter->terms[i].test);
453 /* Check if a packet passes the filters */
454 int check_firewall(int unitnum, unsigned char *pkt, int len)
459 FW_ProtocolRule *prule, *pprule = 0;
464 clock_t clock = time(0);
467 struct iphdr * ip_pkt = (struct iphdr *)pkt;
469 if (!initialized) init_units();
471 if (unitnum < 0 || unitnum >= FW_NRUNIT) {
472 /* FIXME: set an errorno? */
476 unit = &units[unitnum];
479 data = pkt + 4*((struct iphdr *)pkt)->ihl;
481 /* Find the correct protocol rule */
482 for (i = 0; i < unit->nrules; i++) {
483 pprule = &unit->prules[i];
484 if (FW_PROTO_ALL(pprule->protocol)
485 || pprule->protocol == ip_pkt->protocol)
490 return -1; /* No protocol rules? */
493 /* Build the connection ID, and set the direction flag */
494 direction = ip_direction(ip_pkt);
495 if (direction == 2) ip_swap_addrs(ip_pkt);
496 for (i = 0; i < FW_ID_LEN; i++)
497 id.id[i] = (FW_IN_DATA(pprule->codes[i])?data:pkt)
498 [FW_OFFSET(pprule->codes[i])];
499 if (direction == 2) ip_swap_addrs(ip_pkt);
500 conn = find_connection(unit,&id);
501 opdir = (direction==1)?2:1;
503 /* Do the TCP liveness changes */
504 if (ip_pkt->protocol == IPPROTO_TCP) {
505 struct tcphdr *tcp = (struct tcphdr *)((char *)ip_pkt + 4*ip_pkt->ihl);
506 int tcp_data_len = len - (4*ip_pkt->ihl + sizeof(struct tcphdr));
509 lflags = conn->tcp_state;
511 lflags.fin_seq[0] = lflags.fin_seq[1] = 0;
512 lflags.tcp_flags = 0;
517 lflags.tcp_flags = 0;
518 } else if (tcp->fin) {
519 lflags.saw_fin |= direction;
520 lflags.fin_seq[direction-1] = ntohl(tcp->seq)+tcp_data_len+1;
521 } else if (tcp->syn || tcp_data_len > 0) {
522 /* Either we have a SYN packet, or we have a data carrying
523 * packet. In either case we want to declare this direction live.
524 * FIXME. It is possible that this should set saw_fin to 0 in the
525 * case that we have a SYN packet.
527 lflags.saw_fin &= ~direction;
528 lflags.tcp_flags |= direction;
530 if ((lflags.saw_fin & opdir) && (tcp->ack)) {
531 if (lflags.fin_seq[opdir-1] == ntohl(tcp->ack_seq)) {
532 lflags.tcp_flags &= ~direction;
537 conn->tcp_state = lflags;
544 print_filter(&fw->filt);
546 /* is this rule currently applicable? */
547 if ((unit->up && fw->filt.type == FW_TYPE_BRINGUP)
548 || (!unit->up && fw->filt.type == FW_TYPE_KEEPUP)
549 || !in_slot(fw->filt.times,&clock)
550 || fw->filt.type == FW_TYPE_IMPULSE
551 || fw->filt.type == FW_TYPE_UP
552 || fw->filt.type == FW_TYPE_DOWN)
555 /* Check the protocol rule */
556 prule = &unit->prules[fw->filt.prule];
557 if (!(FW_PROTO_ALL(prule->protocol)
558 || prule->protocol == ip_pkt->protocol))
561 /* Check the terms */
563 (fw->filt.count > FW_MAX_TERMS) || (i < fw->filt.count); i++) {
564 if (i > FW_MAX_TERMS && fw->filt.count == 0) {
565 fw = fw->next, i = 0;
566 if (fw == NULL) break;
568 term = &fw->filt.terms[i];
569 if (FW_TCP_STATE(term->offset))
570 v = (lflags.tcp_flags >> term->shift) && term->mask;
572 v = (ntohl(*(int *)(&(FW_IN_DATA(term->offset)?data:pkt)
573 [FW_OFFSET(term->offset)]))
574 >> term->shift) & term->mask;
576 syslog(LOG_INFO,"testing ip %x:%x data %x:%x mask %x shift %x test %x v %x",
577 ntohl(*(int *)(&pkt[FW_OFFSET(term->offset)])),
578 *(int *)(&pkt[FW_OFFSET(term->offset)]),
579 ntohl(*(int *)(&data[FW_OFFSET(term->offset)])),
580 *(int *)(&data[FW_OFFSET(term->offset)]),
587 case FW_EQ: if (v != term->test) goto next_rule; break;
588 case FW_NE: if (v == term->test) goto next_rule; break;
589 case FW_GE: if (v < term->test) goto next_rule; break;
590 case FW_LE: if (v > term->test) goto next_rule; break;
593 /* Ok, we matched a rule. What are we suppose to do? */
597 if (debug&DEBUG_FILTER_MATCH)
598 log_packet(fw->filt.type!=FW_TYPE_IGNORE,ip_pkt,len,rule);
600 /* Check if this entry goes into the queue or not */
601 if (fw->filt.type != FW_TYPE_IGNORE && fw->filt.type != FW_TYPE_WAIT) {
602 add_connection(unit,conn,&id,fw->filt.timeout,lflags);
604 /* check if we are no longer waiting */
605 if (fw->filt.type == FW_TYPE_WAIT) {
607 /* WAITING rules don't do the final match, but
608 * must occur before other rules
613 /* Return 1 if accepting rule with non zero timeout, 0 otherwise */
614 return ((fw->filt.type != FW_TYPE_IGNORE || fw->filt.type != FW_TYPE_WAIT) && fw->filt.timeout > 0);
616 next_rule: /* try the next filter */
620 /* Failed to match any rule. This means we ignore the packet */
621 if (debug&DEBUG_FILTER_MATCH)
622 log_packet(0,ip_pkt,len,0);
626 static void pcountdown(int level, long secs)
629 sprintf(buf,"%02ld:%02ld:%02ld\n",secs/3600,(secs/60)%60,secs%60);
630 if (monitors) mon_write(level,buf,9);
633 int ctl_firewall(int op, struct firewall_req *req)
636 if (!initialized) init_units();
638 /* Need to check that req is OK */
640 if (req && req->unit >= FW_NRUNIT) return -1; /* ERRNO */
642 if (req) unit = &units[req->unit];
647 if (!req) return -1; /* ERRNO */
649 FW_Connection *c,*cn;
650 for (c = unit->connections->next;
651 c != unit->connections; c = cn) {
653 del_timer(&c->timer);
654 c->next->prev = c->prev;
655 c->prev->next = c->next;
661 if (!req) return -1; /* ERRNO */
663 fw_force_update(unit);
664 fw_impulse_update(unit,0);
666 return (unit->force == 2
668 && !(unit->up && unit->impulse_mode == 0
669 && (impulse_init_time > 0 || impulse_time > 0))
670 && unit->connections == unit->connections->next));
674 if (!req) return -1; /* ERRNO */
677 /* PFLUSH implies FFLUSH */
679 if (!req) return -1; /* ERRNO */
681 FW_Filters *next, *filt = unit->filters;
683 { next = filt->next; free(filt); filt = next; }
684 unit->filters = NULL;
689 if (!req) return -1; /* ERRNO */
691 FW_Filters *filters = malloc(sizeof(FW_Filters));
693 syslog(LOG_ERR,"Out of memory! AIIEEE!");
694 return -1; /* ERRNO */
697 filters->filt = req->fw_arg.filter;
698 if (unit->last) unit->last->next = filters;
699 if (!unit->filters) unit->filters = filters;
700 unit->last = filters;
705 if (!req) return -1; /* ERRNO */
706 if (unit->nrules >= FW_MAX_PRULES) return -1; /* ERRNO */
707 unit->prules[(int)unit->nrules] = req->fw_arg.rule;
708 return unit->nrules++;
709 /* Printing does nothing right now */
711 if (!req) return -1; /* ERRNO */
713 unsigned long atime = time(0);
714 unsigned long tstamp = timestamp();
716 char saddr[20], daddr[20];
718 syslog(LOG_INFO,"up = %d, forcing = %d, impulse = %d, iitime = %d, itime = %d, ifuzz = %d, itimeout = %ld, timeout = %ld, next alarm = %d",
719 unit->up,unit->force, unit->impulse_mode, impulse_init_time, impulse_time,
721 unit->impulse.expected-tstamp,unit->force_etime-atime,
723 for (c=unit->connections->next; c!=unit->connections; c=c->next) {
724 if (c->timer.next == 0) c->timer.expected = tstamp;
725 addr.s_addr = c->id.id[1] + (c->id.id[2]<<8)
726 + (c->id.id[3]<<16) + (c->id.id[4]<<24);
727 strcpy(saddr,inet_ntoa(addr));
728 addr.s_addr = c->id.id[5] + (c->id.id[6]<<8)
729 + (c->id.id[7]<<16) + (c->id.id[8]<<24);
730 strcpy(daddr,inet_ntoa(addr));
732 "ttl %ld, %d - %s/%d => %s/%d (tcp state ([%lx,%lx] %d,%d))",
733 c->timer.expected-tstamp, c->id.id[0],
734 saddr, c->id.id[10]+(c->id.id[9]<<8),
735 daddr, c->id.id[12]+(c->id.id[11]<<8),
736 c->tcp_state.fin_seq[0],
737 c->tcp_state.fin_seq[1],
738 c->tcp_state.saw_fin,
739 c->tcp_state.tcp_flags);
745 if (!req || !monitors) return -1; /* ERRNO */
747 unsigned long atime = time(0);
748 unsigned long tstamp = timestamp();
750 char saddr[20], daddr[20];
753 struct protoent *pent;
757 sprintf(buf,"STATUS\n%d\n%d\n%d\n%d\n%d\n%d\n",
758 unit->up, unit->force, unit->impulse_mode,
759 impulse_init_time, impulse_time,
761 if (monitors) mon_write(MONITOR_STATUS,buf,strlen(buf));
763 pcountdown(MONITOR_STATUS,(unit->impulse_mode)?(unit->impulse.expected-tstamp):0);
764 pcountdown(MONITOR_STATUS,unit->force_etime-atime);
765 pcountdown(MONITOR_STATUS,next_alarm());
766 if (monitors) mon_write(MONITOR_QUEUE,"QUEUE\n",6);
767 for (c=unit->connections->next; c!=unit->connections; c=c->next) {
768 if (c->timer.next == 0) continue;
769 addr.s_addr = c->id.id[1] + (c->id.id[2]<<8)
770 + (c->id.id[3]<<16) + (c->id.id[4]<<24);
771 strcpy(saddr,inet_ntoa(addr));
772 addr.s_addr = c->id.id[5] + (c->id.id[6]<<8)
773 + (c->id.id[7]<<16) + (c->id.id[8]<<24);
774 strcpy(daddr,inet_ntoa(addr));
778 pent = getprotobynumber(c->id.id[0]);
780 if (pent) strcpy(proto,pent->p_name);
781 else sprintf(proto,"%d",c->id.id[0]);
782 sport = c->id.id[10]+(c->id.id[9]<<8);
783 dport = c->id.id[12]+(c->id.id[11]<<8);
785 "%-4s %15s/%-5d %15s/%-5d ",
788 if (monitors) mon_write(MONITOR_QUEUE,buf,strlen(buf));
789 pcountdown(MONITOR_QUEUE,c->timer.expected-tstamp);
791 if (monitors) mon_write(MONITOR_QUEUE,"END QUEUE\n",10);
796 if (!req) return -1; /* ERRNO */
799 if (!req) return -1; /* ERRNO */
801 /* Opening and closing firewalls is cooperative right now.
802 * Also, it does nothing to change the behavior of a device
803 * associated with the firewall.
808 for (i = 0; i < FW_NRUNIT; i++)
809 if (units[i].used == 0) {
810 struct firewall_req mreq;
812 ctl_firewall(IP_FW_PFLUSH,&mreq);
814 units[i].force_etime = 0;
815 units[i].impulse_etime = 0;
816 units[i].waiting = 1;
819 return -1; /* ERRNO */
823 struct firewall_req mreq;
824 if (!req) return -1; /* ERRNO */
825 mreq.unit = req->unit;
826 ctl_firewall(IP_FW_PFLUSH,&mreq);
833 fw_force_update(unit);
834 fw_impulse_update(unit,1);
838 if (unit->up) run_ip_down();
840 /* turn off the impulse generator */
841 del_timer(&unit->impulse);
844 return unit->waiting;
845 case IP_FW_RESET_WAITING:
849 return -1; /* ERRNO */