|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Mach Operating System
27: * Copyright (c) 1989 Carnegie-Mellon University
28: * Copyright (c) 1988 Carnegie-Mellon University
29: * Copyright (c) 1987 Carnegie-Mellon University
30: * All rights reserved. The CMU software License Agreement specifies
31: * the terms and conditions for use and redistribution.
32: */
33: /*
34: * HISTORY
35: * Revision 1.1.1.1 1997/09/30 02:44:31 wsanchez
36: * Import of kernel from umeshv/kernel
37: *
38: * 1-Mar-90 Gregg Kellogg (gk) at NeXT
39: * NeXT: Don't make the mach_net_kmsg_zone quite so big.
40: * Turn off optimization around netipc_listen().
41: *
42: * Revision 2.11 89/02/25 18:05:43 gm0w
43: * Changes for cleanup.
44: *
45: * Revision 2.10 89/01/15 16:24:27 rpd
46: * Use decl_simple_lock_data.
47: * [89/01/15 15:02:07 rpd]
48: *
49: * Revision 2.8 88/10/11 10:19:58 rpd
50: * Removed SEND_KERNEL from the msg_queue operation.
51: * Removed redundant log messages.
52: * [88/10/09 08:46:23 rpd]
53: *
54: * Changed "struct KMsg" to "struct kern_msg".
55: * Removed redundant "#if MACH_NET/#endif" wrapper.
56: * [88/10/04 07:07:58 rpd]
57: *
58: * Revision 2.7 88/10/01 21:57:33 rpd
59: * Changed msg_remote_port to msg_local_port, because that is
60: * the destination port of a copied-in message now.
61: * [88/10/01 21:30:34 rpd]
62: *
63: * Revision 2.6 88/08/24 01:51:51 mwyoung
64: * Corrected include file references.
65: * [88/08/22 22:06:23 mwyoung]
66: *
67: * 22-Aug-88 Michael Young (mwyoung) at Carnegie-Mellon University
68: * Removed ancient history.
69: *
70: * 15-Aug-88 Avadis Tevanian (avie) at NeXT
71: * Changed number of allocated messages for mach_net from 8 to 4.
72: *
73: * Revision 2.5 88/08/06 18:22:03 rpd
74: * Eliminated use of kern/mach_ipc_defs.h.
75: *
76: * Revision 2.4 88/07/20 16:38:58 rpd
77: * When queueing a message, bump current and ip_data_grams
78: * ipc_statistics counters.
79: *
80: * 18-May-88 Daniel Julin (dpj) at Carnegie-Mellon University
81: * Added another access check for mach_net_server. Only privileged
82: * users should be allowed to send packets this way, because there
83: * is little or no check against false source addresses.
84: *
85: * 6-May-88 Daniel Julin (dpj) at Carnegie-Mellon University
86: * Added an access check for netipc_listen and
87: * (from code by rds).
88: *
89: * 3-Apr-88 Michael Young (mwyoung) at Carnegie-Mellon University
90: * De-linted.
91: *
92: * 1-Feb-88 David Golub (dbg) at Carnegie-Mellon University
93: * Receive_ip_datagram is called at splnet. It must drop priority
94: * to spl0 to call the IPC routines, and raise back to splnet when
95: * it exits. NOTE that this works ONLY if this is always called
96: * from the netisr thread - it will garble interrupt handling
97: * horribly.
98: *
99: * 8-Dec-87 David Black (dlb) at Carnegie-Mellon University
100: * Removed spl check code; interrupt disabling is no longer needed
101: * because all network code runs in a thread context. Removed TT
102: * conditionals.
103: *
104: * 9-Nov-87 David Golub (dbg) at Carnegie-Mellon University
105: * Since network routines now run in a thread context, use
106: * msg_queue to send message.
107: *
108: */
109:
110: #import <mach_net.h>
111:
112: #import <sys/param.h>
113: #import <sys/systm.h>
114: #import <sys/mbuf.h>
115: #import <sys/socket.h>
116:
117: #import <net/if.h>
118: #import <net/route.h>
119:
120: #import <netinet/in.h>
121: #import <netinet/in_systm.h>
122: #import <netinet/ip.h>
123: #import <netinet/in_pcb.h>
124:
125: #import <netinet/ip.h>
126: #import <netinet/ip_var.h>
127:
128: #import <mach/mach_types.h>
129: #import <mach/mig_errors.h>
130:
131: #import <kern/zalloc.h>
132:
133: #import <sys/param.h> /* NBPG, CLBYTES, etc. */
134:
135: #import <vm/vm_kern.h> /* kernel_map */
136: #import <kern/parallel.h>
137:
138: #import <machine/spl.h>
139:
140: #if MACH_NET
141:
142: #define IP_MSG_ID 1959
143:
144: static
145: void
146: mach_net_output(
147: ipc_kmsg_t kmsg
148: )
149: {
150: struct ip_msg {
151: mach_msg_header_t header;
152: struct ip ip;
153: } *ip_msg = (struct ip_msg *) &kmsg->ikm_header;
154:
155: struct mbuf *top;
156: register struct mbuf **mp;
157: register int size;
158: register caddr_t cp;
159: static struct route cached_route = { 0 };
160:
161: if (!(current_proc()->p_ucred->cr_uid == 0))
162: return;
163:
164: kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
165: /*
166: * Only accept simple messages large enough
167: * to contain an IP header.
168: */
169:
170: if ((ip_msg->header.msgh_bits & MACH_MSGH_BITS_COMPLEX) ||
171: (ip_msg->header.msgh_size < sizeof (struct ip_msg)))
172: return;
173:
174: /*
175: * Check that user has supplied a reasonable IP datagram length.
176: */
177:
178: size = ip_msg->ip.ip_len;
179: if ((size <= sizeof(struct ip)) || (size > (ip_msg->header.msgh_size - sizeof(mach_msg_header_t))))
180: return;
181:
182: /*
183: * Remainder of this procedure must execute on master.
184: */
185: unix_master();
186:
187: /*
188: * Copy data to mbuf chain.
189: * This loop is similar to those in sosend() (in sys/uipc_socket.c)
190: * and if_ubaget() (in vaxif/if_uba.c).
191: */
192: top = 0;
193: mp = ⊤
194: cp = (caddr_t) &ip_msg->ip;
195: while (size > 0) {
196: register struct mbuf *m;
197: register unsigned int len;
198:
199: MGET(m, M_WAIT, MT_DATA);
200: if (m == 0) {
201: m_freem(top);
202: unix_release();
203: return;
204: }
205: if (size >= NBPG/2) { /* heuristic */
206: MCLGET(m);
207: if (m->m_len != MCLBYTES)
208: m->m_len = len = MIN(MLEN, size);
209: else
210: m->m_len = len = MIN(MCLBYTES, size);
211: } else
212: m->m_len = len = MIN(MLEN, size);
213:
214: bcopy(cp, mtod(m, caddr_t), len);
215: cp += len;
216: size -= len;
217: *mp = m;
218: mp = &m->m_next;
219: }
220:
221: /*
222: * Use cached route if the destination address is the same.
223: * Otherwise, zero the route so that ip_output() will find a new one.
224: * The use of the cached route decreases the total time to send a datagram
225: * by as much as 40%.
226: */
227: if (((struct sockaddr_in *) &cached_route.ro_dst)->sin_addr.s_addr
228: != ip_msg->ip.ip_dst.s_addr) {
229: if (cached_route.ro_rt)
230: RTFREE(cached_route.ro_rt);
231: cached_route.ro_rt = 0;
232: }
233:
234: /*
235: * Send the mbuf chain.
236: * We use the IP_FORWARDING option because
237: * the user supplies a complete IP header.
238: * Deallocation of the mbuf chain is handled by ip_output().
239: */
240: if (ip_output(top, (struct mbuf *)0,
241: &cached_route, (IP_FORWARDING|IP_ALLOWBROADCAST)) != 0) {
242: unix_release();
243: return;
244: }
245: unix_release();
246: return;
247: }
248:
249: boolean_t
250: netipc_msg_send(
251: ipc_kmsg_t kmsg
252: )
253: {
254: if (kmsg->ikm_header.msgh_id != IP_MSG_ID)
255: return (FALSE);
256:
257: mach_net_output(kmsg);
258:
259: return (TRUE);
260: }
261:
262:
263: /*
264: * Data structures and associated routines
265: * to register IPC ports for incoming datagrams.
266: *
267: * Listeners are organized into buckets by the (IP) protocol number
268: * for which they are listening. Within a bucket, the listeners
269: * are linked in a list that is maintained by a move-to-front strategy.
270: *
271: * A zero entry in any of the source or destination
272: * fields indicates a wildcard that matches the corresponding field
273: * in any incoming datagram.
274: *
275: * The lock field is used for mutual exclusion when adding listeners.
276: * Lookups do not require synchronization because the ipc_port field
277: * (used to tell whether a listener is present) is always updated last,
278: * in a single operation.
279: *
280: * The routine to add and remove listeners are called by the user
281: * via a Matchmaker interface. Remove_listener() is also called by
282: * port_deallocate().
283: */
284:
285: struct lbucket {
286: decl_simple_lock_data(, lock)
287: struct listener *head;
288: };
289:
290: #define LBHSZ 16 /* kept small -- not many protocols */
291: #define LBHASH(protocol) ((protocol) % LBHSZ)
292: struct lbucket listeners[LBHSZ]; /* indexed by hashed protocol */
293:
294: struct listener {
295: struct listener *next;
296: long src_addr;
297: long dst_addr;
298: unsigned short src_port;
299: unsigned short dst_port;
300: port_t ipc_port;
301: };
302:
303: #define LISTENER_MAX 100
304: #define LISTENER_CHUNK 1
305:
306: zone_t listener_zone;
307:
308: #define FOR_EACH_BUCKET(b) for((b)=listeners; (b) < &listeners[LBHSZ]; (b)++)
309: #define FOR_EACH_LISTENER(lp,b) for((lp)=(b)->head; (lp) != 0; (lp)=(lp)->next)
310: #define LOCK_BUCKET(b, ipl) { ipl = splnet(); simple_lock(&(b)->lock); }
311: #define UNLOCK_BUCKET(b, ipl) { simple_unlock(&(b)->lock); splx(ipl); }
312:
313: #endif
314:
315: /*
316: * Register a listener.
317: * No checking is done to prevent conflict with existing listeners.
318: */
319: /*ARGSUSED*/
320: #if m68k
321: /*
322: * Don't know why this pragme is here. My guess is an old M68K
323: * compiler bug which has probably been fixed. -PFK
324: */
325: #pragma CC_OPT_OFF
326: #endif m68k
327: kern_return_t netipc_listen(server_port, _src_addr, _dst_addr,
328: _src_port, _dst_port, _protocol, ipc_port)
329: port_t server_port; /* unused */
330: int _src_addr;
331: int _dst_addr;
332: int _src_port;
333: int _dst_port;
334: int _protocol;
335: port_t ipc_port;
336: {
337: #if MACH_NET
338: register struct listener *lp;
339: register struct lbucket *b;
340: int ipl;
341:
342: long src_addr = _src_addr;
343: long dst_addr = _dst_addr;
344: unsigned short src_port = _src_port;
345: unsigned short dst_port = _dst_port;
346: u_char protocol = _protocol;
347:
348: if (!(current_proc()->p_ucred->cr_uid == 0))
349: return(KERN_NO_ACCESS);
350:
351: if (ipc_port == PORT_NULL)
352: return(KERN_INVALID_ARGUMENT);
353: lp = (struct listener *) zalloc(listener_zone);
354: lp->src_addr = src_addr;
355: lp->src_port = src_port;
356: lp->dst_addr = dst_addr;
357: lp->dst_port = dst_port;
358: ipc_port_reference((ipc_port_t)lp->ipc_port = ipc_port);
359: b = &listeners[LBHASH(protocol)];
360: LOCK_BUCKET(b, ipl);
361: lp->next = b->head;
362: b->head = lp;
363: UNLOCK_BUCKET(b, ipl);
364: ipc_kobject_set((ipc_port_t)ipc_port, 0, IKOT_NETIPC);
365: return(KERN_SUCCESS);
366: #else
367: return (KERN_FAILURE);
368: #endif
369: }
370: #if m68k
371: /*
372: * See comment at beginning of routine.
373: */
374: #pragma CC_OPT_RESTORE
375: #endif m68k
376:
377: /*
378: * Remove all listeners with the specified port.
379: */
380: /*ARGSUSED*/
381: kern_return_t netipc_ignore(server_port, ipc_port)
382: port_t server_port; /* unused */
383: register port_t ipc_port;
384: {
385: #if MACH_NET
386: register struct lbucket *b;
387: register struct listener *prev, *lp;
388: kern_return_t result = KERN_FAILURE;
389: int ipl;
390:
391: if (ipc_port == PORT_NULL)
392: return KERN_INVALID_ARGUMENT;
393: FOR_EACH_BUCKET (b) {
394: LOCK_BUCKET(b, ipl);
395: prev = b->head;
396: FOR_EACH_LISTENER (lp, b) {
397: if (lp->ipc_port == ipc_port) {
398: result = KERN_SUCCESS;
399: if (lp == b->head) {
400: b->head = lp->next;
401: zfree(listener_zone, (vm_offset_t) lp);
402: if ((prev = lp = b->head) == 0)
403: break;
404: } else {
405: prev->next = lp->next;
406: zfree(listener_zone, (vm_offset_t) lp);
407: lp = prev;
408: }
409: ipc_port_release((ipc_port_t)ipc_port);
410: }
411: else {
412: prev = lp;
413: }
414: }
415: UNLOCK_BUCKET(b, ipl);
416: }
417: return(result);
418: #else
419: return (KERN_FAILURE);
420: #endif
421: }
422:
423: #if MACH_NET
424: /*
425: * Find a listener for the given source, destination, and protocol.
426: */
427: port_t find_listener(src_addr, src_port, dst_addr, dst_port, protocol)
428: u_long src_addr;
429: u_short src_port;
430: u_long dst_addr;
431: u_short dst_port;
432: u_char protocol;
433: {
434: register struct lbucket *b;
435: register struct listener *prev, *lp;
436:
437: #define ADDR_MATCH(lp, addr) ((lp)->addr==INADDR_ANY || (lp)->addr==(addr))
438: #define PORT_MATCH(lp, port) ((lp)->port==0 || (lp)->port ==(port))
439:
440: b = &listeners[LBHASH(protocol)];
441: prev = b->head;
442: FOR_EACH_LISTENER(lp, b) {
443: /*
444: * The following tests should be ordered
445: * in increasing likelihood of success.
446: */
447: if (PORT_MATCH(lp, dst_port) &&
448: PORT_MATCH(lp, src_port) &&
449: ADDR_MATCH(lp, src_addr) &&
450: ADDR_MATCH(lp, dst_addr)) {
451: if (lp != b->head) {
452: /* move to front */
453: prev->next = lp->next;
454: lp->next = b->head;
455: b->head = lp;
456: }
457: return(lp->ipc_port);
458: } else
459: prev = lp;
460: }
461: return(PORT_NULL);
462: }
463:
464: /*
465: * IP header plus source and destination ports.
466: * Common to both UDP datagrams and TCP segments.
467: */
468: struct ip_plus_ports {
469: struct ip ip_header;
470: u_short src_port;
471: u_short dst_port;
472: };
473:
474: /*
475: * Skeletal IPC message header for fast initialization.
476: */
477: static mach_msg_header_t ip_msg_template;
478:
479: #define MACH_NET_MSG_SIZE_MAX 2048
480: zone_t mach_net_kmsg_zone;
481:
482: void mach_net_init()
483: {
484: register struct lbucket *b;
485: vm_offset_t zone_data;
486:
487: listener_zone = zinit(
488: sizeof(struct listener),
489: LISTENER_MAX * sizeof(struct listener),
490: LISTENER_CHUNK * sizeof(struct listener),
491: FALSE,
492: "net listener zone"
493: );
494: ip_msg_template.msgh_bits =
495: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0) |
496: MACH_MSGH_BITS_OLD_FORMAT;
497: ip_msg_template.msgh_size = MACH_NET_MSG_SIZE_MAX - IKM_OVERHEAD;
498: ip_msg_template.msgh_remote_port = MACH_PORT_NULL;
499: ip_msg_template.msgh_local_port = MACH_PORT_NULL;
500: ip_msg_template.msgh_id = IP_MSG_ID;
501: FOR_EACH_BUCKET (b) {
502: simple_lock_init(&b->lock);
503: }
504:
505: /*
506: * Create and allocate some space for our private kmsg zone.
507: */
508: mach_net_kmsg_zone = zinit(MACH_NET_MSG_SIZE_MAX, 4 * MACH_NET_MSG_SIZE_MAX,
509: MACH_NET_MSG_SIZE_MAX, FALSE, "mach_net messages");
510: zchange(mach_net_kmsg_zone, FALSE, FALSE, FALSE, FALSE);
511: (void) kmem_alloc_wired(kernel_map,
512: &zone_data, 4 * MACH_NET_MSG_SIZE_MAX);
513: zcram(mach_net_kmsg_zone, zone_data,
514: 4 * MACH_NET_MSG_SIZE_MAX);
515: }
516:
517: void
518: netipc_msg_release(
519: ipc_kmsg_t kmsg
520: )
521: {
522: zfree(mach_net_kmsg_zone, kmsg);
523: }
524:
525: /*
526: * This routine is called from ipintr() (in netinet/ip_input.c)
527: * to filter incoming datagrams.
528: * Returns TRUE if a listener was found (or the packet was dropped),
529: * FALSE if the datagram should be passed on to socket code.
530: *
531: * This routine is always called at splnet, and must return that way.
532: * However, it must drop interrupt level to spl0 to use any of the MACH_IPC
533: * routines (which do not block interrupts).
534: */
535: boolean_t receive_ip_datagram(mp)
536: struct mbuf **mp;
537: {
538: register struct mbuf *m = *mp;
539: register struct ip_plus_ports *ipp;
540: port_t port;
541: ipc_kmsg_t kmsg;
542: register caddr_t cp;
543: int space;
544:
545: /*
546: * Get IP header and ports (for UDP or TCP) together in first mbuf.
547: * Note: IP leaves IP header in first mbuf.
548: */
549: ipp = mtod(m, struct ip_plus_ports *);
550: if (ipp->ip_header.ip_hl > (sizeof (struct ip) >> 2))
551: ip_stripoptions(&ipp->ip_header, (struct mbuf *)0);
552: if (m->m_off > MMAXOFF || m->m_len < sizeof(struct ip_plus_ports)) {
553: if ((*mp = m = m_pullup(m, sizeof(struct ip_plus_ports))) == 0)
554: return(TRUE);
555: ipp = mtod(m, struct ip_plus_ports *);
556: }
557:
558: port = find_listener(
559: ipp->ip_header.ip_src.s_addr, ipp->src_port, /* source addr and port */
560: ipp->ip_header.ip_dst.s_addr, ipp->dst_port, /* dest addr and port */
561: ipp->ip_header.ip_p); /* protocol */
562:
563: if (port == PORT_NULL) {
564: /*
565: * No one is listening for this datagram.
566: * Pass it on to the socket code.
567: */
568: return(FALSE);
569: }
570:
571: /*
572: * Drop interrupt level to use MACH_IPC.
573: */
574: (void) spl0();
575:
576: if ((kmsg = (ipc_kmsg_t) zget(mach_net_kmsg_zone)) == IKM_NULL) {
577: /*
578: * Could not get a buffer - drop the datagram on the floor.
579: printf("receive_ip_datagram: kern_msg_allocate returns null.\n");
580: */
581: m_freem(m);
582:
583: /*
584: * Raise interrupt level to return.
585: */
586: (void) splnet();
587: return(TRUE);
588: }
589: ikm_init_special(kmsg, IKM_SIZE_NETIPC);
590:
591: /*
592: * Undo changes to IP header made by ipintr()
593: * before we were called. Unfortunately, the
594: * type of service field is gone for good.
595: */
596: ipp->ip_header.ip_len += (ipp->ip_header.ip_hl << 2);
597: ipp->ip_header.ip_off >>= 3;
598:
599: /*
600: * Copy mbuf chain to kmsg buffer.
601: */
602: space = MACH_NET_MSG_SIZE_MAX - sizeof (struct ipc_kmsg);
603: cp = (caddr_t)(&kmsg->ikm_header + 1);
604: while (m && space > 0) {
605: register unsigned int len;
606:
607: len = MIN(m->m_len, space);
608: bcopy(mtod(m, caddr_t), cp, len);
609: cp += len;
610: space -= len;
611: m = m_free(m);
612: }
613: kmsg->ikm_delta = space;
614: space &= ~3;
615: kmsg->ikm_delta = space - kmsg->ikm_delta;
616: /*
617: * Fill in message header and deliver it.
618: */
619: kmsg->ikm_header = ip_msg_template;
620: kmsg->ikm_header.msgh_size -= space;
621: kmsg->ikm_header.msgh_remote_port = port;
622:
623: ipc_port_reference((ipc_port_t)port);
624: ipc_mqueue_send_always(kmsg);
625:
626: /*
627: * Raise interrupt level to return.
628: */
629: (void) splnet();
630: return(TRUE);
631: }
632: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.