IF_ETHER.C
上传用户:tjbfgc
上传日期:2013-03-31
资源大小:140k
文件大小:17k
源码类别:

网络编程

开发平台:

C/C++

  1. /*
  2.  * Copyright (c) 1982, 1986, 1988, 1993
  3.  * The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  * This product includes software developed by the University of
  16.  * California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  *
  33.  * @(#)if_ether.c 8.1 (Berkeley) 6/10/93
  34.  */
  35. /*
  36.  * Ethernet address resolution protocol.
  37.  * TODO:
  38.  * add "inuse/lock" bit (or ref. count) along with valid bit
  39.  */
  40. #include <sys/param.h>
  41. #include <sys/systm.h>
  42. #include <sys/malloc.h>
  43. #include <sys/mbuf.h>
  44. #include <sys/socket.h>
  45. #include <sys/time.h>
  46. #include <sys/kernel.h>
  47. #include <sys/errno.h>
  48. #include <sys/ioctl.h>
  49. #include <sys/syslog.h>
  50. #include <net/if.h>
  51. #include <net/if_dl.h>
  52. #include <net/route.h>
  53. #include <netinet/in.h>
  54. #include <netinet/in_systm.h>
  55. #include <netinet/in_var.h>
  56. #include <netinet/ip.h>
  57. #include <netinet/if_ether.h>
  58. #define SIN(s) ((struct sockaddr_in *)s)
  59. #define SDL(s) ((struct sockaddr_dl *)s)
  60. #define SRP(s) ((struct sockaddr_inarp *)s)
  61. /*
  62.  * ARP trailer negotiation.  Trailer protocol is not IP specific,
  63.  * but ARP request/response use IP addresses.
  64.  */
  65. #define ETHERTYPE_IPTRAILERS ETHERTYPE_TRAIL
  66. /* timer values */
  67. int arpt_prune = (5*60*1); /* walk list every 5 minutes */
  68. int arpt_keep = (20*60); /* once resolved, good for 20 more minutes */
  69. int arpt_down = 20; /* once declared down, don't send for 20 secs */
  70. #define rt_expire rt_rmx.rmx_expire
  71. static void arprequest __P((struct arpcom *, u_long *, u_long *, u_char *));
  72. static void arptfree __P((struct llinfo_arp *));
  73. static void arptimer __P((void *));
  74. static struct llinfo_arp *arplookup __P((u_long, int, int));
  75. static void in_arpinput __P((struct mbuf *));
  76. extern struct ifnet loif;
  77. extern struct timeval time;
  78. struct llinfo_arp llinfo_arp = {&llinfo_arp, &llinfo_arp};
  79. struct ifqueue arpintrq = {0, 0, 0, 50};
  80. int arp_inuse, arp_allocated, arp_intimer;
  81. int arp_maxtries = 5;
  82. int useloopback = 1; /* use loopback interface for local traffic */
  83. int arpinit_done = 0;
  84. /*
  85.  * Timeout routine.  Age arp_tab entries periodically.
  86.  */
  87. /* ARGSUSED */
  88. static void
  89. arptimer(ignored_arg)
  90. void *ignored_arg;
  91. {
  92. int s = splnet();
  93. register struct llinfo_arp *la = llinfo_arp.la_next;
  94. timeout(arptimer, (caddr_t)0, arpt_prune * hz);
  95. while (la != &llinfo_arp) {
  96. register struct rtentry *rt = la->la_rt;
  97. la = la->la_next;
  98. if (rt->rt_expire && rt->rt_expire <= time.tv_sec)
  99. arptfree(la->la_prev); /* timer has expired, clear */
  100. }
  101. splx(s);
  102. }
  103. /*
  104.  * Parallel to llc_rtrequest.
  105.  */
  106. void
  107. arp_rtrequest(req, rt, sa)
  108. int req;
  109. register struct rtentry *rt;
  110. struct sockaddr *sa;
  111. {
  112. register struct sockaddr *gate = rt->rt_gateway;
  113. register struct llinfo_arp *la = (struct llinfo_arp *)rt->rt_llinfo;
  114. static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
  115. if (!arpinit_done) {
  116. arpinit_done = 1;
  117. timeout(arptimer, (caddr_t)0, hz);
  118. }
  119. if (rt->rt_flags & RTF_GATEWAY)
  120. return;
  121. switch (req) {
  122. case RTM_ADD:
  123. /*
  124.  * XXX: If this is a manually added route to interface
  125.  * such as older version of routed or gated might provide,
  126.  * restore cloning bit.
  127.  */
  128. if ((rt->rt_flags & RTF_HOST) == 0 &&
  129.     SIN(rt_mask(rt))->sin_addr.s_addr != 0xffffffff)
  130. rt->rt_flags |= RTF_CLONING;
  131. if (rt->rt_flags & RTF_CLONING) {
  132. /*
  133.  * Case 1: This route should come from a route to iface.
  134.  */
  135. rt_setgate(rt, rt_key(rt),
  136. (struct sockaddr *)&null_sdl);
  137. gate = rt->rt_gateway;
  138. SDL(gate)->sdl_type = rt->rt_ifp->if_type;
  139. SDL(gate)->sdl_index = rt->rt_ifp->if_index;
  140. rt->rt_expire = time.tv_sec;
  141. break;
  142. }
  143. /* Announce a new entry if requested. */
  144. if (rt->rt_flags & RTF_ANNOUNCE)
  145. arprequest((struct arpcom *)rt->rt_ifp,
  146.     &SIN(rt_key(rt))->sin_addr.s_addr,
  147.     &SIN(rt_key(rt))->sin_addr.s_addr,
  148.     (u_char *)LLADDR(SDL(gate)));
  149. /*FALLTHROUGH*/
  150. case RTM_RESOLVE:
  151. if (gate->sa_family != AF_LINK ||
  152.     gate->sa_len < sizeof(null_sdl)) {
  153. log(LOG_DEBUG, "arp_rtrequest: bad gateway value");
  154. break;
  155. }
  156. SDL(gate)->sdl_type = rt->rt_ifp->if_type;
  157. SDL(gate)->sdl_index = rt->rt_ifp->if_index;
  158. if (la != 0)
  159. break; /* This happens on a route change */
  160. /*
  161.  * Case 2:  This route may come from cloning, or a manual route
  162.  * add with a LL address.
  163.  */
  164. R_Malloc(la, struct llinfo_arp *, sizeof(*la));
  165. rt->rt_llinfo = (caddr_t)la;
  166. if (la == 0) {
  167. log(LOG_DEBUG, "arp_rtrequest: malloc failedn");
  168. break;
  169. }
  170. arp_inuse++, arp_allocated++;
  171. Bzero(la, sizeof(*la));
  172. la->la_rt = rt;
  173. rt->rt_flags |= RTF_LLINFO;
  174. insque(la, &llinfo_arp);
  175. if (SIN(rt_key(rt))->sin_addr.s_addr ==
  176.     (IA_SIN(rt->rt_ifa))->sin_addr.s_addr) {
  177.     /*
  178.      * This test used to be
  179.      * if (loif.if_flags & IFF_UP)
  180.      * It allowed local traffic to be forced
  181.      * through the hardware by configuring the loopback down.
  182.      * However, it causes problems during network configuration
  183.      * for boards that can't receive packets they send.
  184.      * It is now necessary to clear "useloopback" and remove
  185.      * the route to force traffic out to the hardware.
  186.      */
  187. rt->rt_expire = 0;
  188. Bcopy(((struct arpcom *)rt->rt_ifp)->ac_enaddr,
  189. LLADDR(SDL(gate)), SDL(gate)->sdl_alen = 6);
  190. if (useloopback)
  191. rt->rt_ifp = &loif;
  192. }
  193. break;
  194. case RTM_DELETE:
  195. if (la == 0)
  196. break;
  197. arp_inuse--;
  198. remque(la);
  199. rt->rt_llinfo = 0;
  200. rt->rt_flags &= ~RTF_LLINFO;
  201. if (la->la_hold)
  202. m_freem(la->la_hold);
  203. Free((caddr_t)la);
  204. }
  205. }
  206. /*
  207.  * Broadcast an ARP packet, asking who has addr on interface ac.
  208.  */
  209. void
  210. arpwhohas(ac, addr)
  211. register struct arpcom *ac;
  212. register struct in_addr *addr;
  213. {
  214. arprequest(ac, &ac->ac_ipaddr.s_addr, &addr->s_addr, ac->ac_enaddr);
  215. }
  216. /*
  217.  * Broadcast an ARP request. Caller specifies:
  218.  * - arp header source ip address
  219.  * - arp header target ip address
  220.  * - arp header source ethernet address
  221.  */
  222. static void
  223. arprequest(ac, sip, tip, enaddr)
  224. register struct arpcom *ac;
  225. register u_long *sip, *tip;
  226. register u_char *enaddr;
  227. {
  228. register struct mbuf *m;
  229. register struct ether_header *eh;
  230. register struct ether_arp *ea;
  231. struct sockaddr sa;
  232. if ((m = m_gethdr(M_DONTWAIT, MT_DATA)) == NULL)
  233. return;
  234. m->m_len = sizeof(*ea);
  235. m->m_pkthdr.len = sizeof(*ea);
  236. MH_ALIGN(m, sizeof(*ea));
  237. ea = mtod(m, struct ether_arp *);
  238. eh = (struct ether_header *)sa.sa_data;
  239. bzero((caddr_t)ea, sizeof (*ea));
  240. bcopy((caddr_t)etherbroadcastaddr, (caddr_t)eh->ether_dhost,
  241.     sizeof(eh->ether_dhost));
  242. eh->ether_type = ETHERTYPE_ARP; /* if_output will swap */
  243. ea->arp_hrd = htons(ARPHRD_ETHER);
  244. ea->arp_pro = htons(ETHERTYPE_IP);
  245. ea->arp_hln = sizeof(ea->arp_sha); /* hardware address length */
  246. ea->arp_pln = sizeof(ea->arp_spa); /* protocol address length */
  247. ea->arp_op = htons(ARPOP_REQUEST);
  248. bcopy((caddr_t)enaddr, (caddr_t)ea->arp_sha, sizeof(ea->arp_sha));
  249. bcopy((caddr_t)sip, (caddr_t)ea->arp_spa, sizeof(ea->arp_spa));
  250. bcopy((caddr_t)tip, (caddr_t)ea->arp_tpa, sizeof(ea->arp_tpa));
  251. sa.sa_family = AF_UNSPEC;
  252. sa.sa_len = sizeof(sa);
  253. (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
  254. }
  255. /*
  256.  * Resolve an IP address into an ethernet address.  If success,
  257.  * desten is filled in.  If there is no entry in arptab,
  258.  * set one up and broadcast a request for the IP address.
  259.  * Hold onto this mbuf and resend it once the address
  260.  * is finally resolved.  A return value of 1 indicates
  261.  * that desten has been filled in and the packet should be sent
  262.  * normally; a 0 return indicates that the packet has been
  263.  * taken over here, either now or for later transmission.
  264.  */
  265. int
  266. arpresolve(ac, rt, m, dst, desten)
  267. register struct arpcom *ac;
  268. register struct rtentry *rt;
  269. struct mbuf *m;
  270. register struct sockaddr *dst;
  271. register u_char *desten;
  272. {
  273. register struct llinfo_arp *la;
  274. struct sockaddr_dl *sdl;
  275. if (m->m_flags & M_BCAST) { /* broadcast */
  276. bcopy((caddr_t)etherbroadcastaddr, (caddr_t)desten,
  277.     sizeof(etherbroadcastaddr));
  278. return (1);
  279. }
  280. if (m->m_flags & M_MCAST) { /* multicast */
  281. ETHER_MAP_IP_MULTICAST(&SIN(dst)->sin_addr, desten);
  282. return(1);
  283. }
  284. if (rt)
  285. la = (struct llinfo_arp *)rt->rt_llinfo;
  286. else {
  287. if (la = arplookup(SIN(dst)->sin_addr.s_addr, 1, 0))
  288. rt = la->la_rt;
  289. }
  290. if (la == 0 || rt == 0) {
  291. log(LOG_DEBUG, "arpresolve: can't allocate llinfo");
  292. m_freem(m);
  293. return (0);
  294. }
  295. sdl = SDL(rt->rt_gateway);
  296. /*
  297.  * Check the address family and length is valid, the address
  298.  * is resolved; otherwise, try to resolve.
  299.  */
  300. if ((rt->rt_expire == 0 || rt->rt_expire > time.tv_sec) &&
  301.     sdl->sdl_family == AF_LINK && sdl->sdl_alen != 0) {
  302. bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
  303. return 1;
  304. }
  305. /*
  306.  * There is an arptab entry, but no ethernet address
  307.  * response yet.  Replace the held mbuf with this
  308.  * latest one.
  309.  */
  310. if (la->la_hold)
  311. m_freem(la->la_hold);
  312. la->la_hold = m;
  313. if (rt->rt_expire) {
  314. rt->rt_flags &= ~RTF_REJECT;
  315. if (la->la_asked == 0 || rt->rt_expire != time.tv_sec) {
  316. rt->rt_expire = time.tv_sec;
  317. if (la->la_asked++ < arp_maxtries)
  318. arpwhohas(ac, &(SIN(dst)->sin_addr));
  319. else {
  320. rt->rt_flags |= RTF_REJECT;
  321. rt->rt_expire += arpt_down;
  322. la->la_asked = 0;
  323. }
  324. }
  325. }
  326. return (0);
  327. }
  328. /*
  329.  * Common length and type checks are done here,
  330.  * then the protocol-specific routine is called.
  331.  */
  332. void
  333. arpintr()
  334. {
  335. register struct mbuf *m;
  336. register struct arphdr *ar;
  337. int s;
  338. while (arpintrq.ifq_head) {
  339. s = splimp();
  340. IF_DEQUEUE(&arpintrq, m);
  341. splx(s);
  342. if (m == 0 || (m->m_flags & M_PKTHDR) == 0)
  343. panic("arpintr");
  344. if (m->m_len >= sizeof(struct arphdr) &&
  345.     (ar = mtod(m, struct arphdr *)) &&
  346.     ntohs(ar->ar_hrd) == ARPHRD_ETHER &&
  347.     m->m_len >=
  348.       sizeof(struct arphdr) + 2 * ar->ar_hln + 2 * ar->ar_pln)
  349.     switch (ntohs(ar->ar_pro)) {
  350.     case ETHERTYPE_IP:
  351.     case ETHERTYPE_IPTRAILERS:
  352.     in_arpinput(m);
  353.     continue;
  354.     }
  355. m_freem(m);
  356. }
  357. }
  358. /*
  359.  * ARP for Internet protocols on 10 Mb/s Ethernet.
  360.  * Algorithm is that given in RFC 826.
  361.  * In addition, a sanity check is performed on the sender
  362.  * protocol address, to catch impersonators.
  363.  * We no longer handle negotiations for use of trailer protocol:
  364.  * Formerly, ARP replied for protocol type ETHERTYPE_TRAIL sent
  365.  * along with IP replies if we wanted trailers sent to us,
  366.  * and also sent them in response to IP replies.
  367.  * This allowed either end to announce the desire to receive
  368.  * trailer packets.
  369.  * We no longer reply to requests for ETHERTYPE_TRAIL protocol either,
  370.  * but formerly didn't normally send requests.
  371.  */
  372. static void
  373. in_arpinput(m)
  374. struct mbuf *m;
  375. {
  376. register struct ether_arp *ea;
  377. register struct arpcom *ac = (struct arpcom *)m->m_pkthdr.rcvif;
  378. struct ether_header *eh;
  379. register struct llinfo_arp *la = 0;
  380. register struct rtentry *rt;
  381. struct in_ifaddr *ia, *maybe_ia = 0;
  382. struct sockaddr_dl *sdl;
  383. struct sockaddr sa;
  384. struct in_addr isaddr, itaddr, myaddr;
  385. int op;
  386. ea = mtod(m, struct ether_arp *);
  387. op = ntohs(ea->arp_op);
  388. bcopy((caddr_t)ea->arp_spa, (caddr_t)&isaddr, sizeof (isaddr));
  389. bcopy((caddr_t)ea->arp_tpa, (caddr_t)&itaddr, sizeof (itaddr));
  390. for (ia = in_ifaddr; ia; ia = ia->ia_next)
  391. if (ia->ia_ifp == &ac->ac_if) {
  392. maybe_ia = ia;
  393. if ((itaddr.s_addr == ia->ia_addr.sin_addr.s_addr) ||
  394.      (isaddr.s_addr == ia->ia_addr.sin_addr.s_addr))
  395. break;
  396. }
  397. if (maybe_ia == 0)
  398. goto out;
  399. myaddr = ia ? ia->ia_addr.sin_addr : maybe_ia->ia_addr.sin_addr;
  400. if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)ac->ac_enaddr,
  401.     sizeof (ea->arp_sha)))
  402. goto out; /* it's from me, ignore it. */
  403. if (!bcmp((caddr_t)ea->arp_sha, (caddr_t)etherbroadcastaddr,
  404.     sizeof (ea->arp_sha))) {
  405. log(LOG_ERR,
  406.     "arp: ether address is broadcast for IP address %x!n",
  407.     ntohl(isaddr.s_addr));
  408. goto out;
  409. }
  410. if (isaddr.s_addr == myaddr.s_addr) {
  411. log(LOG_ERR,
  412.    "duplicate IP address %x!! sent from ethernet address: %sn",
  413.    ntohl(isaddr.s_addr), ether_sprintf(ea->arp_sha));
  414. itaddr = myaddr;
  415. goto reply;
  416. }
  417. la = arplookup(isaddr.s_addr, itaddr.s_addr == myaddr.s_addr, 0);
  418. if (la && (rt = la->la_rt) && (sdl = SDL(rt->rt_gateway))) {
  419. if (sdl->sdl_alen &&
  420.     bcmp((caddr_t)ea->arp_sha, LLADDR(sdl), sdl->sdl_alen))
  421. log(LOG_INFO, "arp info overwritten for %x by %sn",
  422.     isaddr.s_addr, ether_sprintf(ea->arp_sha));
  423. bcopy((caddr_t)ea->arp_sha, LLADDR(sdl),
  424.     sdl->sdl_alen = sizeof(ea->arp_sha));
  425. if (rt->rt_expire)
  426. rt->rt_expire = time.tv_sec + arpt_keep;
  427. rt->rt_flags &= ~RTF_REJECT;
  428. la->la_asked = 0;
  429. if (la->la_hold) {
  430. (*ac->ac_if.if_output)(&ac->ac_if, la->la_hold,
  431. rt_key(rt), rt);
  432. la->la_hold = 0;
  433. }
  434. }
  435. reply:
  436. if (op != ARPOP_REQUEST) {
  437. out:
  438. m_freem(m);
  439. return;
  440. }
  441. if (itaddr.s_addr == myaddr.s_addr) {
  442. /* I am the target */
  443. bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
  444.     sizeof(ea->arp_sha));
  445. bcopy((caddr_t)ac->ac_enaddr, (caddr_t)ea->arp_sha,
  446.     sizeof(ea->arp_sha));
  447. } else {
  448. la = arplookup(itaddr.s_addr, 0, SIN_PROXY);
  449. if (la == NULL)
  450. goto out;
  451. rt = la->la_rt;
  452. bcopy((caddr_t)ea->arp_sha, (caddr_t)ea->arp_tha,
  453.     sizeof(ea->arp_sha));
  454. sdl = SDL(rt->rt_gateway);
  455. bcopy(LLADDR(sdl), (caddr_t)ea->arp_sha, sizeof(ea->arp_sha));
  456. }
  457. bcopy((caddr_t)ea->arp_spa, (caddr_t)ea->arp_tpa, sizeof(ea->arp_spa));
  458. bcopy((caddr_t)&itaddr, (caddr_t)ea->arp_spa, sizeof(ea->arp_spa));
  459. ea->arp_op = htons(ARPOP_REPLY);
  460. ea->arp_pro = htons(ETHERTYPE_IP); /* let's be sure! */
  461. eh = (struct ether_header *)sa.sa_data;
  462. bcopy((caddr_t)ea->arp_tha, (caddr_t)eh->ether_dhost,
  463.     sizeof(eh->ether_dhost));
  464. eh->ether_type = ETHERTYPE_ARP;
  465. sa.sa_family = AF_UNSPEC;
  466. sa.sa_len = sizeof(sa);
  467. (*ac->ac_if.if_output)(&ac->ac_if, m, &sa, (struct rtentry *)0);
  468. return;
  469. }
  470. /*
  471.  * Free an arp entry.
  472.  */
  473. static void
  474. arptfree(la)
  475. register struct llinfo_arp *la;
  476. {
  477. register struct rtentry *rt = la->la_rt;
  478. register struct sockaddr_dl *sdl;
  479. if (rt == 0)
  480. panic("arptfree");
  481. if (rt->rt_refcnt > 0 && (sdl = SDL(rt->rt_gateway)) &&
  482.     sdl->sdl_family == AF_LINK) {
  483. sdl->sdl_alen = 0;
  484. la->la_asked = 0;
  485. rt->rt_flags &= ~RTF_REJECT;
  486. return;
  487. }
  488. rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0, rt_mask(rt),
  489. 0, (struct rtentry **)0);
  490. }
  491. /*
  492.  * Lookup or enter a new address in arptab.
  493.  */
  494. static struct llinfo_arp *
  495. arplookup(addr, create, proxy)
  496. u_long addr;
  497. int create, proxy;
  498. {
  499. register struct rtentry *rt;
  500. static struct sockaddr_inarp sin = {sizeof(sin), AF_INET };
  501. sin.sin_addr.s_addr = addr;
  502. sin.sin_other = proxy ? SIN_PROXY : 0;
  503. rt = rtalloc1((struct sockaddr *)&sin, create);
  504. if (rt == 0)
  505. return (0);
  506. rt->rt_refcnt--;
  507. if ((rt->rt_flags & RTF_GATEWAY) || (rt->rt_flags & RTF_LLINFO) == 0 ||
  508.     rt->rt_gateway->sa_family != AF_LINK) {
  509. if (create)
  510. log(LOG_DEBUG, "arptnew failed on %xn", ntohl(addr));
  511. return (0);
  512. }
  513. return ((struct llinfo_arp *)rt->rt_llinfo);
  514. }
  515. int
  516. arpioctl(cmd, data)
  517. int cmd;
  518. caddr_t data;
  519. {
  520. return (EOPNOTSUPP);
  521. }