#include "../h/param.h" #include "../h/inode.h" #include "../bbnnet/mbuf.h" #include "../bbnnet/net.h" #include "../bbnnet/ifcb.h" #include "../bbnnet/tcp.h" #include "../bbnnet/ip.h" #include "../bbnnet/ucb.h" #include "../bbnnet/fsm.h" #include "../h/buf.h" #include "../h/dir.h" #include "../h/user.h" #include "../h/proc.h" extern struct user u; char netbugf[] = "/etc/net/tcpdebug"; /* * This is the mainline of the network input process. First, we * fork off as a separate process within the kernel, initialize the * net buffer manager, and timers. (Net i/fs must be init by NETINIT * system call). Then, we * loop forever, sleeping on net input. Once awakened by a local net * driver, we dispatch to each local interface in turn, to process the * input message(s). After handling the interfaces, we adjust the net * buffer allocation, call on the tcp processor to handle any outstanding * timer or user events, and... */ netmain() { register struct inode *ip; register struct proc *p; register struct ifcb *lp; int schar(); int fid; fid = u.u_r.r_val1; fork(); /* returns twice - once in old and once in new */ u.u_r.r_val1 = fid; if (!u.u_error && u.u_r.r_val2) { /* if child then */ netcb.n_proc = p = u.u_procp; /* -> proc table entry */ p->p_flag |= SSYS; netcb.n_iss = 1; netcb.n_ip_cnt = 0; /* set up debugging file */ netcb.n_debug = NULL; u.u_dirp = &netbugf[0]; ip = namei(schar, 0); if (ip != NULL) if ((ip->i_mode & IFMT) != IFREG) iput(ip); else { netcb.n_debug = ip; prele(ip); } mbufinit(); /* init buf mgmt system */ gatewayNGATE = gateway; /* null gateway table */ /* start timers */ net_timer(); for (;;) { /* body of input process */ /* * reset local i/f if necessary, otherwise * just handle net input */ for (lp=netcb.n_ifcb_hd; lp != NULL; lp=lp->if_next) { process: if (lp->if_error && !lp->if_needinit) { lp->if_needinit = TRUE; netreset(lp); } else if (lp->if_avail && lp->if_inq_hd != NULL) (*lp->if_rcv)(lp); /* call TCP processor to handle any user or timer events. */ if (netcb.n_work != NULL) tcp_input(NULL, NULL); /* * expand or shrink the buffer freelist as needed */ if (netcb.n_bufs < netcb.n_lowat) m_expand(); else if (netcb.n_bufs > netcb.n_hiwat) m_relse(); } /* * wait for net input (awakened by drivers) */ for (lp=netcb.n_ifcb_hd; lp != NULL; lp=lp->if_next) if (lp->if_inq_hd != NULL) goto process; sleep((caddr_t)&netcb.n_ifcb_hd, PZERO-15); } } } #ifdef BUFSTAT struct buf_stat bufnull = {0}; #endif BUFSTAT /* * Net timer routine: scheduled every second, calls ip and tcp timeout routines * and does any net-wide statistics. */ net_timer() { register struct mbuf *m, *n; register struct ucb *up; register struct tcb *tp; register struct th *t; register struct ifcb *lp; register struct ipq *ip; register struct ip *i; register struct host *h; register struct work *w; ip_timeo(); tcp_timeo(); #ifdef BUFSTAT bufstat = bufnull; for (up = netcb.n_ucb_hd; up != NULL; up = up->uc_next) { if (up->uc_flags & UTCP) { if ((tp = up->uc_tcb) == NULL) continue; bufstat.b_tcbs++; if (tp->t_state != ESTAB) bufstat.b_cons--; if ((t = tp->t_rcv_next) == NULL) continue; for (; t != (struct th *)tp; t=t->t_next) { m = dtom(t); while (m != NULL) { bufstat.b_tseq++; m = m->m_next; } } for (m=tp->t_rcv_unack; m != NULL; m=m->m_act) { n = m; do { bufstat.b_tuna++; n = n->m_next; } while (n != NULL); } } bufstat.b_cons++; bufstat.b_useq += up->uc_rsize + up->uc_ssize; } for (ip=netcb.n_ip_head; ip != NULL; ip=ip->iq_next) for (i=ip->iqx.ip_next; i != (struct ip *)ip; i=i->ip_next) { m = dtom(i); while (m != NULL) { bufstat.b_ipfr++; m = m->m_next; } } for (lp = netcb.n_ifcb_hd; lp != NULL; lp = lp->if_next) { for (m=lp->if_outq_hd; m != NULL; m = m->m_act) { n = m; do { bufstat.b_devq++; n = n->m_next; } while (n != NULL); } for (m=lp->if_outq_cur; m != NULL; m = m->m_next) bufstat.b_devq++; for (m=lp->if_inq_hd; m != NULL; m = m->m_act) { n = m; do { bufstat.b_devq++; n = n->m_next; } while (n != NULL); } for (m=lp->if_inq_msg; m != NULL; m = m->m_next) bufstat.b_devq++; } for (h=host; h < hostNHOST; h++) if (h->h_refct > 0) for (m = h->h_outq; m != NULL; m = m->m_act) { n = m; do { bufstat.b_rfnm++; n = n->m_next; } while (n != NULL); } for (w=netcb.n_work; w != NULL; w = w->w_next) if (w->w_type == INRECV || w->w_type == IUSEND) for (m=dtom(w->w_dat); m != NULL; m = m->m_next) bufstat.b_work++; #endif BUFSTAT timeout(net_timer, 0, HZ); } /* * Generic local net reset: clear input and output queues and call driver * init routine. */ netreset(ip) register struct ifcb *ip; { register struct mbuf *m, *n; int s; s = spl5(); ip->if_avail = FALSE; /* * clear all i/f queues */ for (m=ip->if_inq_hd; m != NULL; m=n) { n = m->m_act; m_freem(m); } ip->if_inq_hd = NULL; ip->if_inq_tl = NULL; for (m=ip->if_outq_hd; m != NULL; m=n) { n = m->m_act; m_freem(m); } ip->if_outq_hd = NULL; ip->if_outq_tl = NULL; if (ip->if_inq_msg != NULL) { m_freem(ip->if_inq_msg); ip->if_inq_msg = NULL; ip->if_inq_cur = NULL; } if (ip->if_outq_cur != NULL) { m_freem(ip->if_outq_cur); ip->if_outq_cur = NULL; } h_reset(iptonet(ip->if_addr)); splx(s); printf("%s%d: netreset\n", ip->if_name, ip->if_unit); ip->if_resets++; /* * now call net driver specific init routine to reinit */ (*ip->if_init)(ip); } /* * Save anomolous packets for debugging purposes. If limit is non-zero, * save up to limit packets. Otherwise just free. */ netlog(mp) register struct mbuf *mp; { register struct mbuf *m; if (netcb.n_loglim > 0) { /* free all but header */ if (mp->m_next != NULL) { m_freem(mp->m_next); mp->m_next = NULL; } /* add to end */ mp->m_act = NULL; if (netcb.n_log_hd != NULL) netcb.n_log_tl->m_act = mp; else netcb.n_log_hd = mp; netcb.n_log_tl = mp; netcb.n_logct++; /* if limit exceeded, remove from head */ while (netcb.n_logct > netcb.n_loglim && (m = netcb.n_log_hd) != NULL) { netcb.n_log_hd = m->m_act; m_free(m); netcb.n_logct--; } } else m_freem(mp); }