|
|
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: iposrv(q)
128: register struct queue *q;
129: {
130: struct x{
131: unsigned int in;
132: unsigned char en[6];
133: } *xp;
134: register struct block *bp;
135: register struct ipif *ifp;
136: register long *intp;
137:
138: ifp = (struct ipif *)q->ptr;
139: while(bp = getq(q)){
140: switch (bp->type) {
141: case M_IOCTL:
142: switch(stiocom(bp)){
143: case IPIOARP:
144: ifp->flags |= IFF_ARP;
145: bp->type = M_IOCACK;
146: bp->wptr = bp->rptr;
147: qreply(q, bp);
148: break;
149: case IPIORESOLVE:
150: xp = (struct x *)(stiodata(bp));
151: if (arpcnt > 0)
152: arp_install(xp->in, xp->en);
153: bp->wptr = bp->rptr;
154: bp->type = M_IOCACK;
155: qreply(q, bp);
156: break;
157: case IPIOHOST:
158: intp = (long *)(stiodata(bp));
159: ifp->that = *intp;
160: ifp->flags |= IFF_HOST;
161: ifp->mask = 0xffffffff;
162: ifp->broadcast = 0;
163: ip_ifinsert(ifp);
164: bp->type = M_IOCACK;
165: qreply(q, bp);
166: ip_doroute(ifp->that, 0);
167: break;
168: case IPIOMTU:
169: intp = (long *)(stiodata(bp));
170: ifp->mtu = *intp;
171: bp->type = M_IOCACK;
172: qreply(q, bp);
173: break;
174: case IPIONET:
175: intp = (long *)(stiodata(bp));
176: ifp->that = *intp;
177: ifp->mask = IN_CLASS_NMASK(ifp->that);
178: ifp->broadcast = ifp->that|~ifp->mask;
179: ip_ifinsert(ifp);
180: ifp->flags &= (~IFF_HOST);
181: bp->type = M_IOCACK;
182: qreply(q, bp);
183: ip_doroute(ifp->that, 0);
184: break;
185: case IPIOMASK:
186: intp = (long *)(stiodata(bp));
187: /*
188: * the mask has to be a superset of the class mask
189: */
190: if((*intp&ifp->mask)==ifp->mask)
191: ifp->mask = *intp;
192: ifp->broadcast = ifp->that|~ifp->mask;
193: ip_ifinsert(ifp);
194: bp->type = M_IOCACK;
195: qreply(q, bp);
196: break;
197: case IPIOLOCAL:
198: intp = (long *)(stiodata(bp));
199: ifp->thishost = *intp;
200: bp->type = M_IOCACK;
201: qreply(q, bp);
202: break;
203: default:
204: (*q->next->qinfo->putp)(q->next, bp);
205: break;
206: }
207: continue;
208:
209: default:
210: if (q->next->flag & QFULL) {
211: putbq(q, bp);
212: return;
213: }
214: if(bp->class&S_DELIM)
215: ifp->opackets++;
216: (*q->next->qinfo->putp)(q->next, bp);
217: continue;
218: }
219: }
220: }
221:
222: /*
223: * Insert an entry into ipifsort. Entries are sorted by mask length,
224: * longest first.
225: */
226: ip_ifinsert(ifp)
227: struct ipif *ifp;
228: {
229: int s = spl6();
230: register int i, j;
231:
232: /*
233: * First try to remove it. This may be a reordering.
234: */
235: ip_ifremove(ifp);
236:
237: /*
238: * Now (re)insert it in the correct place
239: */
240: for(i=0; i<ipcnt; i++){
241: if(ipifsort[i]==ifp)
242: panic("ip_ifinsert duplcate");
243: if(ipifsort[i]==0 || (ifp->mask & ipifsort[i]->mask)!=ifp->mask)
244: break;
245: }
246: if(i>=ipcnt)
247: panic("ip_ifinsert no room");
248: for(j=ipcnt-1; j>i; j--)
249: ipifsort[j] = ipifsort[j-1];
250: ipifsort[i] = ifp;
251: splx(s);
252: }
253:
254: /*
255: * Remove an entry from ipifsort. Compress list to fill gap.
256: * It may not already be there.
257: */
258: ip_ifremove(ifp)
259: struct ipif *ifp;
260: {
261: int s = spl6();
262: register int i;
263:
264: for(i=0; i<ipcnt; i++)
265: if(ipifsort[i]==ifp)
266: break;
267: if(i<ipcnt){
268: for(; i<ipcnt-1; i++)
269: ipifsort[i] = ipifsort[i+1];
270: ipifsort[i] = 0;
271: }
272: splx(s);
273: }
274:
275: /*
276: * Find the interface to use for sending messages to `dst'.
277: * ipifsort is sorted into priority order;
278: * first match found is best.
279: */
280: struct ipif *
281: ip_ifonnetof(dst)
282: register unsigned long dst;
283: {
284: extern ipprintfs;
285: register struct ipif *ifp;
286: register int i;
287: register int Ipcnt = ipcnt; /* optimization */
288:
289: /*
290: * first look for a match against addresses
291: */
292: for(i=0; i < Ipcnt; i++){
293: if((ifp = ipifsort[i])==0)
294: break;
295: if(ifp->flags & IFF_UP)
296: if((dst & ifp->mask) == ifp->that)
297: return(ifp);
298: }
299:
300: /*
301: * now try to match against the local host's addresses
302: */
303: ifp = ip_ifwithaddr(dst);
304: if(ifp)
305: return(ifp);
306:
307: /*
308: * no match
309: */
310: if(ipprintfs)
311: printf("ifonnetof %x?\n", dst);
312: return(0);
313: }
314:
315: /*
316: * return the interface for which addr is a local address. if non
317: * such exists, return 0.
318: *
319: * This routine assumes that ipifsort is sorted in priority order
320: * so that the first match found is the best match.
321: */
322: struct ipif *
323: ip_ifwithaddr(addr)
324: register u_long addr;
325: {
326: register int i;
327: register u_long net, mask;
328: register struct ipif *ifp;
329: register int Ipcnt = ipcnt; /* optimization */
330:
331: net = in_netof(addr);
332: for(i=0; i < Ipcnt; i++){
333: if((ifp = ipifsort[i])==0)
334: break;
335: if(ifp->flags & IFF_UP) {
336:
337: /* address of this host */
338: if(addr == ifp->thishost)
339: return(ifp);
340:
341: /* standard IP broadcast address */
342: if(addr == ifp->broadcast)
343: return(ifp);
344:
345: /* old style BSD IP broadcast address */
346: if(addr == in_netof(ifp->thishost))
347: return(ifp);
348:
349: /* address on a network simulated by this node */
350: if(net == ifp->thishost)
351: return(ifp);
352:
353: /* finally, try unsubnetted broadcast addresses */
354: mask = IN_CLASS_NMASK(ifp->thishost);
355: if((mask&ifp->thishost | ~mask) == addr)
356: return(ifp);
357:
358: /* finally, try unsubnetted broadcast addresses */
359: if((mask&ifp->thishost) == addr)
360: return(ifp);
361: }
362: }
363: return(0);
364: }
365:
366: /*
367: * output list bp onto interface ifp
368: * for better buffering, put it on ip's queue first;
369: * iposrv will dribble it out as there's room
370: */
371: ip_ldout(bp, dst, ifp)
372: register struct block *bp;
373: unsigned long dst; /* host byte order */
374: register struct ipif *ifp;
375: {
376: extern struct block *arp_resolve();
377: register struct block *bp1;
378: register struct queue *q;
379:
380: if(ifp->queue == 0){
381: printf("ifp but no queue in ip_ldout\n");
382: bp_free(bp);
383: return(0);
384: }
385: q = WR(ifp->queue);
386: if(q->flag & QFULL){
387: bp_free(bp);
388: ifp->oerrors++;
389: return(1);
390: }
391: if(arpcnt > 0 && (ifp->flags & IFF_ARP)){
392: bp = arp_resolve(ifp->queue, bp, dst);
393: if(bp == 0)
394: return(1);
395: }
396: MCHECK(bp);
397: while(bp){
398: bp1 = bp->next;
399: if (bp1==NULL)
400: bp->class |= S_DELIM;
401: (*q->qinfo->putp)(q, bp);
402: bp = bp1;
403: }
404: return(0);
405: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.