| 1 | /* |
| 2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. |
| 3 | * |
| 4 | * @APPLE_LICENSE_HEADER_START@ |
| 5 | * |
| 6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
| 7 | * |
| 8 | * This file contains Original Code and/or Modifications of Original Code |
| 9 | * as defined in and that are subject to the Apple Public Source License |
| 10 | * Version 2.0 (the 'License'). You may not use this file except in |
| 11 | * compliance with the License. Please obtain a copy of the License at |
| 12 | * http://www.opensource.apple.com/apsl/ and read it before using this |
| 13 | * file. |
| 14 | * |
| 15 | * The Original Code and all software distributed under the License are |
| 16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER |
| 17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
| 18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, |
| 19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
| 20 | * Please see the License for the specific language governing rights and |
| 21 | * limitations under the License. |
| 22 | * |
| 23 | * @APPLE_LICENSE_HEADER_END@ |
| 24 | */ |
| 25 | /* |
| 26 | * Copyright 1994 Apple Computer, Inc. |
| 27 | * All Rights Reserved. |
| 28 | * |
| 29 | * Tuyen A. Nguyen. (December 5, 1994) |
| 30 | * Modified, March 17, 1997 by Tuyen Nguyen for MacOSX. |
| 31 | */ |
| 32 | |
| 33 | #include <sys/errno.h> |
| 34 | #include <sys/types.h> |
| 35 | #include <sys/param.h> |
| 36 | #include <machine/spl.h> |
| 37 | #include <sys/systm.h> |
| 38 | #include <sys/kernel.h> |
| 39 | #include <sys/proc.h> |
| 40 | #include <sys/filedesc.h> |
| 41 | #include <sys/fcntl.h> |
| 42 | #include <sys/mbuf.h> |
| 43 | #include <sys/ioctl.h> |
| 44 | #include <sys/malloc.h> |
| 45 | #include <sys/socket.h> |
| 46 | #include <sys/socketvar.h> |
| 47 | #include <sys/sockio.h> |
| 48 | |
| 49 | #include <net/if.h> |
| 50 | #include <net/if_types.h> |
| 51 | #include <net/if_dl.h> |
| 52 | #include <net/ethernet.h> |
| 53 | |
| 54 | #include <netat/sysglue.h> |
| 55 | #include <netat/appletalk.h> |
| 56 | #include <netat/at_pcb.h> |
| 57 | #include <netat/at_var.h> |
| 58 | #include <netat/ddp.h> |
| 59 | #include <netat/at_aarp.h> |
| 60 | #include <netat/at_pat.h> |
| 61 | #include <netat/debug.h> |
| 62 | |
| 63 | #define DSAP_SNAP 0xaa |
| 64 | |
| 65 | extern void gref_init(), atp_init(), atp_link(), atp_unlink(); |
| 66 | |
| 67 | extern int adspInited; |
| 68 | |
| 69 | static llc_header_t snap_hdr_at = SNAP_HDR_AT; |
| 70 | static llc_header_t snap_hdr_aarp = SNAP_HDR_AARP; |
| 71 | static unsigned char snap_proto_ddp[5] = SNAP_PROTO_AT; |
| 72 | static unsigned char snap_proto_aarp[5] = SNAP_PROTO_AARP; |
| 73 | |
| 74 | int pktsIn, pktsOut; |
| 75 | |
| 76 | struct ifqueue atalkintrq; /* appletalk and aarp packet input queue */ |
| 77 | |
| 78 | short appletalk_inited = 0; |
| 79 | |
| 80 | extern atlock_t |
| 81 | ddpall_lock, ddpinp_lock, arpinp_lock, refall_lock, nve_lock, |
| 82 | aspall_lock, asptmo_lock, atpall_lock, atptmo_lock, atpgen_lock; |
| 83 | |
| 84 | extern int (*sys_ATsocket )(), (*sys_ATgetmsg)(), (*sys_ATputmsg)(); |
| 85 | extern int (*sys_ATPsndreq)(), (*sys_ATPsndrsp)(); |
| 86 | extern int (*sys_ATPgetreq)(), (*sys_ATPgetrsp)(); |
| 87 | |
| 88 | void atalk_load() |
| 89 | { |
| 90 | extern int _ATsocket(), _ATgetmsg(), _ATputmsg(); |
| 91 | extern int _ATPsndreq(), _ATPsndrsp(), _ATPgetreq(), _ATPgetrsp(); |
| 92 | |
| 93 | sys_ATsocket = _ATsocket; |
| 94 | sys_ATgetmsg = _ATgetmsg; |
| 95 | sys_ATputmsg = _ATputmsg; |
| 96 | sys_ATPsndreq = _ATPsndreq; |
| 97 | sys_ATPsndrsp = _ATPsndrsp; |
| 98 | sys_ATPgetreq = _ATPgetreq; |
| 99 | sys_ATPgetrsp = _ATPgetrsp; |
| 100 | |
| 101 | ATLOCKINIT(ddpall_lock); |
| 102 | ATLOCKINIT(ddpinp_lock); |
| 103 | ATLOCKINIT(arpinp_lock); |
| 104 | ATLOCKINIT(refall_lock); |
| 105 | ATLOCKINIT(aspall_lock); |
| 106 | ATLOCKINIT(asptmo_lock); |
| 107 | ATLOCKINIT(atpall_lock); |
| 108 | ATLOCKINIT(atptmo_lock); |
| 109 | ATLOCKINIT(atpgen_lock); |
| 110 | ATLOCKINIT(nve_lock); |
| 111 | |
| 112 | atp_init(); |
| 113 | atp_link(); |
| 114 | adspInited = 0; |
| 115 | |
| 116 | /* adsp_init(); |
| 117 | for 2225395 |
| 118 | this happens in adsp_open and is undone on ADSP_UNLINK |
| 119 | */ |
| 120 | } /* atalk_load */ |
| 121 | |
| 122 | /* Undo everything atalk_load() did. */ |
| 123 | void atalk_unload() /* not currently used */ |
| 124 | { |
| 125 | extern gbuf_t *scb_resource_m; |
| 126 | extern gbuf_t *atp_resource_m; |
| 127 | |
| 128 | sys_ATsocket = 0; |
| 129 | sys_ATgetmsg = 0; |
| 130 | sys_ATputmsg = 0; |
| 131 | sys_ATPsndreq = 0; |
| 132 | sys_ATPsndrsp = 0; |
| 133 | sys_ATPgetreq = 0; |
| 134 | sys_ATPgetrsp = 0; |
| 135 | |
| 136 | atp_unlink(); |
| 137 | |
| 138 | #ifdef NOT_YET |
| 139 | if (scb_resource_m) { |
| 140 | gbuf_freem(scb_resource_m); |
| 141 | scb_resource_m = 0; |
| 142 | scb_free_list = 0; |
| 143 | } |
| 144 | /* allocated in atp_trans_alloc() */ |
| 145 | if (atp_resource_m) { |
| 146 | gbuf_freem(atp_resource_m); |
| 147 | atp_resource_m = 0; |
| 148 | atp_trans_free_list = 0; |
| 149 | } |
| 150 | #endif |
| 151 | |
| 152 | appletalk_inited = 0; |
| 153 | } /* atalk_unload */ |
| 154 | |
| 155 | void appletalk_hack_start() |
| 156 | { |
| 157 | if (!appletalk_inited) { |
| 158 | atalk_load(); |
| 159 | atalkintrq.ifq_maxlen = IFQ_MAXLEN; |
| 160 | appletalk_inited = 1; |
| 161 | } |
| 162 | } /* appletalk_hack_start */ |
| 163 | |
| 164 | int pat_output(patp, mlist, dst_addr, type) |
| 165 | at_ifaddr_t *patp; |
| 166 | struct mbuf *mlist; /* packet chain */ |
| 167 | unsigned char *dst_addr; |
| 168 | int type; |
| 169 | { |
| 170 | struct mbuf *m, *m1; |
| 171 | llc_header_t *llc_header; |
| 172 | struct sockaddr dst; |
| 173 | |
| 174 | if (! patp->aa_ifp) { |
| 175 | for (m = mlist; m; m = mlist) { |
| 176 | mlist = m->m_nextpkt; |
| 177 | m->m_nextpkt = 0; |
| 178 | m_freem(m); |
| 179 | } |
| 180 | return ENOTREADY; |
| 181 | } |
| 182 | |
| 183 | /* this is for ether_output */ |
| 184 | dst.sa_family = AF_APPLETALK; |
| 185 | dst.sa_len = 2 + sizeof(struct etalk_addr); |
| 186 | bcopy (dst_addr, &dst.sa_data[0], sizeof(struct etalk_addr)); |
| 187 | |
| 188 | /* packet chains are used on output and can be tested using aufs */ |
| 189 | for (m = mlist; m; m = mlist) { |
| 190 | mlist = m->m_nextpkt; |
| 191 | m->m_nextpkt = 0; |
| 192 | |
| 193 | M_PREPEND(m, sizeof(llc_header_t), M_DONTWAIT); |
| 194 | if (m == 0) { |
| 195 | continue; |
| 196 | } |
| 197 | |
| 198 | llc_header = mtod(m, llc_header_t *); |
| 199 | *llc_header = |
| 200 | (type == AARP_AT_TYPE) ? snap_hdr_aarp : snap_hdr_at; |
| 201 | |
| 202 | for (m->m_pkthdr.len = 0, m1 = m; m1; m1 = m1->m_next) |
| 203 | m->m_pkthdr.len += m1->m_len; |
| 204 | m->m_pkthdr.rcvif = 0; |
| 205 | |
| 206 | /* *** Note: AT is sending out mbufs of type MSG_DATA, |
| 207 | not MT_DATA. *** */ |
| 208 | #ifdef APPLETALK_DEBUG |
| 209 | if (m->m_next && |
| 210 | !((m->m_next)->m_flags & M_EXT)) |
| 211 | kprintf("po: mlen= %d, m2len= %d\n", m->m_len, |
| 212 | (m->m_next)->m_len); |
| 213 | #endif |
| 214 | dlil_output(patp->at_dl_tag, m, NULL, &dst, 0); |
| 215 | |
| 216 | pktsOut++; |
| 217 | } |
| 218 | |
| 219 | return 0; |
| 220 | } /* pat_output */ |
| 221 | |
| 222 | void atalkintr() |
| 223 | { |
| 224 | struct mbuf *m, *m1, *mlist = NULL; |
| 225 | struct ifnet *ifp; |
| 226 | int s; |
| 227 | llc_header_t *llc_header; |
| 228 | at_ifaddr_t *ifID; |
| 229 | char src[6]; |
| 230 | enet_header_t *enet_header; |
| 231 | |
| 232 | next: |
| 233 | s = splimp(); |
| 234 | IF_DEQUEUE(&atalkintrq, m); |
| 235 | splx(s); |
| 236 | |
| 237 | if (m == 0) |
| 238 | return; |
| 239 | |
| 240 | for ( ; m ; m = mlist) { |
| 241 | mlist = m->m_nextpkt; |
| 242 | #ifdef APPLETALK_DEBUG |
| 243 | /* packet chains are not yet in use on input */ |
| 244 | if (mlist) kprintf("atalkintr: packet chain\n"); |
| 245 | #endif |
| 246 | m->m_nextpkt = 0; |
| 247 | |
| 248 | if (!appletalk_inited) { |
| 249 | m_freem(m); |
| 250 | continue; |
| 251 | } |
| 252 | |
| 253 | if ((m->m_flags & M_PKTHDR) == 0) { |
| 254 | #ifdef APPLETALK_DEBUG |
| 255 | kprintf("atalkintr: no HDR on packet received"); |
| 256 | #endif |
| 257 | m_freem(m); |
| 258 | continue; |
| 259 | } |
| 260 | |
| 261 | /* make sure the interface this packet was received on is configured |
| 262 | for AppleTalk */ |
| 263 | ifp = m->m_pkthdr.rcvif; |
| 264 | TAILQ_FOREACH(ifID, &at_ifQueueHd, aa_link) { |
| 265 | if (ifID->aa_ifp && (ifID->aa_ifp == ifp)) |
| 266 | break; |
| 267 | } |
| 268 | /* if we didn't find a matching interface */ |
| 269 | if (!ifID) { |
| 270 | m_freem(m); |
| 271 | continue; /* was EAFNOSUPPORT */ |
| 272 | } |
| 273 | |
| 274 | /* make sure the entire packet header is in the current mbuf */ |
| 275 | if (m->m_len < ENET_LLC_SIZE && |
| 276 | (m = m_pullup(m, ENET_LLC_SIZE)) == 0) { |
| 277 | #ifdef APPLETALK_DEBUG |
| 278 | kprintf("atalkintr: packet too small\n"); |
| 279 | #endif |
| 280 | m_freem(m); |
| 281 | continue; |
| 282 | } |
| 283 | enet_header = mtod(m, enet_header_t *); |
| 284 | |
| 285 | /* Ignore multicast packets from local station */ |
| 286 | /* *** Note: code for IFTYPE_TOKENTALK may be needed here. *** */ |
| 287 | if (ifID->aa_ifp->if_type == IFT_ETHER) { |
| 288 | bcopy((char *)enet_header->src, src, sizeof(src)); |
| 289 | |
| 290 | #ifdef COMMENT /* In order to receive packets from the Blue Box, we cannot |
| 291 | reject packets whose source address matches our local address. |
| 292 | */ |
| 293 | if ((enet_header->dst[0] & 1) && |
| 294 | (bcmp(src, ifID->xaddr, sizeof(src)) == 0)) { |
| 295 | /* Packet rejected: think it's a local mcast. */ |
| 296 | m_freem(m); |
| 297 | continue; /* was EAFNOSUPPORT */ |
| 298 | } |
| 299 | #endif /* COMMENT */ |
| 300 | |
| 301 | llc_header = (llc_header_t *)(enet_header+1); |
| 302 | |
| 303 | /* advance the mbuf pointers past the ethernet header */ |
| 304 | m->m_data += ENET_LLC_SIZE; |
| 305 | m->m_len -= ENET_LLC_SIZE; |
| 306 | |
| 307 | pktsIn++; |
| 308 | |
| 309 | if (LLC_PROTO_EQUAL(llc_header->protocol,snap_proto_aarp)) { |
| 310 | (void)aarp_rcv_pkt(mtod(m, aarp_pkt_t *), ifID); |
| 311 | m_freem(m); |
| 312 | } |
| 313 | else if (LLC_PROTO_EQUAL(llc_header->protocol, snap_proto_ddp)) { |
| 314 | /* if we're a router take all pkts */ |
| 315 | if (!ROUTING_MODE) { |
| 316 | if (aarp_chk_addr(mtod(m, at_ddp_t *), ifID) |
| 317 | == AARP_ERR_NOT_OURS) { |
| 318 | #ifdef APPLETALK_DEBUG |
| 319 | kprintf("pat_input: Packet Rejected: not for us? dest=%x.%x.%x.%x.%x.%x LLC_PROTO= %02x%02x\n", |
| 320 | enet_header->dst[0], enet_header->dst[1], |
| 321 | enet_header->dst[2], enet_header->dst[3], |
| 322 | enet_header->dst[4], enet_header->dst[5], |
| 323 | llc_header->protocol[3], |
| 324 | llc_header->protocol[4]); |
| 325 | #endif |
| 326 | m_freem(m); |
| 327 | continue; /* was EAFNOSUPPORT */ |
| 328 | } |
| 329 | } |
| 330 | MCHTYPE(m, MSG_DATA); /* set the mbuf type */ |
| 331 | |
| 332 | ifID->stats.rcv_packets++; |
| 333 | for (m1 = m; m1; m1 = m1->m_next) |
| 334 | ifID->stats.rcv_bytes += m1->m_len; |
| 335 | |
| 336 | if (!MULTIPORT_MODE) |
| 337 | ddp_glean(m, ifID, src); |
| 338 | |
| 339 | ddp_input(m, ifID); |
| 340 | } else { |
| 341 | #ifdef APPLETALK_DEBUG |
| 342 | kprintf("pat_input: Packet Rejected: wrong LLC_PROTO = %02x%02x\n", |
| 343 | llc_header->protocol[3], |
| 344 | llc_header->protocol[4]); |
| 345 | #endif |
| 346 | m_freem(m); |
| 347 | } |
| 348 | } |
| 349 | } |
| 350 | goto next; |
| 351 | } /* atalkintr */ |