¡º¸®´ª½º Çдç-¸®´ª½º °­Á / ¿¬Àç (go LINUX)¡» 736¹ø Á¦ ¸ñ:[°­ÁÂ]Network Device Driver¸¸µé±â [1] ¿Ã¸°ÀÌ:hetta (À̱âõ ) 01/10/21 11:38 ÀÐÀ½:334 °ü·ÃÀÚ·á ¾øÀ½ ----------------------------------------------------------------------------- ######################################### °­ÁÂ: Network Device Driver¸¸µé±â ## (ºÎÀç: ¾ÖÀθ¸µé±â) ######################################### 1ºÎ: ³×Æ®¿öÅ© µå¶óÀ̹öÀÇ ±âº»(1) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ À̾߱â²Û:À̱âõ(hetta@nownuri.net) +-----------------------------------------------------------------------+ | *°­Á¿¡ ¾Õ¼­¼­.... | | ÀÌ ±ÛÀº GFDL(GNU Free Documentation License)À» µû¸¨´Ï´Ù. | | ±×·¯¹Ç·Î ÇÊÀÚ´Â À̱۷ΠÀÎÇÑ ¹°ÁúÀûÀ̵ç Á¤½ÅÀûÀÌµç ¶ÇÇÑ | | °¡Á¤ÀÇ ºÒÈ­µçÁö°£¿¡ ¾î¶°ÇÑ Ã¥ÀÓµµ ÁöÁö ¾Ê½À´Ï´Ù. | | ¿øÀúÀÚ°¡ ¸í½ÃµÇ´ÂÇÑ ºñ»ó¾÷Àû¿ëµµ¿¡ ÇÑÇÏ¿© | | ÀÚÀ¯·Î¿î ¹èÆ÷,¼öÁ¤À̰¡´ÉÇÏÁö¸¸, | | ¾î¶°ÇÑ ¼ö´ÜÀ̵çÁö°£¿¡ »ó¾÷Àû ¿ëµµ·Î »ç¿ëµÇ¾îÁú¼ö´Â ¾ø½À´Ï´Ù. | +-----------------------------------------------------------------------+ <Âü°íÀÚ·á> 1.Linux Device Driver 2nd - http://www.oreilly.com ¿¡¼­ pdf¹öÀü ¹«·á¹èÆ÷ 2.Linux Network Device Driver(±Ç¼öÈ£) - http://www.linuxdeveloper.co.kr 3.RTL8139C datasheet - http://www.realtek.com.tw/ 4.(Linux_Kernel_Src_Path)drivers/net/8139too.c 5.RTL8139 Programming guide 6.Understanding the Linux Kernel *ȯ°æ:kernel 2.4.9 (´Ù¸¥¹öÀüÀÇ Ä¿³Î¿¡¼­´Â Á¶±Ý¾¿ ´Ù¸¦¼öÀÖÀ½À» À¯ÀÇÇϽñ⠹ٶø´Ï´Ù.) ¿À´ÃÀº À̹ø°­ÀÇÀÇ Ã¹¹øÂ°½Ã°£ÀÔ´Ï´Ù. À̹ø½Ã°£¿£ ¸ÕÀú Network Driver¿¡´ëÇÑ °³³äÀ» Àâ±âÀ§ÇÏ¿© Linux Device Driver 2ndÀÇ [chapter 15. Network Drivers]¸¦ ±â¹ÝÀ¸·Î À̾߱⸦ ½ÃÀÛÇϰڽÀ´Ï´Ù. ¾ðÁ¦±îÁö ÇÒ°ÍÀ̶ó´Â ¾à¼ÓÀº ¸øµå¸±°Í°°½À´Ï´Ù.Àúµµ Àΰ£À̴ϱî¿ä..¾î¼¸é À̹ø°­ÀÇ °¡ óÀ½ÀÌÀÚ ¸¶Áö¸·ÀÏÁöµµ ¸ð¸£°ÚÁÒ^^ ¾ðÁ¦µçÁö ³×Æ®¿öÅ© µå¶óÀ̹ö ºÐ¼®ÀÌ Àç¹Ì(funny)¾ø´Ù¸é °­ÀǸ¦ ±×¸¸µÑ°Ì´Ï´Ù.(¾Æ¸¶ °¡´É¼ºÀÌ Èñ¹ÚÇϰÚÁö¸¸^^) Àúµµ Ãʺ¸ÀÓÀ» ¹àÈ÷°Ú½À´Ï´Ù. ½ÇÁ¦Àû device driver¸¦ ´Ù·ç´Â°ÍÀº óÀ½ÀÔ´Ï´Ù. ±×·¯¹Ç·Î Ʋ¸°Á¡ÀÌ ¸¹À»°Í°°½À´Ï´Ù... ¾ðÁ¦µçÁö À߸øµÈ°ÍÀº È¥ÀÚ¾ËÁö¸¶½Ã°í ¾Ë·ÁÁÖ¼¼¿© ~~~~~~~~~! Àú´Â Á¦°¡ ÀÌÇØÇÑ ¹æÇâÀ¸·Î °­Á¸¦ ÁøÇàÇϰڽÀ´Ï´Ù.^^ ÀÌÁ¦ºÎÅÍ Á¸ÄªÀº »ý·«Çϵµ·Ï ÇϰڽÀ´Ï´Ù.^^ ŸÀÌÇÎÄ¡±â°¡ Èûµå·¯¼­¿ä.... :P ÀÚ ±×·³ ½ÃÀÛÇÕ´Ï´Ù. :) ¸ðµâ ¿Ã¸®±â ^^^^^^^^^^^^ µð¹ÙÀ̽º µå¶óÀ̹ö°¡ Ä¿³Î¿¡ ·ÎµùµÉ¶§ ÀڱⰡ »ç¿ëÇÒ ¸®¼Ò½º¸¦ Ä¿³Î¿¡ ¿äûÇÏ°Ô µÈ´Ù. ¿¹¸¦µé¾î »ç¿ëÇÒ irq¹øÈ£¿Í I/O port¸¦ µî·ÏÇØ¾ßÇÑ´Ù. ·£Ä«µå¸¦ ÀâÀ»¶§ ´ÙÀ½°ú °°ÀÌ Àâ´Â´Ù. ÇÊÀÚÀÇ °æ¿ìµµ ne2000·£Ä«µå¸¦ ÀâÀ»¶§, ¸ÕÀú À©µµ¿ì·Î °¡¼­ °Å±â¼­ io¿Í irq¹øÈ£¸¦ ¾Ë¾Æ¿Â´ÙÀ½¿¡ ¸®´ª½º¿¡¼­ ´ÙÀ½°ú °°ÀÌ Àâ¾Ò´Ù.(¹°·Ð ÀÌ·¸°Ô Àâ´Â°ÍÀº isa¹æ½ÄÀÌ ´ëºÎºÐÀ̾úÀ¸³ª, pciµµ ÀÌ·¸°Ô Àâ ¾Æ¾ß ÀâÈ÷´Â °æ¿ì¸¦ °æÇèÇß´Ù.) modprobe ne.o io=0x100 irq=9 À̰ÍÀÌ ·£Ä«µå°¡ »ç¿ëÇÒ io¿Í irq¸¦ ¸í·É¾î ¶óÀÎ Àμö·Î ³Ñ°Ü¹Þ°Ô µÇ´Â°ÍÀÌ´Ù. Å©°Ô µð¹ÙÀ̽º µå¶óÀ̹ö´Â... ºÒ·Ï(block),¹®ÀÚ(character),³×Æ®¿÷ ÀÌ·¸°Ô 3°³·Î ³ª´«´Ù. ±×Áß¿¡¼­ ºÒ·Ï°ú ¹®ÀÚ´Â ÁÖ¹øÈ£¿Í ºÎ¹øÈ£¶ó´Â°ÍÀÌ Á¸ÀçÇÏ¿© µð¹ÙÀ̽º¸¦ Á¦¾îÇϳª, ³×Æ®¿÷ÀåÄ¡´Â ±×·¯ÇÑ °³³äÀÌ Á¸ÀçÇÏÁö ¾Ê´Â´Ù.±×´ë½Å Ä¿³ÎÀÇ ¾î´À°÷¿¡¼­µµ ÂüÁ¶ÇÒ¼öÀÖ´Â Àü¿ª(global)¸®½ºÆ®·Î »õ·Î¿î µð¹ÙÀ̽ºÀåÄ¡¸¦ ³Ö°ÔµÈ´Ù. ¶ÇÇÑ "À¯´Ð½º(¸®´ª½º)¿¡¼­ ´Â ¸ðµç°ÍÀÌ ÆÄÀÏ"À̶ó´Â ¸»À» ¸¹ÀÌ µé¾îº¸¾ÒÀ»°ÍÀÌ´Ù. ÇÏÁö¸¸, ¿©±â¼­ ³×Æ®¿÷ÀåÄ¡ ´Â ¾Æ½±°Ôµµ ¿¹¿Ü·Î¼­ Á¸ÀçÇÑ´Ù. ´Ù¸¥ ¹®ÀÚ³ª,ºí·ÏÀå Ä¡´Â /dev/¹Ø¿¡ ½ÇÁ¦ÀûÀÎ ÆÄÀϷμ­Á¸ÀçÇϳª, ³×Æ®¿÷ÀåÄ¡¸¸Àº °Å±â¿¡ Á¸ÀçÇÏ Áö ¾Ê´Â´Ù! ¹¹.. ¿¹¿Ü¾ø´Â ¹ýÄ¢ÀÌ ¾ø´Ù´Â¸»µµ ÀÖÀ¸´Ï, Àá½Ã ºÁÁÖ±â·Î ÇÏÀÚ..¤¾¤¾ "À¯´Ð½º¿¡¼­ ¸ðµç°ÍÀº ÆÄÀÏÀÌ´Ù.(´Ü ³×Æ®¿÷ÀåÄ¡¸¸»©°í^^)" (ÁÖ: ³×Æ®¿÷ ÀåÄ¡¸»°í ´Ù¸¥°ÍÀÌ ÀÖ´Ù¸é ¾Ë·ÁÁֱ⠹ٶø´Ï´Ù.) À§¿¡¼­ Àü¿ª¸®½ºÆ®°¡ Á¸ÀçÇÑ´Ù°í ÇÏ¿´´Ù. ±×·¸´Ù¸é ÀÌ Àü¿ª¸®½ºÆ®ÀÇ ÀڷᱸÁ¶´Â ¾î¶»°Ô »ý°åÀ»±î? ¸®´ª½º´Â ³×Æ®¿÷ ÀåÄ¡¿¡ ´ëÇÑ µ¥ÀÌÅ͸¦ struct net_device·Î¼­ °ü¸®ÇÑ´Ù. ÀÌÁ¦, LXR·Î »ìÆìº¸µµ·ÏÇÏÀÚ. <Âü°í> ----------------------------------------------------------- ¸ð¸£½Ã´Â ºÐÀ» À§ÇÏ¿© °£´ÜÈ÷ ¾²°Ú´Ù. À¥ºê¶ó¿ìÀú·Î http://lxr.linux.no¿¡°¡¼­ browse the code¸¦ ´©¸¥µÚ identifier search ¸¦ ´©¸£°í °Ë»ö¶õ¿¡ net_device¸¦ Àû´Â´Ù. ÀÌÁ¦ net_device¸¦ Á¤ÀÇÇÑ ´ÙÀ½°ú °°Àº °Ë»ö°á°ú°¡ ³ª¿Ã°ÍÀÌ´Ù. ±×°ÍÀ» ´©¸¥´Ù. include/linux/netdevice.h, line 230 -------------------------------------------------------------------- Ä¿³Î¼Ò½º¸¦ óÀ½º¸½Ã´ÂºÐÀº ¹ú½áºÎÅÍ ±â°¡ ÂûÁöµµ ¸ð¸£°Ú´Ù. ±¸Á¶Ã¼°¡ Àڱ׸¶Ä¡ 180¶óÀÎÀÌ´Ï ¸»ÀÌ´Ù. ±×·¯³ª ¸ðµç°ÍÀ» ¾ËÇÊ¿ä´Â¾ø´Ù. ÇÊ¿äÇѰÍÀº ÇÊ¿äÇÒ¶§ °øºÎÇÑ´Ù´Â ¸¾À» °®°í, ´ëÃæ¸¸ ÈÇÅͺ¸°í ³Ñ¾î°¡µµ·ÏÇÏÀÚ. µÚ¿¡¼­ ²À ÇÊ¿äÇÑ Çʵ常À» ¼³¸íÇÒ°ÍÀÌ´Ù. (»ç½Ç ¾ÈºÁµµ À̾߱â ÁøÇà»ó Å«¹®Á¦´Â¾øÀ¸´Ï ³Ê¹« °ÌºÎÅÍ ³»Áö´Â ¸»±â¸¦ ¹Ù¶õ´Ù.) ---------------------------------------------------------------------- /* * The DEVICE structure. * Actually, this whole structure is a big mistake. It mixes I/O * data with strictly "high-level" data, and it has to know about * almost every data structure used in the INET module. * * FIXME: cleanup struct net_device such that network protocol info * moves out. */ struct net_device { /* * This is the first field of the "visible" part of this structure * (i.e. as seen by users in the "Space.c" file). It is the name * the interface. */ char name[IFNAMSIZ]; /* * I/O specific fields * FIXME: Merge these and struct ifmap into one */ unsigned long rmem_end; /* shmem "recv" end */ unsigned long rmem_start; /* shmem "recv" start */ unsigned long mem_end; /* shared mem end */ unsigned long mem_start; /* shared mem start */ unsigned long base_addr; /* device I/O address */ unsigned int irq; /* device IRQ number */ /* * Some hardware also needs these fields, but they are not * part of the usual set specified in Space.c. */ unsigned char if_port; /* Selectable AUI, TP,..*/ unsigned char dma; /* DMA channel */ unsigned long state; struct net_device *next; /* The device initialization function. Called only once. */ int (*init)(struct net_device *dev); /* ------- Fields preinitialized in Space.c finish here ------- */ struct net_device *next_sched; /* Interface index. Unique device identifier */ int ifindex; int iflink; struct net_device_stats* (*get_stats)(struct net_device *dev); struct iw_statistics* (*get_wireless_stats)(struct net_device *dev); /* * This marks the end of the "visible" part of the structure. All * fields hereafter are internal to the system, and may change at * will (read: may be cleaned up at will). */ /* These may be needed for future network-power-down code. */ unsigned long trans_start; /* Time (in jiffies) of last Tx */ unsigned long last_rx; /* Time of last Rx */ unsigned short flags; /* interface flags (a la BSD) */ unsigned short gflags; unsigned mtu; /* interface MTU value */ unsigned short type; /* interface hardware type */ unsigned short hard_header_len; /* hardware hdr length */ void *priv; /* pointer to private data */ struct net_device *master; /* Pointer to master device of a group, * which this device is member of. */ /* Interface address info. */ unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */ unsigned char addr_len; /* hardware address length */ struct dev_mc_list *mc_list; /* Multicast mac addresses */ int mc_count; /* Number of installed mcasts */ int promiscuity; int allmulti; int watchdog_timeo; struct timer_list watchdog_timer; /* Protocol specific pointers */ void *atalk_ptr; /* AppleTalk link */ void *ip_ptr; /* IPv4 specific data */ void *dn_ptr; /* DECnet specific data */ void *ip6_ptr; /* IPv6 specific data */ void *ec_ptr; /* Econet specific data */ struct Qdisc *qdisc; struct Qdisc *qdisc_sleeping; struct Qdisc *qdisc_list; struct Qdisc *qdisc_ingress; unsigned long tx_queue_len; /* Max frames per queue allowed */ /* hard_start_xmit synchronizer */ spinlock_t xmit_lock; /* cpu id of processor entered to hard_start_xmit or -1, if nobody entered there. */ int xmit_lock_owner; /* device queue lock */ spinlock_t queue_lock; /* Number of references to this device */ atomic_t refcnt; /* The flag marking that device is unregistered, but held by an user */ int deadbeaf; /* Net device features */ int features; #define NETIF_F_SG 1 /* Scatter/gather IO. */ #define NETIF_F_IP_CSUM 2 /* Can checksum only TCP/UDP over IPv4. */ #define NETIF_F_NO_CSUM 4 /* Does not require checksum. F.e. loopack. */ #define NETIF_F_HW_CSUM 8 /* Can checksum all the packets. */ #define NETIF_F_DYNALLOC 16 /* Self-dectructable device. */ #define NETIF_F_HIGHDMA 32 /* Can DMA to high memory. */ #define NETIF_F_FRAGLIST 64 /* Scatter/gather IO. */ /* Called after device is detached from network. */ void (*uninit)(struct net_device *dev); /* Called after last user reference disappears. */ void (*destructor)(struct net_device *dev); /* Pointers to interface service routines. */ int (*open)(struct net_device *dev); int (*stop)(struct net_device *dev); int (*hard_start_xmit) (struct sk_buff *skb, struct net_device *dev); int (*hard_header) (struct sk_buff *skb, struct net_device *dev, unsigned short type, void *daddr, void *saddr, unsigned len); int (*rebuild_header)(struct sk_buff *skb); #define HAVE_MULTICAST void (*set_multicast_list)(struct net_device *dev); #define HAVE_SET_MAC_ADDR int (*set_mac_address)(struct net_device *dev, void *addr); #define HAVE_PRIVATE_IOCTL int (*do_ioctl)(struct net_device *dev, struct ifreq *ifr, int cmd); #define HAVE_SET_CONFIG int (*set_config)(struct net_device *dev, struct ifmap *map); #define HAVE_HEADER_CACHE int (*hard_header_cache)(struct neighbour *neigh, struct hh_cache *hh); void (*header_cache_update)(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr); #define HAVE_CHANGE_MTU int (*change_mtu)(struct net_device *dev, int new_mtu); #define HAVE_TX_TIMEOUT void (*tx_timeout) (struct net_device *dev); int (*hard_header_parse)(struct sk_buff *skb, unsigned char *haddr); int (*neigh_setup)(struct net_device *dev, struct neigh_parms *); int (*accept_fastpath)(struct net_device *, struct dst_entry*); /* open/release and usage marking */ struct module *owner; /* bridge stuff */ struct net_bridge_port *br_port; #ifdef CONFIG_NET_FASTROUTE #define NETDEV_FASTROUTE_HMASK 0xF /* Semi-private data. Keep it at the end of device struct. */ rwlock_t fastpath_lock; struct dst_entry *fastpath[NETDEV_FASTROUTE_HMASK+1]; #endif #ifdef CONFIG_NET_DIVERT /* this will get initialized at each interface type init routine */ struct divert_blk *divert; #endif /* CONFIG_NET_DIVERT */ }; ---------------------------------------------------------------------- ½ÇÁ¦ÀûÀÎ ³×Æ®¿÷ÀåÄ¡ µî·ÏÀº ÀÌ net_deviceÀÇ Çʵåµé¿¡ ÀûÀýÇÑ °ªÀ» ¼¼ÆÃÇÑ´ÙÀ½ ´ÙÀ½°ú °°ÀÌ register_netdev()¸¦ È£ÃâÇϴ°ÍÀÌ´Ù. int result ; struct net_device *my_net ; // my_net±×Á¶Ã¼¿¡ ÀûÀýÇÑ °ªÀ» ä¿ò! result = register_netdev( my_net ); <Âü°í>---------------------------------------------------------------- LDD(Linux Device Driver) 15éÅÍ¿¡¼­´Â snullÀ̶ó´Â ÀåÄ¡¸¦ ¸¸µå´Âµ¥, ÀÌÀåÄ¡´Â ½ÇÁ¦ÀûÀÎ Çϵå¿þ¾î°¡ ¾Æ´Ñ °¡»óÀåÄ¡ÀÌ´Ù. °³ÀÎÀûÀ¸·Î snullÀ̶ó´Â ÀåÄ¡°¡ µ¿ÀÛÇϴ¹æ½ÄÀ» ÀÌÇØÇϴ°ÍÀº º° µµ¿òÀÌ ¾ÈµÇ¾ú´Ù. ±×·¡¼­ ºÒÇÊ¿äÇÑ È¥µ¿À» ÁÙÀ̰íÀÚ µÇµµ·ÏÀ̸é, LDD¿¡ ³ª¿À´Â snullÀÇ ¼³°è´Â Á¦¿ÜÇϰí, ½ÇÁ¦Àû ³×Æ®¿÷ÀåÄ¡¸¦ ºÐ¼®Çϴµ¥ µµ¿òÀÌ µÇ´Â ºÎºÐ¸¸À» ¼³¸íÇÒ °ÍÀÌ´Ù. ÀüüÀûÀÎ È帧À» ÀÌÇØÇϴ°ÍÀÌ Áß¿äÇҰͰ°´Ù. °ü½ÉÀÖÀ¸½ÅºÐÀº ¿À·¼¸® »çÀÌÆ®¿¡¼­ snull¼Ò½º¸¦ ´Ù¿î¹Þ¾Æ¼­ »ìÆìº¸±â ¹Ù¶õ´Ù. ----------------------------------------------------------------------- ³×Æ®¿÷ ÀåÄ¡¸¦ ÃʱâÈ­Çϱâ ~~~~~~~~~~~~~~~~~~~~~~~~~ À̶§ snullÀÇ °æ¿ì net_device±¸Á¶Ã¼¿¡ ÁöÁ¤ÇÑ initÇÔ¼ö°¡ ÃʱâÈ­¸¦ ¼öÇàÇÑ´Ù. ±×ÇÔ¼ö´Â snull_initÀ̸ç, net_device±¸Á¶Ã¼¿¡ ÀûÀýÇÑ Çʵ带 ä¿î´Ù. ¿¹¸¦µé¾î dev->open = snull_open ; //ÀåÄ¡ ¿­¶§. ¾Æ¸¶µµ ifconfig eth0 up Àϵí? dev->stop = snull_release ; //ÀåÄ¡ ´ÝÀ»¶§. ¾Æ¸¶µµ ifconfig eth0 down Àϵí? dev->do_ioctl = snull_ioctl ; //ioctl½Ã½ºÅÛ ÄÝÇÒ¶§ dev->hard_start_xmit = snull_tx ; dev->get_stats = snull_stats ; dev->tx_timeout = snull_tx_timeout ; //TxŸÀӾƿô¹ß»ý½Ã È£ÃâÇÔ¼ö dev->watchdog_timeo = timeout ; //timeout µÇ´Â ½Ã°£¼³Á¤ .... SET_MODULE_OWNER(dev) µîµî... openÀº ÀåÄ¡¸¦ ¿­¶§ ½ÇÇàµÇ´Â°ÍÀ̸ç , hard_start_xmitÀº ÆÐŶÀ» Àü¼ÛÇϱâÀü¿¡ ÃʱâÈ­¸¦ Çϴ°ÍÀ̸ç, get_statsÀº ÀåÄ¡¿¡ °üÇÑ Á¤º¸¸¦ ¿äûÇÒ¶§ Á¤º¸¸¦ Á¦°ø Çϴ°ÍÀÌ´Ù. ifconfig ¶ó´Â ¸í·É¾î¸¦ Ä¥¶§ get_stats°¡ ½ÇÇàµÈ´Ù°í º¸¸é µÉ°ÍÀÌ´Ù. SET_MODULE_OWNER()Àº net_deviceÀÇ owner Çʵ忡 ÀÌ µð¹ÙÀ̽º ¸ðµâ¿¡ ´ëÇÑ Æ÷ÀÎÅÍ·Î ÃʱâÈ­ÇÑ´Ù. ¸ðµâÀÇ usage count¸¦ °ü¸®Çϱâ À§ÇÏ¿©, file_operations±¸Á¶Ã¼ÀÇ ownerÇʵå¿Í ¶È°°ÀÌ Ä¿³Î¿¡¼­ »ç¿ëÇÑ´Ù. ¿¹¸¦µéÀÚ¸é ifconfig eth0 upÇÒ¶§ snull_openÀÌ ½ÇÇàµÇ°í, ifconfig eth0 downÇÒ¶§ snull_release°¡ ½ÇÇàµÈ´Ù°í º¸¸é µÉ°ÍÀÌ´Ù. <Âü°í>----------------------------------------------------------------- ÇÏÁö¸¸, ½ÇÁ¦ 8139too.c¿¡¼­´Â ¾à°£ ´Ù¸¥¹æ½ÄÀ» »ç¿ëÇϴ°ÍÀ¸·Î º¸ÀδÙ. Áï, ÀåÄ¡¸¦ ÃʱâÈ­ Çϴ°ÍÀÌ net_deviceÀÇ initÇʵ带 »ç¿ëÇϴ°ÍÀÌ ¾Æ´Ï¶ó, pci_driver ÀÇ probe¸¦ »ç¿ëÇѴٴ°ÍÀÌ´Ù.( rtl8139_init_one() ) ÇÏÁö¸¸ ÇÏ´Â ÀÛ¾÷Àº ºñ½ÁÇÏ´Ù°í »ý°¢ÇÏ¸é µÉ°Í°°´Ù. rtl8139_init_one(...)¿¡¼­ °á±¹ net_device¸¦ ä¿î´ÙÀ½ register_netdev()¸¦ È£ÃâÇÑ´Ù. ----------------------------------------------------------------------- ÁÖÀÇÇÒÁ¡Àº irq¿Í io°°Àº Áß¿äÇÑ ¸®¼Ò½º´Â initÇϴ½ÃÁ¡ÀÌ ¾Æ´Ñ open½ÃÁ¡¿¡ ¸®¼Ò½º¸¦ È®º¸ÇؾßÇѴٴ°ÍÀÌ´Ù. ¿Ö³ÄÇÏ¸é ±×·¸Áö ¾ÊÀ»°æ¿ì ½ÇÁ¦·Î »ç¿ëµÇÁöµµ ¾Ê´Â ÀåÄ¡¿¡ ÇÒ´çµÈ io¿Í irq¶§¹®¿¡ ´Ù¸¥ÀåÄ¡¸¦ ¾²Áö ¸øÇϴ°æ¿ìµµ ¹ß»ýÇÒ¼öÀֱ⠶§¹®ÀÌ´Ù. ¶ÇÇÑ net_device¿¡´Â priv¶ó´Â Çʵ尡 ÀÖ´Ù. À̰ÍÀº °¢°¢ÀÇ ÀåÄ¡°¡ °ü¸®ÇÏ´Â privateÇÑ ÀÚ·áµîÀ» °ü¸®ÇÏ°Ô µÈ´Ù. À̰ÍÀº ÀåÄ¡¸¦ openÇÏ´Â ½ÃÁ¡ÀÌ ¾Æ´Ï¶ó initÇÒ¶§ ½ÇÇàÇØ¾ßÇÑ´Ù.¿Ö³ÄÇϸé priv¿¡´Â °¢Á¾Åë°èÁ¤º¸¿¡ À¯¿ëÇÑ °ªµéÀÌ Àִµ¥ »ç¿ëÀÚ´Â ÀåÄ¡°¡ Ȱ¼ºÈ­µÇÁö ¾Ê¾ÒÀ»¶§¶óµµ ±×Á¤º¸¸¦ º¸±â ¿øÇÒ¼öÀֱ⠶§¹®ÀÌ´Ù. snullÀÇ °æ¿ì¿¡´Â ´ÙÀ½°ú °°Àº ÇʵåµéÀÌ ÀÖ´Ù. ------------------------------------------------------------------ /* * This structure is private to each device. It is used to pass * packets in and out, so there is place for a packet */ struct snull_priv { struct net_device_stats stats; int status; int rx_packetlen; u8 *rx_packetdata; int tx_packetlen; u8 *tx_packetdata; struct sk_buff *skb; spinlock_t lock; }; ¿©±â¼­ »õ·Î¿î ±¸Á¶Ã¼°¡ ³ª¿À´Âµ¥ net_device_stats·Î¼­ ¸»±×´ë·Î ³×Æ®¿÷ÀåÄ¡¿¡´ëÇÑ Åë°èÀڷḦ °ü¸®ÇÑ´Ù. ----------------------------------------------------------------- /* * Network device statistics. Akin to the 2.0 ether stats but * with byte counters. */ struct net_device_stats { unsigned long rx_packets; /* total packets received */ unsigned long tx_packets; /* total packets transmitted */ unsigned long rx_bytes; /* total bytes received */ unsigned long tx_bytes; /* total bytes transmitted */ unsigned long rx_errors; /* bad packets received */ unsigned long tx_errors; /* packet transmit problems */ unsigned long rx_dropped; /* no space in linux buffers */ unsigned long tx_dropped; /* no space available in linux */ unsigned long multicast; /* multicast packets received */ unsigned long collisions; /* detailed rx_errors: */ unsigned long rx_length_errors; unsigned long rx_over_errors; /* receiver ring buff overflow */ unsigned long rx_crc_errors; /* recved pkt with crc error */ unsigned long rx_frame_errors; /* recv'd frame alignment error */ unsigned long rx_fifo_errors; /* recv'r fifo overrun */ unsigned long rx_missed_errors; /* receiver missed packet */ /* detailed tx_errors */ unsigned long tx_aborted_errors; unsigned long tx_carrier_errors; unsigned long tx_fifo_errors; unsigned long tx_heartbeat_errors; unsigned long tx_window_errors; /* for cslip etc */ unsigned long rx_compressed; unsigned long tx_compressed; }; ----------------------------------------------------------------------- ¹¹ °£´ÜÈ÷ ¿¹¸¦ µéÀÚ¸é ÆÐŶÀ» ¹Þ´Ù°¡ ¸Þ¸ð¸®°¡ ²ËÂ÷¼­ dropµÇ¾ú´Ù¸é rx_dropped Çʵ带 Çϳª Áõ°¡½ÃÄÑÁÖ´Â ±×³É ÀÌ·±½ÄÀÌ´Ù. ifconfig¸í·ÉÀ» ³»¸®¸é ·£Ä«µå¿¡´ëÇÑ °¢Á¾ Åë°èÄ¡°¡ ³ª¿À´Âµ¥ ÀÌ·±Åë°èÀڷḦ ¹ÙÅÁÀ¸·Î Ãâ·ÂµÇ´Â°ÍÀÌ´Ù. eth0 Link encap:Ethernet HWaddr 00:50:FC:0C:ff:f1 ... RX packets:894551 errors:0 dropped:0 overruns:0 frame:0 TX packets:686533 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:100 Interrupt:5 Base address:0xac00 privateÇÑ ±¸Á¶Ã¼¸¦ °ü¸®ÇÏ·Á¸é ´ç¿¬È÷ ¸ÕÀú ¸Þ¸ð¸®°ø°£À» È®º¸ÇؾßÇÑ´Ù. ´ÙÀ½°ú °°ÀÌ ÇÑ´Ù. dev->priv = kmalloc(sizeof(struct snull_priv), GFP_KERNEL); if( dev->priv == NULL ) return -ENOMEM ; memset( dev->priv, 0 sizeof(struct snull_priv)); spin_lock_init( &((struct snull_priv *) dev->priv)->lock ) ; ¸¶Áö¸·¿¡¼­ spin_lock_init()Àº ½ºÇɶôÀÎ snull_privÀÇ lockÀ» ÃʱâÈ­Çϴ°ÍÀÌ´Ù. ÀÏ´Ü ½ºÇɶôÀº ±×³É race conditionÀ» ¹æÁöÇϴ°ÍÀ̶ó°í¸¸ ÀÌÇØÇϵµ·Ï ÇÏÀÚ. ¸ðµâ³»¸®±â ^^^^^^^^^^^ ¸ðµâÀ» ³»¸®·Á¸é ´ÙÀ½°ú °°ÀÌ priv¿¡ ÇÒ´çµÈ ¸Þ¸ð¸®¸¦ ÇØÁ¦Çϰí unregister_netdev()·Î¼­ ³×Æ®¿÷ÀåÄ¡ÀÇ µî·ÏÀ» ÇØÁ¦ÇÑ´Ù. void snull_cleanup(void) { int i; for (i=0; i<2; i++) { kfree(snull_devs[i].priv); unregister_netdev(snull_devs + i); } return; } net_device±¸Á¶Ã¼¿¡ ´ëÇØ¼­... ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ À§¿¡¼­ net_device¿¡ ´ëÇÏ¿© Á¶±Ý ¾ð±ÞÇÏ¿´´Ù.¿©±â¼­´Â Á¶±Ý´õ ±íÀÌ µé¾î°¡ º¸µµ·Ï ÇϰڴÙ. ÀÌ ±¸Á¶Ã¼´Â À§¿¡¼­ º¸¾ÒµíÀÌ »ó´çÈ÷ ±æÀ̰¡ ±æ´Ù. Å©°Ô µÎ°¡Áö·Î ³ª´µ´Âµ¥, ù¹øÂ°´Â º¸ÀÌ´Â(visible)Çʵå°ú ¼û°ÜÁø(hidden)ÇʵåÀÌ´Ù.º¸ÀÌ´Â Çʵå´Â ±×³É static±¸Á¶Ã¼¿¡ ¸í½ÃÀûÀ¸·Î °ªÀ» ÇÒ´çÇÒ¼öÀÖ´Â Çʵåµé·Î ±¸¼ºµÈ´Ù.(the visible part of the structure is made up of the fields that can be explicitly assigned in static net_device structure ) ±×³É ½±°Ô ¸»ÇØ º¸ÀÌ´ÂÇʵå´Â ¿ì¸®°¡ ½Å°æ½á¾ßµÇ´ÂºÎºÐÀ̸ç, ¼û°ÜÁø Çʵå´Â Ä¿³Î¿¡¼­ ³»ºÎÀûÀ¸·Î »ç¿ëµÇ´Â°ÍÀ̶ó »ý°¢ÇÏ¸é µÉ°Í°°´Ù. ¸ÕÀú º¸ÀÌ´ÂÇʵ带 »ìÆìº¸ÀÚ. char name[IFNAMSIZ]; À̰ÍÀº ÀåÄ¡ÀÇ À̸§À» ÁöĪÇÑ´Ù. ¿¹¸¦µé¾î ÀÌ´õ³ÝÀåÄ¡·Î eth0,eth1,eth2µîÀ» º¸¾ÒÀ»°ÍÀÌ´Ù. ¿©±â¿¡ %d¸¦ ³ÖÀ¸¸é 0ºÎÅÍ ÀåÄ¡À̸§ÀÌ Áö¾îÁø´Ù. Áï "eth%d"·Î ÇÑ´Ù¸é ¸Ç Ã¹¹øÂ° ÀåÄ¡´Â eth0°¡µÇ°í ±×´ãÀÌ eth1...ÀÌ·±½ÄÀÌ´Ù. unsigned long rmem_end ; unsigned long rmem_start; unsigned long mem_end ; unsigned long mem_start ; ÀåÄ¡°¡ »ç¿ëÇÏ´Â ¸Þ¸ð¸® Á¤º¸ÀÌ´Ù. ¸¸¾à ÆÐŶÀ» ¹ÞÀ»¶§ »ç¿ëµÇ´Â rx¿Í ÆÐŶÀ» º¸³¾¶§ »ç¿ëÇÏ´Â tx¿¡¼­ ´Ù¸¥¿µ¿ªÀÌ ÇÒ´çµÇ¾ú´Ù¸é rmem_ Àº rx¸¦ ÀǹÌÇϰí mem_Àº tx¸¦ ÀǹÌÇÑ´Ù. mem_start, mem_end´Â ºÎÆÃÇÒ¶§ ¸í·É¾î ¶óÀο¡¼­ ÁöÁ¤ÇÒ¼öÀÖÀ¸¸ç, ±×°ªÀº ifconfig·Î¼­ È®ÀÎÇÒ¼öÀÖ´Ù. end - startÇÔÀ¸·Î¼­ »ç¿ëµÇ´Â ¸Þ¸ð¸®¸¦ È®ÀÎÇÒ¼öÀÖ´Ù. ifconfigÀÇ ¸ÇÆäÀÌÁö¿¡ ´ÙÀ½°ú °°Àº ¼³¸íÀÌ ³ª¿Â´Ù. mem_start addr Set the start address for shared memory used by this device. Only a few devices need this. Áï mem_start¸¦ ÀÌ¿ëÇØ ifconfig¿¡¼­ °ªÀ» º¯°æÇÒ¼öÀִٴ°ÍÀÌ´Ù. unsigned long base_addr ; ·£Ä«µå°¡ »ç¿ëÇÏ´Â I/O ÁÖ¼ÒÀÌ´Ù.À̰͵µ ifconfig·Î È®Àΰ¡´ÉÇÏ´Ù. unsigned char irq ; ÇÒ´çµÈ ÀÎÅÍ·´Æ® ¹øÈ£ÀÌ´Ù. ifconfig·Î È®Àΰ¡´ÉÇÏ´Ù. unsigned char if_port ; À̰ÍÀº µÎ°³ÀÌ»óÀÇ Æ÷Æ®°¡ ÀÖ´Â ·£Ä«µåÀÇ °æ¿ì ¾î´À°ÍÀÌ »ç¿ëµÇ´Â°¡¸¦ ³ªÅ¸³½´Ù. ¿¹¸¦µé¾î coaxial , twisted-pairÀÇ µÎ°³°¡ ÀÖÀ»°æ¿ìÀÌ´Ù. (IF_PORT_10BASE2 , IF_PORT_10BASET ) unsigned char dma ; ÀåÄ¡¿¡ ÇÒ´çµÈ dmaä³ÎÀÌ´Ù.À̰ÍÀº isaÀÇ °æ¿ì¿¡ ¾²À̸ç pci´Â ¾È¾²ÀδÙ. unsigned long state ; ÀåÄ¡ÀÇ »óÅÂÀÌ´Ù.À̰ªÀº º¸Åë Á÷Á¢ Á¢±ÙÇÏ¿© ¼öÁ¤ÇÏÁö ¾Ê°í, À̰ªÀ» °ü¸®ÇÏ´Â ÇÔ¼ö°¡ µû·Î Á¸ÀçÇÑ´Ù. struct net_device *next ; ¾Õ¿¡¼­ ³×Æ®¿÷ÀåÄ¡´Â Àü¿ª ¸®½ºÆ®·Î °ü¸®µÈ´Ù°í Çß´Ù. À̰ÍÀº ±× Àü¿ª¸®½ºÆ®¿¡¼­ ´ÙÀ½ ÀåÄ¡¸¦ ÁöĪÇÑ´Ù. À̰ÍÀº ¼öÁ¤µÇ¾î¼­´Â ¾ÈµÈ´Ù. int (*init)(struct net_device *dev) ÃʱâÈ­ ÇÔ¼öÀÌ´Ù. (Âü°í: rtl8139´Â ÀÌ°É »ç¿ëÇÏÁö ¾Ê´Â´Ù.) ÀÌÁ¦ ¼û°ÜÁø ÇʵåµéÀ» »ìÆìº¸µµ·Ï ÇÏÀÚ. ÀϹÝÀûÀ¸·Î ÀÌ ÇʵåµéÀº µå¶óÀ̹ö¸¦ ÃʱâÈ­ÇÒ¶§ ÇÒ´çµÈ´Ù. unsigned mtu ; maximum transfer unit(MTU)ÀÌ´Ù. À̰ÍÀº network layer¿¡¼­ »ç¿ëµÇ´Â°ÍÀÌ´Ù. Áï, IP layer ¿¡¼­ÀÇ ÆÐŶÀÇ Å©±â¸¦ Á¦ÇÑÇϴµ¥ ÀÌ´õ³ÝÀǰæ¿ì 1500ÀÌ´Ù. ±×·¸´Ù¸é ½ÇÁ¦ÀûÀ¸·Î ³×Æ®¿÷¶óÀÎ»ó¿¡ º¸³»Áö´Â ÆÐŶÀÇ ÃÖ´ëÅ©±â´Â ¸îÀϱî? mtu(1500) + ethernet header(14) + pad(4) = 1536ÀÌ´Ù. unsigned long tx_queue_len ; ÀåÄ¡ÀÇ Àü¼ÛÅ¥¿¡ ³ÖÀ»¼öÀÖ´Â ÃÖ´ëÇÑÀÇ ÇÁ·¹ÀÓ¼öÀÌ´Ù.À̰ªÀº ÀÌ´õ³ÝÀǰæ¿ì 100À¸·Î ÇÒ´çµÇ¾îÀÖÀ¸³ª,º¯°æÇÒ¼öµµÀÖ´Ù. ifconfig·Î È®Àΰ¡´ÉÇÏ´Ù. eth0 Link encap:Ethernet HWaddr 00:50:FC:0C:ff:ff ... collisions:0 txqueuelen:100 Interrupt:5 Base address:0xac00 unsigned char addr_len ; unsigned char broadcast[MAX_ADDR_LEN]; unsigned char dev_addr[MAX_ADDR_LEN]; addr_lenÀº ÁÖ¼ÒÀÇ ±æÀÌ·Î ÀÌ´õ³ÝÀǰæ¿ì 6 ¿ÁÅÝ(octets)ÀÌ´Ù. broadcast´Â 6°³ÀÇ ¿ÁÅÝÀÌ 0xff·Î ä¿öÁüÀ¸·Î¼­ ÀÌ·ïÁø´Ù. dev_addr Àº Çϵå¿þ¾î ÁÖ¼Ò¸¦ ³ªÅ¸³»´Â°ÍÀ¸·Î À̰ªÀº ·£Ä«µå¸¶´Ù °íÀ¯ÇÏ°Ô °®°íÀְԵǸç, ¸ðµâÃʱâÈ­½Ã ·£Ä«µåÀÇ EEPROM¿¡¼­ Àоî¿À°ÔµÈ´Ù. <Âü°í>--------------------------------------------------------- ³×Æ®¿÷¿¡¼­´Â byte´ë½Å octetÀ̶ó´Â ¿ë¾î°¡ »ç¿ëµÈ´Ù. ±×³É ¶È°°ÀÌ ÀÌÇØÇÏ¸é º°»ó°üÀº ¾øÀ»°ÍÀÌ´Ù. --------------------------------------------------------------- unsigned short flags ; ÀÌ Ç÷¡±×´Â °¢°¢ÀÇ ÀåÄ¡ÀÇ µ¶Æ¯ÇÑ ¼Ó¼ºÀ» ÁöÁ¤ÇÏ°Ô µÈ´Ù. ¾Õ¿¡ IFF_¶ó´Â prefix°¡ ÀÖÀ¸¸ç, ¿¡ ¸ðµÎ ¼±¾ðµÇ¾îÀÖ´Ù. ¸î¸îÀº Ä¿³Î¿¡ÀÇÇØ ³»ºÎÀûÀ¸·Î »ç¿ëµÇ°í,¸î¸îÀº ÃʱâÈ­½Ã »ç¿ëµÈ´Ù. ´ÙÀ½°ú °°Àº °ªµéÀÌ °¡´ÉÇÏ´Ù. ---------------------------------------------------------------------- /* Standard interface flags. */ #define IFF_UP 0x1 /* interface is up */ #define IFF_BROADCAST 0x2 /* broadcast address valid */ #define IFF_DEBUG 0x4 /* turn on debugging */ #define IFF_LOOPBACK 0x8 /* is a loopback net */ #define IFF_POINTOPOINT 0x10 /* interface is has p-p link */ #define IFF_NOTRAILERS 0x20 /* avoid use of trailers */ #define IFF_RUNNING 0x40 /* resources allocated */ #define IFF_NOARP 0x80 /* no ARP protocol */ #define IFF_PROMISC 0x100 /* receive all packets */ #define IFF_ALLMULTI 0x200 /* receive all multicast packets*/ #define IFF_MASTER 0x400 /* master of a load balancer */ #define IFF_SLAVE 0x800 /* slave of a load balancer */ #define IFF_MULTICAST 0x1000 /* Supports multicast */ #define IFF_VOLATILE (IFF_LOOPBACK|IFF_POINTOPOINT|IFF_BROADCAST|IFF_MASTER|IFF_SLAVE|IFF_RUNNING) #define IFF_PORTSEL 0x2000 /* can set media type */ #define IFF_AUTOMEDIA 0x4000 /* auto media select active */ #define IFF_DYNAMIC 0x8000 /* dialup device with changing addresses*/ ------------------------------------------------------------------------ ´Ù¸¥°ªµéÀº Âü°í¸¸Çϰí IFF_PROMISC,IFF_ALLMULTI Ç÷¡±×´Â ²À ¾Ë¾ÆµÎÀÚ. ¿Ö³ÄÇÏ¸é ¿ì¸®°¡ ºÐ¼®ÇÒ 8139too.c¿¡¼­ »ç¿ëµÇ±â ¶§¹®ÀÌ´Ù. IFF_PROMISC À̰ÍÀº ÀÚ±âÀÇ Çϵå¿þ¾î ÁÖ¼Ò¿¡ ÇØ´çÇÏ´Â ÆÐŶ»Ó¾Æ´Ï¶ó. ·£¿¡ µ¹¾Æ´Ù´Ï´Â ¸ðµç ÆÐŶÀ» Àâ´Â °ÍÀÌ´Ù. tcpdump´Â ÀÌÇ÷¡±×¸¦ ÀÌ¿ëÇÏ¿© ÆÐŶÀ» ¸ðµÎ Àâ´Â´Ù. IFF_MULTICAST ¸ÖƼij½ºÆ® ÆÐŶÀ» º¸³»´Â°ÍÀ» °¡´ÉÇϰÔÇÑ´Ù. À̰ÍÀº µðÆúÆ®·Î "Çã¿ë"À̹ǷΠ¸¸ÀÏ ¸ÖƼij½ºÆ®ÆÐŶÀ» º¸³»Áö ¸øÇϵµ·ÏÇÏ·Á¸é, ÃʱâÈ­½Ã ÀÌÇ÷¡±×¸¦ ²¨ÁÖ¾î¾ßÇÑ´Ù. IFF_ALLMULTI ¸ðµç ¸ÖƼij½ºÆ® ÆÐŶÀ» ¹Þµµ·ÏÇÑ´Ù.Ä¿³ÎÀº ÇØ´ç È£½ºÆ®°¡ ¸ÖƼij½ºÆ® ¶ó¿ìÆÃÀ» ÇÒ¶§, IFF_MULTICAST°¡ ÄÑÁ®Àִ¶§¿¡ ÇÑÇÏ¿© ÀÌ Ç÷¡±×¸¦ ¼¼ÆÃÇÑ´Ù. À̰ªÀº read-onlyÀÌ´Ù. ÀÌ·¯ÇÑ Ç÷¡±×µéÀÌ ¼öÁ¤µÇ¸é Á¦ÀϸÕÀú net_deviceÀÇ set_multicase_list°¡ ½ÇÇàµÈ´Ù.±×·¯¹Ç·Î Ç÷¡±×°¡ º¯°æµÇ¾úÀ»¶§ ½ÇÇàµÇ¾ßÇÒ ÀÛ¾÷ÀÌ ÀÖ´Ù¸é set_multicast_list¿¡ ³Öµµ·ÏÇÑ´Ù. * ÀÌÁ¦ net_deviceÇʵåµéÁß¿¡¼­ ÇÔ¼öµéÀ» »ìÆìº¸µµ·ÏÇÏÀÚ.ÀÌ¹Ì ¸î°¡Áö´Â ¾Õ¿¡¼­ ¾ð±ÞÇßÁö¸¸,´Ù½ÃÇѹø »ìÆìº¸´Â ¸¶À½À¸·Î »ìÆìº¸µµ·ÏÇÏÀÚ. ºí·ÏÀ̳ª ¹®ÀÚÀåÄ¡¿Í °°ÀÌ ³×Æ®¿÷ÀåÄ¡µµ ÀåÄ¡¸¦ ´Ù·ç´Â ¿©·¯°¡Áö ÇÔ¼öµéÀÌ Á¸ÀçÇÑ´Ù. ¹®ÀÚ³ª ºí·ÏÀåÄ¡´Â file_operations±¸Á¶Ã¼¿¡ À̰ªµéÀ» ¼¼ÆÃÇϳª, ³×Æ®¿÷ÀåÄ¡´Â net_device±¸Á¶Ã¼¿¡ ¼¼ÆÃÇÑ´Ù. À̰ªµéÁß ¾î¶²°ªÀº NULL·Î ¼¼ÆÃ ÇÒ¼öµµ ÀÖ´Ù. ±×·³ ÇϳªÇϳª ¾Ë¾Æº¸µµ·ÏÇÏÀÚ. int (*open)(struct net_device *dev); ifconfig eth0 up °ú °°Àº ¸í·ÉÀ» ÇßÀ»¶§ ½ÇÇàµÇ´Â ÇÔ¼öÀÌ´Ù. ¿©±â¼­´Â I/O ports , IRQ, DMAµîÀÇ ¸®¼Ò½º¸¦ µî·Ï,usage countÁõ°¡ µîÀÇ ÀÛ¾÷À» ÇÑ´Ù. int (*stop)(struct net_device *dev); ifconfig eth0 down°ú °°Àº ¸í·ÉÀ» ÇßÀ»¶§ ½ÇÇàµÇ¸ç, open¿¡¼­ ÇÒ´ç¹ÞÀº ¸®¼Ò½º µéÀ» ¹Ý³³ÇÏ´Â ÀÛ¾÷µîÀ» ÇÑ´Ù. int (*hard_start_xmit)(struct sk_buff *skb, struct net_device *dev) ÆÐŶÀ» ¿ÜºÎ·Î Àü¼ÛÇϱâÀ§ÇÑ ÃʱâÈ­ ÀÛ¾÷À» ½ÇÇàÇÑ´Ù. ¿ÜºÎ·Î º¸³»Áú ¸ðµçµ¥ÀÌÅÍ´Â sk_buff±¸Á¶Ã¼¿¡¼­ °ü¸®ÇÑ´Ù. void (*tx_timeout)(struct net_device *dev); ÆÐŶÀ» Àü¼ÛÇϴ°Ϳ¡ ´ëÇÑ timeoutÀÌ´Ù. Áï, ¼³Á¤µÈ ½Ã°£¸¸Å­ ±â´Ù·È´Âµ¥, ÆÐŶÀÌ Àü¼ÛµÇÁö ¸øÇß´Ù¸é, ÀçÀü¼Ûµî, ¾î¶°ÇÑ ÀÛ¾÷À» ÇØÁÖ¾î¾ß ÇÑ´Ù. struct net_device_stats *(*get_stats)(struct net_device *dev ); ÀåÄ¡¿¡´ëÇÑ Á¤º¸¸¦ ¿äûÇÒ¶§ ÀÌÇÔ¼ö°¡ ½ÇÇàµÈ´Ù. ¿¹¸¦µé¾î... ifconfig, netstat -i µîÀÌ µÇ°Ú´Ù. int (*do_ioctl)(struct net_device *dev, struct ifreg *ifr, int cmd); ioctl¸í·É¾î.»ç¿ëÇÏÁö ¾ÊÀ»·Á¸é NULL·Î ÁöÁ¤Çصµ »ó°ü¾ø´Ù. void (*set_multicast_list)(struct net_device *dev); ³×Æ®¿÷ÀåÄ¡¿¡´ëÇÑ ¸ÖƼij½ºÆ® ¸®½ºÆ®(multicast list)°¡ º¯°æµÇ¾ú°Å³ª Ç÷¡±×°¡ º¯°æµÇ¾úÀ»¶§ ½ÇÇàµÈ´Ù. *ÀÌÁ¦ ÀåÄ¡¿¡´ëÇÑ À¯¿ëÇÑ Á¤º¸µîÀ» Æ÷ÇÔÇÑ Àâ´ÙÇÑ ÇʵåµéÀ» ¾Ë¾Æº¸ÀÚ. unsigned long trans_start ; unsigned long last_rx ; trans_start´Â Àü¼ÛÀ» Àü¼ÛÇÑ ½Ã°£À» jiffies°ªÀ¸·Î °®°íÀÖ°í, last_rx´Â °¡Àå ÃÖ±Ù¿¡ ÆÐŶÀ» ¹ÞÀº ½Ã°£À» jiffies°ªÀ¸·Î °®°íÀÖ´Ù. int watchdog_timeo ; À̰ªµµ jiffies°ªÀ¸·Î ÁöÁ¤µÇ¸ç, ÀÌ ½Ã°£µ¿¾È Àü¼ÛµÇÁö ¸øÇß´Ù¸é, tx_timeout ÇÔ¼ö°¡ ½ÇÇàµÈ´Ù. void *priv ; ÀåÄ¡ÀÇ private µ¥ÀÌÅ͸¦ ÀúÀåÇϴ°÷ÀÌ´Ù. struct dev_mc_list *mc_list ; int mc_count ; À̵ΰ³ÀÇ Çʵå´Â ¸ÖƼij½ºÆ® Àü¼ÛÀ» °ü¸®Çϴµ¥ »ç¿ëµÈ´Ù. ¿©±â¼­ ¼³¸íÇÏÁö ¾ÊÀº net_device ÇʵåµéÀÌ ¸¹ÀÌ ÀÖÁö¸¸, ±×°ÍµéÀº ³×Æ®¿÷ µå¶óÀÌ ¹ö¿¡ »ç¿ëµÇÁö ¾Ê´Â´Ù. ¶ÇÇÑ ³×Æ®¿÷ µå¶óÀ̹ö¿¡ »ç¿ëµÈ´Ù ÇÏ´õ¶óµµ, ¿ì¸®ÀÇ ¸ñÇ¥ÀÎ 8139too.c¿¡ »ç¿ëµÇÁö ¾Ê´Â°ÍÀº ¹èÁ¦ÇÏ¿´´Ù. ÇÊ¿äÇѰÍÀº ÇÊ¿äÇѶ§... ^_^ ±×·³ ´ÙÀ½½Ã°£¿¡.... :) ¡º¸®´ª½º Çдç-¸®´ª½º °­Á / ¿¬Àç (go LINUX)¡» 737¹ø Á¦ ¸ñ:[°­ÁÂ]Network Device Driver¸¸µé±â [2] ¿Ã¸°ÀÌ:hetta (À̱âõ ) 01/10/21 17:42 ÀÐÀ½:109 °ü·ÃÀÚ·á ¾øÀ½ ----------------------------------------------------------------------------- ######################################## #°­ÁÂ: Network Device Driver¸¸µé±â # # (ºÎÀç: ¾ÖÀθ¸µé±â) # ######################################## 1ºÎ: ³×Æ®¿öÅ© µå¶óÀ̹öÀÇ ±âº»(2) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ À̾߱â²Û:À̱âõ(hetta@nownuri.net) ³×Æ®¿÷ÀåÄ¡¸¦ ¿­±â¿Í ´Ý±â ~~~~~~~~~~~~~~~~~~~~~~~~ À̺κÐÀº Á¶±Ý Áߺ¹µÇ´Â³»¿ëµµ ÀÖ´Ù. Á¤¸®Çϴ±âºÐÀ¸·Î º¸¸éµÉ°Í°°´Ù. ifconfig eth0 111.111.111.111 up ÀÌ·±½ÄÀ¸·Î ÇßÀ»¶§ ´ÙÀ½°ú °°Àº µÎ°¡Áö »ç°ÇÀÌ ¹ß»ýÇÑ´Ù. ù°·Î ioctl(SIOCSIFADDR)·Î ÀÎÅÍÆäÀ̽ºÁÖ¼Ò¸¦ ¼¼ÆÃÇÑ´Ù. À̰ÍÀº µå¶ó À̹ö¿¡¼­ ±¸ÇöÇϴ°ÍÀÌ ¾Æ´Ï¶ó Ä¿³Î¿¡¼­ ÇÏ´ÂÀÛ¾÷ÀÌ´Ù. µÑ°·Î, ioctl(SIOCSIFFLAGS)¸¦ »ç¿ëÇÏ¿© dev->flag¸¦ IFF_UPÀ¸·Î ¸¸µç´Ù.·£Ä«µå ¸¦ ¾µ¼öÀÖµµ·Ï Ȱ¼ºÈ­½Ã۴°ÍÀÌ´Ù. ±×´ÙÀ½ net_device¿¡¼­ Á¤ÀÇÇÑ openÇÔ¼ö¸¦ ½ÇÇàÇÑ´Ù. openÀº Àú¹ø½Ã°£¿¡µµ ¼³¸íÇßµíÀÌ, ÀåÄ¡°¡ ÇÊ¿ä·ÎÇÏ´Â °¢Á¾ ¸®¼Ò½ºµéÀ» ÇÒ´ç¹Þ´Â ´Ù.±×¹Û¿¡µµ ¿©·¯°¡Áö ÀÛ¾÷ÀÌ Open¿¡¼­ ½ÇÇàµÈ´Ù. ù°,Çϵå¿þ¾î ÁÖ¼Ò¸¦ dev->dev_addr ¿¡ º¹»çÇÑ´Ù. µÑ°, open¿¡¼­´Â ÀÎÅÍÆäÀ̽ºÀÇ Àü¼ÛÅ¥(interface's transmit queue)¸¦ ½ÃÀÛÇϱâ À§ÇÏ¿© netif_start_queue(struct net_device *dev); ¸¦ È£ÃâÇÏ°Ô µÈ´Ù. ÀÌÀÛ ¾÷ÀÌ ½ÇÇàµÇ¾î¾ß ÆÐŶÀ» ¿ÜºÎ·Î Àü¼ÛÇÒ¼ö°¡ Àֱ⶧¹®ÀÌ´Ù. ifconfig eth0 down µîÀÇ ¸í·ÉÀ» ÇÒ¶§ closeÇÔ¼ö°¡ ½ÇÇàµÇ°í À̶§´Â, netif_stop_queue()¸¦ È£ÃâÇÑ´Ù. À̰ÍÀº netif_start_queue()¿Í ¹Ý´ë°¡ µÇ´Â ÀÛ¾÷À¸·Î ÆÐŶÀ» ´õÀÌ»ó Àü¼ÛÇÒ¼ö¾øµµ·Ï ÇÑ´Ù. ÆÐŶÀü¼ÛÇϱâ ~~~~~~~~~~~~~ °á±¹ ³×Æ®¿÷ µð¹ÙÀ̽º µå¶óÀ̹ö´Â ¹«½¼ÀÏÀ» ÇÒ±î? "Àß¹Þ°í", "Àߺ¸³»°í", ÀÌ·¯´Â°ÍÀÌ µå¶óÀ̹ö°¡ ÇÏ´Â ÀÏÀÇ ÀüºÎ°¡ ¾Æ´Ò±îÇÑ´Ù. ³ª¸ÓÁöµéÀº ÀÌ·¯ÇÑ ÀÛ¾÷µéÀ» È¿À²ÀûÀ¸·Î Çϵµ·Ï µµ¿ÍÁÖ´Â ¿ªÈ°À» Çϴ°ÍÀÌ´Ù. ÆÐŶÀ» ¹Þ´Â°Íº¸´Ù º¸³»´Â°ÍÀÌ ´õ ½±±â¶§¹®¿¡ º¸³»´Â°ÍÀ» ¸ÕÀú ¾Ë¾Æº¸ÀÚ. ÆÐŶÀ» Àü¼ÛÇÒÇʿ䰡 ÀÖÀ»¶§¸¶´Ù, hard_start_transmit ÇÔ¼ö°¡ È£ÃâµÈ´Ù.ÀÌÇÔ¼ö °¡ ÇÏ´ÂÀÏÀº ³ª°¡´ÂÅ¥(outgoing queue)¿¡´Ù°¡ µ¥ÀÌÅ͸¦ ³õ´Â°ÍÀÌ´Ù. ¼ÒÄϹöÆÛ(socket buffer)´Â struct sk_buff ±¸Á¶Ã¼·Î ¸¸µé¾îÁø´Ù. Áï ÇϳªÀÇ ÆÐŶÀº sk_buff±¸Á¶Ã¼·Î Ç¥ÇöµÈ´Ù°í ÇÒ¼öÀÖ´Ù. ´ÙÀ½°ú °°ÀÌ »ý°å´Ù --------------------------------------------------------------------- struct sk_buff { /* These two members must be first. */ struct sk_buff * next; /* Next buffer in list */ struct sk_buff * prev; /* Previous buffer in list */ struct sk_buff_head * list; /* List we are on */ struct sock *sk; /* Socket we are owned by */ struct timeval stamp; /* Time we arrived */ struct net_device *dev; /* Device we arrived on/are leaving by */ /* Transport layer header */ union { struct tcphdr *th; struct udphdr *uh; struct icmphdr *icmph; struct igmphdr *igmph; struct iphdr *ipiph; struct spxhdr *spxh; unsigned char *raw; } h; /* Network layer header */ union { struct iphdr *iph; struct ipv6hdr *ipv6h; struct arphdr *arph; struct ipxhdr *ipxh; unsigned char *raw; } nh; /* Link layer header */ union { struct ethhdr *ethernet; unsigned char *raw; } mac; struct dst_entry *dst; /* * This is the control buffer. It is free to use for every * layer. Please put your private variables there. If you * want to keep them across layers you have to do a skb_clone() * first. This is owned by whoever has the skb queued ATM. */ char cb[48]; unsigned int len; /* Length of actual data */ unsigned int data_len; unsigned int csum; /* Checksum */ unsigned char __unused, /* Dead field, may be reused */ cloned, /* head may be cloned (check refcnt to be sure). */ pkt_type, /* Packet class */ ip_summed; /* Driver fed us an IP checksum */ __u32 priority; /* Packet queueing priority */ atomic_t users; /* User count - see datagram.c,tcp.c */ unsigned short protocol; /* Packet protocol from driver. */ unsigned short security; /* Security level of packet */ unsigned int truesize; /* Buffer size */ unsigned char *head; /* Head of buffer */ unsigned char *data; /* Data head pointer */ unsigned char *tail; /* Tail pointer */ unsigned char *end; /* End pointer */ void (*destructor)(struct sk_buff *); /* Destruct function */ #ifdef CONFIG_NETFILTER /* Can be used for communication between hooks. */ unsigned long nfmark; /* Cache info */ __u32 nfcache; /* Associated connection, if any */ struct nf_ct_info *nfct; #ifdef CONFIG_NETFILTER_DEBUG unsigned int nf_debug; #endif #endif /*CONFIG_NETFILTER*/ #if defined(CONFIG_HIPPI) union{ __u32 ifield; } private; #endif #ifdef CONFIG_NET_SCHED __u32 tc_index; /* traffic control index */ #endif }; -------------------------------------------------------------------------- ¹°·Ð ÀÌ·± ÇʵåµéÀ» ´Ù ¾Ë¾Æ¾ß¸¸ ÇѴٴ°ÍÀº ¾Æ´Ï´Ù. sk_buff±¸Á¶Ã¼´Â »ó´çÈ÷ º¹ÀâÇÑ ±¸Á¶Ã¼À̹ǷΠÀ̰ÍÀ» ´Ù·ç´Â ´Ù¾çÇÑ ÇÔ¼öµéÀÌ Á¦°øµÇ¸ç µÚ¿¡¼­ ¼³¸íÇÒ °ÍÀÌ´Ù. struct sk_buff¸¦ ÂüÁ¶ÇÒ¶§ skb¸¦ »ç¿ëÇϰڴÙ. hard_start_xmitÀÌ È£ÃâµÉ¶§ Àü´ÞµÇ´Â socket buffer´Â ¿Ïº®ÇÑ ÆÐŶÀÇ ÇüŸ¦ °®°ÔµÈ´Ù.Áï, ÀÎÅÍÆäÀ̽º(·£Ä«µå)¿¡¼­ ¾î¶°ÇÑ µ¥ÀÌÅÍ ¼öÁ¤µµ Çʿ䰡 ¾ø´Ù. ±×³É ºñÆ®ÀÇ ¿¬¼ÓÀ̶ó°í »ý°¢Çϰí Àü¼ÛÇÏ¸é µÈ´Ù. skb->data´Â Àü¼ÛµÇ¾îÁö´Â ÆÐŶÀÇ µ¥ÀÌÅ͸¦ °¡¸£Å²´Ù.skb->lenÀº ±æÀ̸¦ ³ªÅ¸³»¸ç ´ÜÀ§´Â ¿ÁÅÝ(¹ÙÀÌÆ®)ÀÌ´Ù. snull¿¡¼­´Â snull_tx·Î ÆÐŶÀü¼ÛÀ» ó¸®ÇÑ´Ù. snull¿¡ ´ëÇØ ¼¼ºÎÀûÀ¸·Î ¾Ë·Á°í ÇÒÇÊ¿ä´Â ¾ø´Ù°í º»´Ù. ±×·¯³ª ÀüüÀûÀÎ È帧Àº ½ÇÁ¦ µå¶óÀ̹ö¿Í ºñ½ÁÇϹǷΠ¿©±â¼­ º¸µµ·Ï ÇÏÀÚ. Àú¹ø½Ã°£¿¡ ³ª¿ÔµíÀÌ ÃʱâÈ­½Ã snull_init¿¡¼­ ´ÙÀ½°ú °°Àº ¼¼ÆÃÀ» ÇÑ´Ù. int snull_init(struct net_device *dev) { ... dev->open = snull_open; dev->stop = snull_release; dev->set_config = snull_config; dev->hard_start_xmit = snull_tx; dev->do_ioctl = snull_ioctl; ... } ¿©±â¼­ dev->hard_start_xmit ÀÌ snull_tx·Î ¼¼ÆÃµÇ¾úÀ½À» º¼¼öÀÖ´Ù. ±×·¯¹Ç·Î Ä¿³ÎÀº ÆÐŶÀ» Àü¼ÛÇØ¾ßÇÒ°æ¿ì¿¡ snull_tx¸¦ È£ÃâÇÏ°Ô µÈ´Ù. snull_txÀÇ ±¸ÇöÀ» »ìÆìº¸µµ·Ï ÇÏÀÚ. ----------------------------------------------------------------------- /* * Transmit a packet (called by the kernel) */ int snull_tx(struct sk_buff *skb, struct net_device *dev) { int len; char *data; struct snull_priv *priv = (struct snull_priv *) dev->priv; len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; data = skb->data; dev->trans_start = jiffies; /* save the timestamp */ /* Remember the skb, so we can free it at interrupt time */ priv->skb = skb; /* actual deliver of data is device-specific, and not shown here */ snull_hw_tx(data, len, dev); //¹«½ÃÇÏÀÚ. return 0; /* Our simple device can not fail */ } --------------------------------------------------------------------- snull¿¡¼­´Â °¡»óÀåÄ¡À̹ǷΠÇϵå¿þ¾îÀåÄ¡¿¡ ´ëÇÑ ½ÇÁ¦ÀûÀü¼ÛÀ» snull_hw_tx()·Î Ç¥ÇöÇÏ¿´´Ù. ½ÇÁ¦Àû Çϵå¿þ¾î Àü¼ÛÀº DMAµîÀ» »ç¿ëÇÏ¿© Àü¼ÛÇÑ´Ù.Àϴܹ«½ÃÇÏÀÚ. ½ÇÁ¦Àû »óȲ¿¡¼­ ¹ß»ýÇÒ¼öÀÖ´Â ¹®Á¦ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ hard_start_xmitÇÔ¼ö´Â net_deviceÀÇ xmit_lock·Î race condition¹®Á¦¸¦ ÇØ°áÇÔ À» Àú¹ø½Ã°£¿¡ º¸¾Ò´Ù. ±×·¯³ª ÀÌÀüÀÛ¾÷ÀÌ ³¡³ª¸é °ð¹Ù·Î ´Ù½Ã È£ÃâµÈ´Ù. ¸Þ¸ð¸®°¡ ºÎÁ·Çϰųª, ´Ù¸¥ °÷¿¡¼­ ±×½Ã°£¿¡ ÆÐŶÀÌ Àü¼ÛÁßÀ̶ó¸é Àá½Ã Àü¼ÛÀ» Áö¿¬ÇÒÇʿ䰡 ÀÖ´Ù. À̶§ netif_stop_queue¸¦ »ç¿ëÇÑ´Ù. ¶ÇÇÑ Àü¼ÛÀÌ °¡´ÉÇØÁö¸é netif_wake_queue¸¦ È£ÃâÇÑ´Ù. void netif_wake_queue( struct net_devic *dev); netif_wake_queue´Â netif_start_queue¿Í ºñ½ÁÇϳª, netif_wake_queue´Â ´Ù½Ã Àü¼ÛÀ» °¡´ÉÇÏ°Ô ÇØÁشٴ°ÍÀÌ °¡´ÉÇÏ´Ù. ¿äÁò³ª¿À´Â Çϵå¿þ¾î´Â Àü¼ÛÅ¥¸¦ ¿©·¯°³ °®°íÀÖ´Ù. RTL8139¿¡¼­µµ 4°³ÀÇ Àü¼ÛÅ¥ ¸¦ °ü¸®ÇÔÀ» È®ÀÎÇÒ¼öÀÖ´Ù. Àü¼Û ŸÀӾƿô ~~~~~~~~~~~~~~~ ½ÇÁ¦ ³×Æ®¿÷»óȲÀº ¿¹ÃøºÒÇãÀ̹ǷΠ¿©·¯°¡Áö ¿äÀÎÀ¸·Î ÆÐŶ Àü¼ÛÀ» È®ÀÎÇÏ´Â ack°¡ ¾È¿Ã¼öµµ ÀÖ´Ù. ÀÌ·²°æ¿ì, ¸¸¾à ŸÀӾƿô°ªÀ» ¼¼ÆÃÇØµÎÁö ¾Ê´Â´Ù¸é ¹«ÇÑÁ¤À¸·Î ÆÐŶÀü¼Û È®ÀÎ ÆÐŶÀ» ±â´Ù¸®°Ô µÈ´Ù. Àú¹ø½Ã°£¿¡µµ ³ª¿Â³»¿ëÀÌÁö¸¸ ¸®´ª½º´Â ŸÀӾƿô°ªÀ» ¼¼ÆÃÇÔÀ¸·Î À̰ÍÀ» ¹æÁö ÇÑ´Ù. ÆÐŶÀÌ dev->trans_start¿¡ ¼¼ÆÃÇÑ °ªºÎÅÍ dev->watchdog_timeo °ª¿¡ ¼¼ÆÃÇÑ jiffies°ª¸¸Å­±â´Ù·Áµµ ÆÐŶÀü¼Û È®ÀÎÀÌ ¾ÈµÉ°æ¿ì dev->tx_timeoutÇÔ¼ö°¡ È£ÃâµÈ´Ù. snullÀÇ °æ¿ì´Â snull_tx_timeoutÇÔ¼ö°¡ È£ÃâµÈ´Ù. ´ÙÀ½°ú °°ÀÌ ±¸ÇöµÇ¾úÀ¸¸ç, ´ëÃæ È帧¸¸À» ¾Ë¾Æº¸µµ·ÏÇÏÀÚ. ------------------------------------------------------------------ /* * Deal with a transmit timeout. */ void snull_tx_timeout (struct net_device *dev) { struct snull_priv *priv = (struct snull_priv *) dev->priv; PDEBUG("Transmit timeout at %ld, latency %ld\n", jiffies, jiffies - dev->trans_start); priv->status = SNULL_TX_INTR; snull_interrupt(0, dev, NULL); priv->stats.tx_errors++; netif_wake_queue(dev); return; } ------------------------------------------------------------------ ŸÀӾƿôÀÌ ¹ß»ýÇÏ¸é ³õÄ£ ÀÎÅÍ·´Æ®¸¦ ä¿ì±âÀ§ÇÏ¿© snull_interrupt¸¦ È£Ãâ ÇÑ´Ù. ±×¸®°í ´Ù½ÃÇѹø Àü¼ÛÀ» ½ÃµµÇÏ°Ô µÈ´Ù. ( when a timeout happens in snull, the driver calls snull_nterrupt to fill in the "missing" interrupt and restarts the transmit queu with netif_wake_queue.) ÆÐŶ ¹Þ±â ~~~~~~~~~~ ÀÌÁ¦ ÆÐŶÀ» ¾î¶»°Ô ¹ÞÀ»°ÍÀΰ¡¸¦ ¾Ë¾Æº¸µµ·ÏÇÏÀÚ.ÆÐŶÀ» ¹Þ´Â°ÍÀº Àü¼ÛÇÏ´Â°Í º¸´Ù Á¶±Ý º¹ÀâÇÏ´Ù. »ç½Ç ½ÇÁ¦ Çϵå¿þ¾î¿¡¼­ ÇÏ´ÂÀÛ¾÷Àº ¸¹ÀÌ Æ²¸®¹Ç·Î snullÀÇ °ÍÀ» º¸´Â°ÍÀÌ º°µµ¿òÀº ¾ÈµÇ°ÚÁö¸¸, È帧¸¸À» ¾Ë¾Æº¸ÀÚ. ¸ÕÀú ·£Ä«µå¿¡¼­ ¹ÞÀº ÆÐŶÀ» ÀúÀåÇÒ sk_buff¸¦ ÇÒ´çÇØ¾ßÇÑ´Ù.ÆÐŶÀ» ¹Þ´Â°ÍÀº interrupt¸¦ ÅëÇØ¼­ÀÌ´Ù. Áï, ·£Ä«µå¿¡¼­ ¾î´À ÀÏÁ¤·®ÀÌ»ó µ¥ÀÌÅͰ¡ ¿À¸é, ·£Ä«µå °¡ ÀÎÅÍ·´´À¸¦ ¹ß»ýÇÑ´Ù.±×·¯¸é µå¶óÀ̹ö¿¡¼­ ÀÛ¾÷À» ó¸®Çϴ½ÄÀÌ´Ù. ¾î´À ÀÏÁ¤ ·®À̶ó´Â°ÍÀº ÀÓÀ¸·Î ¼³Á¤ÀÌ °¡´ÉÇÏ´Ù. ¹°·Ð polling ¹æ½ÄÀ¸·Î ÆÐŶ¹Þ±â¸¦ ó¸®Çϴ°͵µ °¡´ÉÇϳª È¿À²¼º¸é¿¡¼­ interrupt¸¦ ÀÌ¿ëÇÑ ¹æ½ÄÀÌ À¯¸®ÇÏ´Ù.´ëºÎºÐÇϵå¿þ¾î°¡ interrupt¸¦ »ç¿ëÇÑ´Ù. ----------------------------------------------------------------- /* * Receive a packet: retrieve, encapsulate and pass over to upper levels */ void snull_rx(struct net_device *dev, int len, unsigned char *buf) { struct sk_buff *skb; struct snull_priv *priv = (struct snull_priv *) dev->priv; /* * The packet has been retrieved from the transmission * medium. Build an skb around it, so upper layers can handle it */ skb = dev_alloc_skb(len+2); if (!skb) { printk("snull rx: low on mem - packet dropped\n"); priv->stats.rx_dropped++; return; } skb_reserve(skb, 2); /* align IP on 16B boundary */ memcpy(skb_put(skb, len), buf, len); /* Write metadata, and then pass to the receive level */ skb->dev = dev; skb->protocol = eth_type_trans(skb, dev); skb->ip_summed = CHECKSUM_UNNECESSARY; /* don't check it */ priv->stats.rx_packets++; priv->stats.rx_bytes += len; netif_rx(skb); return; } ----------------------------------------------------------------- ¸ÕÀú dev_alloc_skb¸¦ »ç¿ëÇÏ¿© skb¸¦ À§ÇÑ °ø°£À» ¸¶·ÃÇÑ´Ù. ¿©±â¼­ +2´Â 16ºñÆ®·Î Á¤·ÄÇϱâ À§ÇÏ¿© ÇÊ¿äÇÑ ÀÛ¾÷ÀÌ´Ù.¿Ö³ÄÇϸé ÀÌ´õ³ÝÇì´õ´Â 14ºñÆ® À̱⶧¹®ÀÌ´Ù. ±×´ÙÀ½ skb_reserve·Î ¾Õ¿¡ 2ºñÆ®¸¦ ¿¹ºñÇØµÐ´Ù. ±×´ÙÀ½ memcpy¸¦ »ç¿ëÇÏ¿© bufÀÇ µ¥ÀÌÅ͸¦ º¹»çÇÏ°Ô µÈ´Ù. skb_put()Àº skbÀÇ µÚ¿¡ µ¥ÀÌÅ͸¦ ºÙÀ̰íÀÚ ÇÒ¶§ »ç¿ëÇÑ´Ù. ¾Õ¿¡¼­ 2ºñÆ®¸¦ ¿¹ºñÇßÀ¸¹Ç·Î ±×´ÙÀ½¿¡ ÀÌ´õ³ÝÇì´õ 14¹ÙÀÌÆ® µîÀÌ µé¾î°¡¼­ 16ºñÆ®·Î Á¤·Ä(align)µÈ´Ù. Âü°í·Î, dev_alloc_skb()´Â ³»ºÎÀûÀ¸·Î kmalloc¸¦ atomic priority·Î È£ÃâÇϹǷΠÀÎÅÍ·´Æ® ¹ß»ýÁßÀ϶§ »ç¿ëÀÌ °¡´ÉÇÏ´Ù. ±×´ÙÀ½ üũ¼¶À» ¾î¶»°Ô ó¸®ÇÒ°ÍÀΰ¡¸¦ ¼¼ÆÃÇÑ´Ù. snullÀº °¡»óÀåÄ¡¶ó¼­ CHECKSUM_UNNECESSARYÀ» ¼¼ÆÃÇϳª ½Å°æ¾²Áö ¸»±â ¹Ù¶õ´Ù. 3°¡Áö°¡ Á¸ÀçÇϴµ¥ ´ÙÀ½°ú °°´Ù. CHECKSUM_HW - Çϵå¿þ¾î·Î üũ¼¶À» °ü¸®ÇÑ´Ù. CHECKSUM_NONE - ¼ÒÇÁÆ®¿þ¾î·Î üũ¼¶À» °ü¸®ÇÑ´Ù. µðÆúÆ® °ªÀÌ´Ù. rtl8139 CHECK_UNNECESSARY - ÇÊ¿ä¾øÀ½ ±×¸®°í protocolÀº eth_type_trans·Î °£´ÜÈ÷ ¼¼ÆÃÀÌ °¡´ÉÇÏ´Ù. ÃÖÁ¾ÀûÀ¸·Î netif_rx()¸¦ È£ÃâÇÏ¿©¼­ À­´Ü°è(ex: IP layer)·Î ÆÐŶÀ» Àü¼ÛÇÑ´Ù. ÀÎÅÍ·´Æ® Çڵ鷯 ~~~~~~~~~~~~~~~~ ÆÐŶÀ» ó¸®ÇÒ¶§ ÀÎÅÍ·´Æ®¸¦ ÀÌ¿ëÇÑ´Ù°íÇß´Ù. ÀÌÁ¦ ÀÎÅÍ·´Æ® Çڵ鷯¸¦ »ìÆìº¸ÀÚ. ³×Æ®¿÷ÀåÄ¡¿¡¼­ ÀÎÅÍ·´Æ®´Â ÆÐŶÀÌ ¿ÔÀ»¶§¿Í ÆÐŶÀü¼ÛÀÌ ¿Ï·áµÇ¾úÀ»¶§ ¹ß»ýµÇ¸ç, °¢°¢ÀÇ ±¸ºÐÀº ·£Ä«µåÀÇ status register¸¦ ÀÐÀ½À¸·Î¼­ ¾Ë¼ö°¡ ÀÖ´Ù. snullÀº °¡»óÀåÄ¡À̹ǷΠpriviateµ¥ÀÌÅÍ ¿µ¿ª¿¡ ÀÌ»óÅÂÁ¤º¸¸¦ ÀúÀåÇϳª,À̰ÍÀº ½ÇÁ¦ Çʵ忡¼­ ¾²´Â¹æ¹ýÀÌ ¾Æ´Ï´Ù.! ±×³É ¹«½ÃÇÏÀÚ. ------------------------------------------------------------------- /* * The typical interrupt entry point */ void snull_interrupt(int irq, void *dev_id, struct pt_regs *regs) { int statusword; struct snull_priv *priv; /* * As usual, check the "device" pointer for shared handlers. * Then assign "struct device *dev" */ struct net_device *dev = (struct net_device *)dev_id; /* ... and check with hw if it's really ours */ if (!dev /*paranoid*/ ) return; /* Lock the device */ priv = (struct snull_priv *) dev->priv; spin_lock(&priv->lock); /* retrieve statusword: real netdevices use I/O instructions */ statusword = priv->status; if (statusword & SNULL_RX_INTR) { /* send it to snull_rx for handling */ snull_rx(dev, priv->rx_packetlen, priv->rx_packetdata); } if (statusword & SNULL_TX_INTR) { /* a transmission is over: free the skb */ priv->stats.tx_packets++; priv->stats.tx_bytes += priv->tx_packetlen; dev_kfree_skb(priv->skb); } /* Unlock the device and we are done */ spin_unlock(&priv->lock); return; } ------------------------------------------------------------------- ¸¸¾à ÆÐŶÀ» ¹Þ¾Ò´Ù¸é À§¿¡¼­ ¼³¸íÇÑ snull_rx¸¦ È£ÃâÇØ¼­ ó¸®Çϰí, ÆÐŶÀü¼Û¿Ï·á ÀÎÅÍ·´Æ®¶ó¸é Åë°èÁ¤º¸¸¦ ¼¼ÆÃÇÑ´ÙÀ½ dev_kfree_skb·Î skb¸¦ À§ÇØ ÇÒ´çµÈ ¸Þ¸ð¸®¸¦ ÇØÁ¦ÇÑ´Ù.Áï, ack°¡ ¿Ã¶§±îÁö´Â ¸Þ¸ð¸®¿¡ ÆÐŶÀ» À§ÇÑ ¸Þ¸ð¸®°¡ ÇÒ´çµÈä·Î ³²¾ÆÀִ°ÍÀÌ´Ù. ¸µÅ©ÀÇ »óŸ¦ º¯°æÇϱâ ~~~~~~~~~~~~~~~~~~~~~~~ (RTL8139¿¡¼­ »ç¿ëµÇÁø ¾Ê´Â´Ù. Âü°í¸¸ÇÏÀÚ.) ÀÎÀ§ÀûÀ¸·Î ·£»ó¿¡ carrier°¡ Á¸ÀçÇÏÁö ¾Ê´Â°Íó·³ ÇÒ¼öÀִٴ°ÍÀÌ´Ù. Áï, ·£¼±À» »Ì¾Ò´Ù¸é carrier°¡ »ç¶óÁö°í, ´Ù½Ã ²ÈÀ¸¸é carrier°¡ ÀְԵȴÙ. µðÆúÆ®·Î ·£Ä«µå¿¡ carrier°¡ Á¸ÀçÇÑ´Ù°í °¡Á¤µÇ³ª,º¯°æµµ °¡´ÉÇÏ´Ù. netif_carrier_on(strut net_device *dev); // carrier on À¸·Î! netif_carrier_off(strut net_device *dev); //carrier off·Î! netif_carrier_ok(strut net_device *dev); //ÇöÀç»óÅÂÈ®ÀÎ. ³»ºÎÀûÀ¸·Î ´ÙÀ½°ú °°ÀÌ ¼¼ÆÃµÇ¾îÀÖÀ»»ÓÀÌ´Ù. ±×³É Âü°í¸¸ÇÏÀÚ. set_bitÀº atomicÇÏ°Ô ºñÆ®¸¦ ¼¼ÆÃÇÏ´Â ÇÔ¼öÀÌ´Ù. include/linux/netdevice.h ----------------------------------------- 611 static inline void netif_carrier_off(struct net_device *dev) 612 { 613 set_bit(__LINK_STATE_NOCARRIER, &dev->state); 614 } ------------------------------------------------------------------- ¼ÒÄÏ ¹öÆÛ(socket buffer) ~~~~~~~~~~~~~~~~~~~~~~~~~ ¼ÒÄϹöÆÛ¸¦ ¸¹ÀÌ »ç¿ëÇÏ¿´À¸³ª ÀÚ¼¼ÇѼ³¸íÀº Áö±Ý±îÁö »ý·«µÇ¾ú´Ù. sk_buff´Â ¸®´ª½ºÀÇ ³×Æ®¿÷ Äڵ忡¼­ °¡ÀåÁß½ÉÀÌ µÇ´Â ±¸Á¶Ã¼ÀÌ´Ù. ¿©·¯°³ÀÇ Çʵåµé°ú sk_buff ¸¦ ´Ù·ç´Â ´Ù¾çÇÑ À¯Æ¿¸®Æ¼ ÇÔ¼öµéÀ» ¾Ë¾Æº¸µµ·Ï ÇÏÀÚ. Áß¿ä Çʵå ========================== Áß¿äÇʵ带 ¸ÕÀú ¾Ë¾Æº¸ÀÚ. struct net_device *rx_dev ; //¼ÒÄÏ ¹öÆÛ¸¦ ¹Þ´ÂÀåÄ¡ struct net_device *dev ; //¼ÒÄϹöÆÛ¸¦ º¸³»´Â ÀåÄ¡ // transport layer Çì´õ ex) tcp, ucp... union { struct tcphdr *th; struct udphdr *uh; struct icmphdr *icmph; struct igmphdr *igmph; struct iphdr *ipiph; struct spxhdr *spxh; unsigned char *raw; } h; // Network layer Çì´õ ex) ip ... union { struct iphdr *iph; struct ipv6hdr *ipv6h; struct arphdr *arph; struct ipxhdr *ipxh; unsigned char *raw; } nh; // Link layer Çì´õ ex) ethernet union { struct ethhdr *ethernet; unsigned char *raw; } mac; À§¿Í°°ÀÌ ³×Æ®¿öÅ©ÀÇ °¢ °èÃþ¿¡ ÇØ´çÇÏ´Â Çì´õµéÀÌ Á¤ÀǵǾîÀÖ´Ù. <Âü°í>--------------------------------------------------------------- ¿¹¸¦µé¾î¼­ source ip address , dest ip address ¸¦ ¾Ë°í½Í´Ù°íÇÏÀÚ. À̶§´Â struct tcphdrÀ» ¾ò¾î¾ßÇϹǷΠ±×³É skb->h.th ¸¦ ÂüÁ¶ÇÏ¸é µÈ´Ù. struct tcphdr Àº include/linux/tcp.h ¿¡¼­ ´ÙÀ½°ú °°ÀÌ Á¤ÀÇÇÑ´Ù. struct tcphdr { __u16 source; __u16 dest; __u32 seq; __u32 ack_seq; #if defined(__LITTLE_ENDIAN_BITFIELD) __u16 res1:4, doff:4, fin:1, syn:1, rst:1, psh:1, ack:1, urg:1, ece:1, cwr:1; #elif defined(__BIG_ENDIAN_BITFIELD) __u16 doff:4, res1:4, cwr:1, ece:1, urg:1, ack:1, psh:1, rst:1, syn:1, fin:1; #else #error "Adjust your defines" #endif __u16 window; __u16 check; __u16 urg_ptr; }; ±×·¯¹Ç·Î.... source ip address¸¦ ¾Ë·Á¸é skb->h.th.source dest ip address¸¦ ¾Ë·Á¸é skb->h.th.dest ·Î ÇÏ¸é °£´ÜÈ÷ ¾Ë¼ö°¡ ÀÖ´Ù. ------------------------------------------------------------------------ ±×´ÙÀ½ Á¶±Ý º¹ÀâÇÑ º¯¼öµéÀÌ ¼±¾ðµÇ¾îÀÖ´Ù. unsigned char *head ; unsigned char *data ; unsigned char *tail ; unsigned char *end ; ÇÊÀÚµµ Á» ¾ù°¥·È´Âµ¥, ±Ç¼öÈ£´ÔÀÇ ±Û¿¡ÀÖ´Â ±×¸²À» º¸°í ´Ü¹ø¿¡ ÀÌÇØ°¡ µÇ¾ú´Ù. ¿©±â¿¡ ±×¸®±â´Â Èûµé¹Ç·Î ±×¸²Àº »ý·«ÇÑ´Ù. ½Ã°£ÀÌ Çã¶ôÇϽôºÐÀº ²À! »ìÆìº¸±â¸¦ ¹Ù¶õ´Ù. °£´ÜÈ÷ ¼³¸íÇÏ¸é ´ÙÀ½°ú °°´Ù. À§ÀÇ 4°³ÀÇ º¯¼ö´Â °á±¹ ¹öÆÛÀÇ ÁÖ¼Ò¸¦ ÀúÀåÇÏ´Â Æ÷ÀÎÅÍ º¯¼öÀÌ´Ù. ¹öÆÛ´Â head ·ÎºÎÅÍ end ±îÁö°¡ µÇ¸ç, ½ÇÁ¦·Î µ¥ÀÌÅͰ¡ Àִ°÷Àº data·ÎºÎÅÍ tail±îÁö°¡ µÈ´Ù.°£´ÜÈ÷ ±×·Áº¸¸é ´ÙÀ½°ú °°´Ù. +------------------------------------------------------------------+ | | | | | | ½ÇÁ¦ Àü¼ÛÇÒ È¤Àº ¹ÞÀº µ¥ÀÌÅÍ | | +------------------------------------------------------------------+ head data tail end ±×·¯¹Ç·Î »ç¿ë°¡´ÉÇÑ ¹öÆÛÅ©±â´Â skb->end - skb->head °¡ µÇ¸ç, ÇöÀç»ç¿ëµÇ´Â µ¥ÀÌÅÍÀÇ Å©±â´Â skb->tail - skb->data °¡µÈ´Ù. unsigned long len ; ÀÌ °ªÀº µ¥ÀÌÅÍÀÇ ±æÀ̷μ­ skb->tail - skb->data °¡µÈ´Ù. unsigned char ip_summed ; üũ¼¶À» Ç¥½ÃÇÏ´Â Á¤Ã¥À¸·Î¼­ À§¿¡¼­ ¼³¸íÇÏ¿´´Ù. unsigned char pkt_type ; À̰ÍÀº ÆÐŶŸÀÔÀ¸·Î¼­ PACKET_HOST , PACKET_BROADCAST , PACKET_MULTICAST, PAKCET_OTHERHOSTÁßÀÇ Çϳª¸¦ ¼¼ÆÃÇÒÃ¥ÀÓÀÌÀÖ´Ù.±×·¯³ª ½ÇÁúÀûÀÎ ¼¼ÆÃÀº ´ÙÀ½°ú °°ÀÌ eth_type_trans()¿¡¼­ ¼¼ÆÃÇϹǷΠµå¶óÀ̹ö °³¹ßÀÚ´Â ½Å°æÀ» ¾²Áö ¾Ê¾Æµµ µÈ´Ù. skb->protocol = eth_type_trans (skb, dev); ¼ÒÄϹöÆÛ¸¦ ´Ù·ç´Â ´Ù¾çÇÑ ÇÔ¼öµé ================================= ¼ÒÄϹöÆÛ¸¦ ´Ù·ç´Â ´Ù¾çÇÑ ÇÔ¼öµéÀÌ ÀÌ¹Ì Á¤ÀǵǾîÀÖÀ¸¹Ç·Î ¼ÒÄϹöÆÛ¸¦ ½±°Ô »ç¿ëÇÒ¼ö°¡ ÀÖ´Ù. struct sk_buff *alloc_skb(unsigned int len, int priority ); struct sk_buff *dev_alloc_skb(unsigned int len ) ; dev_alloc_skb´Â GFP_ATOMIC±ÇÇÑÀ¸·Î alloc_skb¸¦ ½ÇÇà½ÃŲ´Ù.±×¸®°í skb->data¿Í skb->head»çÀÌ¿¡ °ø°£À» Á¶±Ý ¿¹ºñÇØÁØ´Ù. ÀÌ °ø°£Àº network layer¿¡¼­ ÃÖÀûÈ­¿¡ »ç¿ëµÇ´Â°ÍÀ¸·Î¼­ µå¶óÀ̹ö¿¡¼­´Â °ÇµéÁö ¸»¾Æ¾ßÇÑ´Ù. º¸Åë µå¶óÀ̹ö °³¹ß¿¡¼­´Â dev_alloc_skb¸¦ »ç¿ëÇÑ´Ù. void kfree_skb( struct sk_buff *skb); void dev_kfree_skb(struct sk_buff *skb); <<==ÀÌ°É ¾²ÀÚ! ÇÒ´ç¹ÞÀº °ø°£À» ÇØÁ¦ÇÑ´Ù.µå¶óÀ̹ö °³¹ßÀÚ´Â dev_kfree_skb¸¦ »ç¿ëÇØ¾ßÇÑ´Ù. unsigned char * skb_put(struct sk_buff *skb, int len ); unsigned char * __skb_put(struct sk_buff *skb, int len ); unsigned char * skb_push(struct sk_buff *skb, int len ); unsigned char * __skb_push(struct sk_buff *skb, int len ); skb_putÀº ¹öÆÛÀÇ tail µÚ¿¡ ºÙÀ̴°ÍÀ¸·Î,º¯°æµÇ´Â°ªÀº tail,len ÀÌ µÈ´Ù. tailÀº ´ç¿¬È÷ ´Ã°Ú°í, lenµµ ´Ã°ÍÀÌ´Ù. À̰ÍÀº ¹öÆÛ¸¦ ´Ã¸®±âÀüÀÇ ÁÖ¼Ò¸¦ ¸®ÅÏÇϹǷΠsnull¿¡¼­µµ À̰ÍÀ» »ç¿ëÇÏ¿© memcpy·Î º¹»çÇß´Ù. skb_push´Â ¹öÆÛÀÇ ¾Õ¿¡´Ù°¡ ºÙÀ̴°ÍÀ¸·Î º¯°æµÇ´Â°ÍÀº data , lenÀÌ´Ù. data´Â ´ç¿¬È÷ ÁÙ°Ú°í, lenÀº ´Ã°ÍÀÌ´Ù. ¸®ÅϰªÀº ¹æ±Ý ¸¸µé¾îÁø data°ªÀÌ µÈ´Ù. ¸®ÅϰªÀ» »ìÆìº¸ÀÚ¸é, memcpy·Î º¹»çÇϱ⠽¬¿î °ªÀ» °¢°¢ ¸®ÅÏÇÔÀ» ¾Ë¼öÀÖ´Ù. __¸¦ ºÙÀΰÍÀº ±×³É °£´ÜÈ÷ ±â´ÉÀº ¶È°°Àºµ¥ µ¥ÀÌÅ͸¦ ¹öÆÛ¿¡ º¹»çÇÒ ¶§ °ø°£ÀÌ ¸Â´ÂÁö¸¦ üũÇÏ´Â ¿­ÇÒÀ» ´õ ÇÑ´Ù. int skb_tailroom(struct sk_buff *skb); int skb_headroom(strut sk_buff *skb); Áö±Ý ¹öÆÛ¿¡ ¾ó¸¶³ª °ø°£ÀÌ ³²¾Ò³ª¸¦ ¸®ÅÏÇϴ°ÍÀ¸·Î.... skb_tailÀº µÞÂʰø°£À», skb_headroomÀº ¾ÕÂÊ ³²Àº °ø°£À» ¸®ÅÏÇÑ´Ù. ÇÏÁö¸¸ ½ÇÁ¦ÀûÀ¸·Î ¾µÀÏÀº ¾øÀ»°ÍÀÌ´Ù. ¿Ö³ÄÇϸé skb_put ,skb_push¸¦ È£ÃâÇÒ¶§ ÀÚµ¿À¸·Î Ã¼Å©ÇØÁֱ⠶§¹®ÀÌ´Ù. void skb_reserve(struct sk_buff *skb , int len ); unsigned char *skb_pull(struct sk_buff *skb , int len ); skb_reserve´Â ¾ÕÂÊ¿¡ °ø°£À» È®º¸ÇϹǷΠdata,tail°¡ º¯ÇÑ´Ù. snull¿¡¼­µµ ÀÌ°Í À» »ç¿ëÇÏ¿© 16ºñÆ®Á¤·Ä¹®Á¦¸¦ ÇØ°áÇÔÀ» À§¿¡¼­ º¸¾Ò´Ù. skb_pullÀº ÆÐŶÀÇ Çì´õ·ÎºÎÅÍ µ¥ÀÌÅ͸¦ Á¦°ÅÇÑ´Ù. µå¶óÀ̹ö´Â ÀÌÀÛ¾÷ÀÌ Çʿ䰡 ¾ø´Ù. ±×³É Âü°í¸¸ Çϱ⠹ٶõ´Ù. ´ç¿¬È÷ skb->len,skb->data°¡ °¨¼ÒÇÒ°ÍÀÌ´Ù. À̰ÍÀÌ ¹Ù·Î ethernet header,ip header, tcp header, udp header µîÀÌ ¹þ°ÜÁö´Â ¿ø¸®ÀÌ´Ù.Áï, ºÒÇÊ¿äÇÑ ¸Þ¸ð¸® º¹»ç°¡ ÇÊ¿ä¾øÀÌ °£´ÜÈ÷ skb¿¡¼­ ¸î¸î º¯¼ö°¡ Á¶Á¤ÇØÁÖ¸é µÇ´Â°ÍÀÌ´Ù. À̹ø°­ÀǸ¦ ¸¶Ä¡¸ç ~~~~~~~~~~~~~~~~~ À̹ø½Ã°£±îÁö snull¿¡ ´ëÇØ¼­ ¾Ë¾Æº¸¾Ò´Ù. °á±¹ ³×Æ®¿÷ µð¹ÙÀ̽º µå¶óÀ̹ö¶õ Àß¹Þ°í,Àߺ¸³»¸é µÈ´Ù´Â°ÍÀ» ±â¾ïÇßÀ¸¸é ÇÑ´Ù. ±×·¯±â À§ÇÏ¿©, ÀÎÅÍ·´Æ®¸¦ »ç¿ëÇϸç, ÀÏÁ¤·®ÀÌ»óÀÇ µ¥ÀÌÅͰ¡ ¿À¸é ·£Ä«µå°¡ ÀÎÅÍ·´Æ®¸¦ °É¾î¼­ "³ªÁ» ó¸®ÇØÁà.." ¶ó°í ¸»Çϸç, ÆÐŶ Àü¼ÛÀÌ ¿Ï·áµÇ¾îµµ ÀÎÅÍ·´Æ®°¡ ¹ß»ýÇÏ¿©¼­ ÇÒ´çµÈ ¹öÆÛ¸¦ ÇØÁ¦ÇϴµîÀÇ ÀÏÀ» ÇÔÀ» ¾Ë¾Æº¸¾Ò´Ù. ¶ÇÇÑ ¼ÒÄÏ ¹öÆÛ¶ó´Â struct skb_buffµµ ¾Ë¾Æº¸¾Ò´Ù. ½ÇÁ¦ ³×Æ®¿÷ µð¹ÙÀ̽º µå¶óÀ̹ö¸¸µå´Â °ÍÀº ÀÌ·¯ÇÑ À̷к¸´Ù´Â.. ·£Ä«µåµîÀÇ Çϵå¿þ¾îÀÇ datasheetÀ» ´õ¸¹ÀÌ ºÁ¾ßÇÒ°ÍÀÌ´Ù. ÇÏÁö¸¸ ¿©±â¼­ ¼³¸íÇÑ ³»¿ëµéÀÌ »À´ë°¡ µÉ°ÍÀÓÀº ºÐ¸íÇÏ´Ù. À̱۷ΠÀÎÇØ µ¶ÀÚµéÀÌ ¶Ç ´Ù¸¥ Àç¹Ì(funny)¸¦ ¸¸³£ÇÒ¼ö¸¸ ÀÖ´Ù¸é ´õ ¹Ù¶ö°ÍÀÌ ¾ø°Ú´Ù. ±×·³ ´ã½Ã°£¿¡ ^_^