1/* $NetBSD$ */ 2 3/* 4 * Copyright (c) 1996 Charles D. Cranor and Washington University. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28/* 29 * if_atmsubr.c 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD$"); 34 35#include "opt_inet.h" 36#include "opt_gateway.h" 37#include "opt_natm.h" 38 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/kernel.h> 43#include <sys/malloc.h> 44#include <sys/mbuf.h> 45#include <sys/protosw.h> 46#include <sys/socket.h> 47#include <sys/ioctl.h> 48#include <sys/errno.h> 49#include <sys/syslog.h> 50 51#include <sys/cpu.h> 52 53#include <net/if.h> 54#include <net/netisr.h> 55#include <net/route.h> 56#include <net/if_dl.h> 57#include <net/if_types.h> 58#include <net/if_atm.h> 59#include <net/ethertypes.h> /* XXX: for ETHERTYPE_* */ 60 61#include <net/bpf.h> 62 63#include <netinet/in.h> 64#include <netinet/if_atm.h> 65 66#if defined(INET) || defined(INET6) 67#include <netinet/in_var.h> 68#endif 69#ifdef NATM 70#include <netnatm/natm.h> 71#endif 72 73#define senderr(e) { error = (e); goto bad;} 74 75/* 76 * atm_output: ATM output routine 77 * inputs: 78 * "ifp" = ATM interface to output to 79 * "m0" = the packet to output 80 * "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI) 81 * "rt0" = the route to use 82 * returns: error code [0 == ok] 83 * 84 * note: special semantic: if (dst == NULL) then we assume "m" already 85 * has an atm_pseudohdr on it and just send it directly. 86 * [for native mode ATM output] if dst is null, then 87 * rt0 must also be NULL. 88 */ 89 90int 91atm_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst, 92 struct rtentry *rt0) 93{ 94 uint16_t etype = 0; /* if using LLC/SNAP */ 95 int error = 0, sz; 96 struct atm_pseudohdr atmdst, *ad; 97 struct mbuf *m = m0; 98 struct rtentry *rt; 99 struct atmllc *atmllc; 100 uint32_t atm_flags; 101 ALTQ_DECL(struct altq_pktattr pktattr;) 102 103 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 104 senderr(ENETDOWN); 105 106 /* 107 * If the queueing discipline needs packet classification, 108 * do it before prepending link headers. 109 */ 110 IFQ_CLASSIFY(&ifp->if_snd, m, 111 (dst != NULL ? dst->sa_family : AF_UNSPEC), &pktattr); 112 113 /* 114 * check route 115 */ 116 if ((rt = rt0) != NULL) { 117 118 if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */ 119 if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL) 120 rt->rt_refcnt--; 121 else 122 senderr(EHOSTUNREACH); 123 } 124 125 if (rt->rt_flags & RTF_GATEWAY) { 126 if (rt->rt_gwroute == 0) 127 goto lookup; 128 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 129 rtfree(rt); rt = rt0; 130 lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 0); 131 if ((rt = rt->rt_gwroute) == 0) 132 senderr(EHOSTUNREACH); 133 } 134 } 135 136 /* XXX: put RTF_REJECT code here if doing ATMARP */ 137 138 } 139 140 /* 141 * check for non-native ATM traffic (dst != NULL) 142 */ 143 if (dst) { 144 switch (dst->sa_family) { 145#ifdef INET 146 case AF_INET: 147#endif 148#ifdef INET6 149 case AF_INET6: 150#endif 151#if defined(INET) || defined(INET6) 152 if (dst->sa_family == AF_INET) 153 etype = ETHERTYPE_IP; 154 else 155 etype = ETHERTYPE_IPV6; 156# ifdef ATM_PVCEXT 157 if (ifp->if_flags & IFF_POINTOPOINT) { 158 /* pvc subinterface */ 159 struct pvcsif *pvcsif = (struct pvcsif *)ifp; 160 atmdst = pvcsif->sif_aph; 161 break; 162 } 163# endif 164 if (!atmresolve(rt, m, dst, &atmdst)) { 165 m = NULL; 166 /* XXX: atmresolve already free'd it */ 167 senderr(EHOSTUNREACH); 168 /* XXX: put ATMARP stuff here */ 169 /* XXX: watch who frees m on failure */ 170 } 171 break; 172#endif 173 174 case AF_UNSPEC: 175 /* 176 * XXX: bpfwrite or output from a pvc shadow if. 177 * assuming dst contains 12 bytes (atm pseudo 178 * header (4) + LLC/SNAP (8)) 179 */ 180 memcpy(&atmdst, dst->sa_data, sizeof(atmdst)); 181 break; 182 183 default: 184#if defined(__NetBSD__) || defined(__OpenBSD__) 185 printf("%s: can't handle af%d\n", ifp->if_xname, 186 dst->sa_family); 187#elif defined(__FreeBSD__) || defined(__bsdi__) 188 printf("%s%d: can't handle af%d\n", ifp->if_name, 189 ifp->if_unit, dst->sa_family); 190#endif 191 senderr(EAFNOSUPPORT); 192 } 193 194 /* 195 * must add atm_pseudohdr to data 196 */ 197 sz = sizeof(atmdst); 198 atm_flags = ATM_PH_FLAGS(&atmdst); 199 if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */ 200 M_PREPEND(m, sz, M_DONTWAIT); 201 if (m == 0) 202 senderr(ENOBUFS); 203 ad = mtod(m, struct atm_pseudohdr *); 204 *ad = atmdst; 205 if (atm_flags & ATM_PH_LLCSNAP) { 206 atmllc = (struct atmllc *)(ad + 1); 207 memcpy(atmllc->llchdr, ATMLLC_HDR, 208 sizeof(atmllc->llchdr)); 209 ATM_LLC_SETTYPE(atmllc, etype); 210 } 211 } 212 213 return ifq_enqueue(ifp, m ALTQ_COMMA ALTQ_DECL(&pktattr)); 214 215bad: 216 if (m) 217 m_freem(m); 218 return (error); 219} 220 221/* 222 * Process a received ATM packet; 223 * the packet is in the mbuf chain m. 224 */ 225void 226atm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m, 227 void *rxhand) 228{ 229 struct ifqueue *inq; 230 uint16_t etype = ETHERTYPE_IP; /* default */ 231 int s; 232 233 if ((ifp->if_flags & IFF_UP) == 0) { 234 m_freem(m); 235 return; 236 } 237 ifp->if_ibytes += m->m_pkthdr.len; 238 239 if (rxhand) { 240#ifdef NATM 241 struct natmpcb *npcb = rxhand; 242 s = splnet(); /* in case 2 atm cards @ diff lvls */ 243 npcb->npcb_inq++; /* count # in queue */ 244 splx(s); 245 schednetisr(NETISR_NATM); 246 inq = &natmintrq; 247 m->m_pkthdr.rcvif = rxhand; /* XXX: overload */ 248#else 249 printf("atm_input: NATM detected but not configured in kernel\n"); 250 m_freem(m); 251 return; 252#endif 253 } else { 254 /* 255 * handle LLC/SNAP header, if present 256 */ 257 if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) { 258 struct atmllc *alc; 259 if (m->m_len < sizeof(*alc) && (m = m_pullup(m, sizeof(*alc))) == 0) 260 return; /* failed */ 261 alc = mtod(m, struct atmllc *); 262 if (memcmp(alc, ATMLLC_HDR, 6)) { 263#if defined(__NetBSD__) || defined(__OpenBSD__) 264 printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n", 265 ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah)); 266#elif defined(__FreeBSD__) || defined(__bsdi__) 267 printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n", 268 ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah)); 269#endif 270 m_freem(m); 271 return; 272 } 273 etype = ATM_LLC_TYPE(alc); 274 m_adj(m, sizeof(*alc)); 275 } 276 277 switch (etype) { 278#ifdef INET 279 case ETHERTYPE_IP: 280#ifdef GATEWAY 281 if (ipflow_fastforward(m)) 282 return; 283#endif 284 schednetisr(NETISR_IP); 285 inq = &ipintrq; 286 break; 287#endif /* INET */ 288#ifdef INET6 289 case ETHERTYPE_IPV6: 290#ifdef GATEWAY 291 if (ip6flow_fastforward(&m)) 292 return; 293#endif 294 schednetisr(NETISR_IPV6); 295 inq = &ip6intrq; 296 break; 297#endif 298 default: 299 m_freem(m); 300 return; 301 } 302 } 303 304 s = splnet(); 305 if (IF_QFULL(inq)) { 306 IF_DROP(inq); 307 m_freem(m); 308 } else 309 IF_ENQUEUE(inq, m); 310 splx(s); 311} 312 313/* 314 * Perform common duties while attaching to interface list 315 */ 316void 317atm_ifattach(struct ifnet *ifp) 318{ 319 320 ifp->if_type = IFT_ATM; 321 ifp->if_addrlen = 0; 322 ifp->if_hdrlen = 0; 323 ifp->if_dlt = DLT_ATM_RFC1483; 324 ifp->if_mtu = ATMMTU; 325 ifp->if_output = atm_output; 326#if 0 /* XXX XXX XXX */ 327 ifp->if_input = atm_input; 328#endif 329 330 if_alloc_sadl(ifp); 331 /* XXX Store LLADDR for ATMARP. */ 332 333 bpf_attach(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc)); 334} 335 336#ifdef ATM_PVCEXT 337 338static int pvc_max_number = 16; /* max number of PVCs */ 339static int pvc_number = 0; /* pvc unit number */ 340 341struct ifnet * 342pvcsif_alloc(void) 343{ 344 struct pvcsif *pvcsif; 345 346 if (pvc_number >= pvc_max_number) 347 return (NULL); 348 pvcsif = malloc(sizeof(struct pvcsif), 349 M_DEVBUF, M_WAITOK|M_ZERO); 350 if (pvcsif == NULL) 351 return (NULL); 352 353#ifdef __NetBSD__ 354 snprintf(pvcsif->sif_if.if_xname, sizeof(pvcsif->sif_if.if_xname), 355 "pvc%d", pvc_number++); 356#else 357 pvcsif->sif_if.if_name = "pvc"; 358 pvcsif->sif_if.if_unit = pvc_number++; 359#endif 360 return (&pvcsif->sif_if); 361} 362#endif /* ATM_PVCEXT */ 363