|
|
1.1 root 1: /*
2: * ip line discipline, to be pushed on an ethernet controller.
3: * collects data till a delim, passes it to ip_input().
4: */
5:
6: #include "sys/param.h"
7: #include "sys/stream.h"
8: #include "sys/conf.h"
9: #include "sys/inet/in.h"
10: #include "sys/inet/ip_var.h"
11: #include "sys/inet/ethernet.h"
12:
13: extern struct ipif ipif[];
14: extern struct ipif *ipifsort[];
15: extern int ipcnt; /* number of ip's */
16: extern int arpcnt;
17:
18: int ipiput(), ipisrv(), ipclose();
19: long ipopen();
20: int iposrv();
21: static struct qinit iprinit = { ipiput, ipisrv, ipopen, ipclose, IP_MSG_LIMIT, 64};
22: static struct qinit ipwinit = { putq, iposrv, ipopen, ipclose, 2*IP_MSG_LIMIT, 64 };
23: struct streamtab ipstream = { &iprinit, &ipwinit };
24:
25: long
26: ipopen(q, dev)
27: register struct queue *q;
28: {
29: static int timing;
30: register struct ipif *fp, *ifend;
31:
32: if (q->ptr)
33: return(1);
34: if(!timing){
35: timing = 1;
36: ip_slowtimo();
37: }
38: ifend = &ipif[ipcnt];
39: for (fp = ipif; fp < ifend; fp++)
40: if (fp->queue == NULL)
41: break;
42: if (fp >= ifend)
43: return(0);
44: fp->queue = q; /* that's the RD q */
45: fp->flags = IFF_UP;
46: fp->that = fp->thishost = 0;
47: fp->ipackets = fp->opackets = fp->ierrors = fp->oerrors = 0;
48: fp->mtu = 1500;
49: fp->arp = -1;
50: fp->dev = dev;
51: q->flag |= QDELIM;
52: WR(q)->flag |= QDELIM;
53: q->ptr = (caddr_t)fp;
54: WR(q)->ptr = (caddr_t)fp;
55: q->flag |= QNOENB; /* ipiput calls qenable() */
56: return(1);
57: }
58:
59: ipclose(q)
60: struct queue *q;
61: {
62: register struct ipif *ifp;
63:
64: ifp = (struct ipif *)q->ptr;
65: ip_ifremove(ifp);
66: ifp->queue = 0;
67: ifp->flags = 0;
68: }
69:
70: ipisrv(q)
71: register struct queue *q;
72: {
73: register struct block *bp, *head, *tail;
74: register struct ipif *ifp;
75:
76: /* there is now a whole packet waiting
77: * on this queue; strip it off and pass to ip_input().
78: * things other than data or delims are forwarded directly
79: * by ipiput().
80: */
81: head = tail = (struct block *) 0;
82: ifp = (struct ipif *)q->ptr;
83: while(bp = getq(q)){
84: if (bp->type != M_DATA)
85: panic("ipisrv");
86: bp->next = NULL;
87: if (head == NULL)
88: head = bp;
89: else
90: tail->next = bp;
91: tail = bp;
92: if (bp->class&S_DELIM) {
93: bp->class &=~ S_DELIM;
94: MCHECK(head);
95: if((ifp->flags & IFF_ARP)
96: && (head->wptr-head->rptr) >= sizeof(struct etherpup)){
97: /* strip off ether header */
98: head->rptr += sizeof(struct etherpup);
99: }
100: ip_input(head);
101: ifp->ipackets++;
102: head = tail = NULL;
103: }
104: }
105: if(head)
106: bp_putback(q, head);
107: }
108:
109:
110: ipiput(q, bp)
111: register struct queue *q;
112: register struct block *bp;
113: {
114: switch(bp->type){
115: case M_DATA:
116: putq(q, bp);
117: if (bp->class&S_DELIM)
118: qenable(q);
119: break;
120: default:
121: (*q->next->qinfo->putp)(q->next, bp);
122: break;
123: }
124:
125: }
126:
127:
128: /*
129: * set our many broadcast addresses
130: */
131: static
132: setbcast(ifp)
133: struct ipif *ifp;
134: {
135: int i;
136:
137: /* official style */
138: ifp->bcast[0] = ifp->that|~ifp->mask; /* subnet */
139: ifp->bcast[1] = ifp->that|~IN_CLASS_NMASK(ifp->that); /* net */
140: ifp->bcast[2] = 0xffffffff; /* undirected */
141:
142: /* old BSD style */
143: ifp->bcast[3] = ifp->that&ifp->mask; /* subnet */
144: ifp->bcast[4] = ifp->that&IN_CLASS_NMASK(ifp->that); /* net */
145: ifp->bcast[5] = 0; /* undirected */
146:
147: if(ifp->flags & IFF_HOST)
148: for(i = 0; i < 6; i++)
149: ifp->bcast[i] = 0;
150: }
151:
152: iposrv(q)
153: register struct queue *q;
154: {
155: struct x{
156: unsigned int in;
157: unsigned char en[6];
158: } *xp;
159: register struct block *bp;
160: register struct ipif *ifp;
161: register long *intp;
162:
163: ifp = (struct ipif *)q->ptr;
164: while(bp = getq(q)){
165: switch (bp->type) {
166: case M_IOCTL:
167: switch(stiocom(bp)){
168: case IPIOARP:
169: ifp->flags |= IFF_ARP;
170: bp->type = M_IOCACK;
171: bp->wptr = bp->rptr;
172: qreply(q, bp);
173: break;
174: case IPIORESOLVE:
175: xp = (struct x *)(stiodata(bp));
176: if (arpcnt > 0)
177: arp_install(xp->in, xp->en);
178: bp->wptr = bp->rptr;
179: bp->type = M_IOCACK;
180: qreply(q, bp);
181: break;
182: case IPIOHOST:
183: intp = (long *)(stiodata(bp));
184: ifp->that = *intp;
185: ifp->flags |= IFF_HOST;
186: ifp->mask = 0xffffffff;
187: setbcast(ifp);
188: ip_ifinsert(ifp);
189: bp->type = M_IOCACK;
190: qreply(q, bp);
191: ip_doroute(ifp->that, 0);
192: break;
193: case IPIOMTU:
194: intp = (long *)(stiodata(bp));
195: ifp->mtu = *intp;
196: bp->type = M_IOCACK;
197: qreply(q, bp);
198: break;
199: case IPIONET:
200: intp = (long *)(stiodata(bp));
201: ifp->that = *intp;
202: ifp->mask = IN_CLASS_NMASK(ifp->that);
203: setbcast(ifp);
204: ip_ifinsert(ifp);
205: ifp->flags &= (~IFF_HOST);
206: bp->type = M_IOCACK;
207: qreply(q, bp);
208: ip_doroute(ifp->that, 0);
209: break;
210: case IPIOMASK:
211: intp = (long *)(stiodata(bp));
212: /*
213: * the mask has to be a superset of the class mask
214: */
215: if((*intp&ifp->mask)==ifp->mask)
216: ifp->mask = *intp;
217: setbcast(ifp);
218: ip_ifinsert(ifp);
219: bp->type = M_IOCACK;
220: qreply(q, bp);
221: break;
222: case IPIOLOCAL:
223: intp = (long *)(stiodata(bp));
224: ifp->thishost = *intp;
225: setbcast(ifp);
226: bp->type = M_IOCACK;
227: qreply(q, bp);
228: break;
229: default:
230: (*q->next->qinfo->putp)(q->next, bp);
231: break;
232: }
233: continue;
234:
235: default:
236: if (q->next->flag & QFULL) {
237: putbq(q, bp);
238: return;
239: }
240: if(bp->class&S_DELIM)
241: ifp->opackets++;
242: (*q->next->qinfo->putp)(q->next, bp);
243: continue;
244: }
245: }
246: }
247:
248: /*
249: * Insert an entry into ipifsort. Entries are sorted by mask length,
250: * longest first.
251: */
252: ip_ifinsert(ifp)
253: struct ipif *ifp;
254: {
255: int s = spl6();
256: register int i, j;
257:
258: /*
259: * First try to remove it. This may be a reordering.
260: */
261: ip_ifremove(ifp);
262:
263: /*
264: * Now (re)insert it in the correct place
265: */
266: for(i=0; i<ipcnt; i++){
267: if(ipifsort[i]==ifp)
268: panic("ip_ifinsert duplcate");
269: if(ipifsort[i]==0 || (ifp->mask & ipifsort[i]->mask)!=ifp->mask)
270: break;
271: }
272: if(i>=ipcnt)
273: panic("ip_ifinsert no room");
274: for(j=ipcnt-1; j>i; j--)
275: ipifsort[j] = ipifsort[j-1];
276: ipifsort[i] = ifp;
277: splx(s);
278: }
279:
280: /*
281: * Remove an entry from ipifsort. Compress list to fill gap.
282: * It may not already be there.
283: */
284: ip_ifremove(ifp)
285: struct ipif *ifp;
286: {
287: int s = spl6();
288: register int i;
289:
290: for(i=0; i<ipcnt; i++)
291: if(ipifsort[i]==ifp)
292: break;
293: if(i<ipcnt){
294: for(; i<ipcnt-1; i++)
295: ipifsort[i] = ipifsort[i+1];
296: ipifsort[i] = 0;
297: }
298: splx(s);
299: }
300:
301: /*
302: * Find the interface to use for sending messages to `dst'.
303: * ipifsort is sorted into priority order;
304: * first match found is best.
305: */
306: struct ipif *
307: ip_ifonnetof(dst)
308: register unsigned long dst;
309: {
310: extern ipprintfs;
311: register struct ipif *ifp;
312: register int i;
313: register int Ipcnt = ipcnt; /* optimization */
314:
315: /*
316: * first look for a match against addresses
317: */
318: for(i=0; i < Ipcnt; i++){
319: if((ifp = ipifsort[i])==0)
320: break;
321: if(ifp->flags & IFF_UP)
322: if((dst & ifp->mask) == ifp->that)
323: return(ifp);
324: }
325:
326: /*
327: * now try to match against the local host's addresses
328: */
329: ifp = ip_ifwithaddr(dst);
330: if(ifp)
331: return(ifp);
332:
333: /*
334: * no match
335: */
336: if(ipprintfs)
337: printf("ifonnetof %x?\n", dst);
338: return(0);
339: }
340:
341: /*
342: * return the interface for which addr is a local address. if non
343: * such exists, return 0.
344: *
345: * This routine assumes that ipifsort is sorted in priority order
346: * so that the first match found is the best match.
347: */
348: struct ipif *
349: ip_ifwithaddr(addr)
350: register u_long addr;
351: {
352: register int i, j;
353: register u_long net, mask;
354: register struct ipif *ifp;
355: register int Ipcnt = ipcnt; /* optimization */
356:
357: net = in_netof(addr);
358: for(i=0; i < Ipcnt; i++){
359: if((ifp = ipifsort[i])==0)
360: break;
361: if(ifp->flags & IFF_UP) {
362:
363: /* address of this host */
364: if(addr == ifp->thishost)
365: return(ifp);
366:
367: for(j = 0; j < 6; j++)
368: if(addr == ifp->bcast[j])
369: return(ifp);
370:
371: /* address on a network simulated by this node */
372: if(net == ifp->thishost)
373: return(ifp);
374: }
375: }
376: return(0);
377: }
378:
379: /*
380: * output list bp onto interface ifp
381: * for better buffering, put it on ip's queue first;
382: * iposrv will dribble it out as there's room
383: */
384: ip_ldout(bp, dst, ifp)
385: register struct block *bp;
386: unsigned long dst; /* host byte order */
387: register struct ipif *ifp;
388: {
389: extern struct block *arp_resolve();
390: register struct block *bp1;
391: register struct queue *q;
392:
393: if(ifp->queue == 0){
394: printf("ifp but no queue in ip_ldout\n");
395: bp_free(bp);
396: return(0);
397: }
398: q = WR(ifp->queue);
399: if(q->flag & QFULL){
400: bp_free(bp);
401: ifp->oerrors++;
402: return(1);
403: }
404: if(arpcnt > 0 && (ifp->flags & IFF_ARP)){
405: bp = arp_resolve(ifp->queue, bp, dst);
406: if(bp == 0)
407: return(1);
408: }
409: MCHECK(bp);
410: while(bp){
411: bp1 = bp->next;
412: if (bp1==NULL)
413: bp->class |= S_DELIM;
414: (*q->qinfo->putp)(q, bp);
415: bp = bp1;
416: }
417: return(0);
418: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.