1.04k likes | 1.57k Views
12. 네트워크 디바이스 드라이버. data. TFTP header. data. Application Layer. TFTP message. FTP, Telnet, HTTP. Transport Layer. UDP header. TFTP header. data. UDP message. TCP, UDP. IP header. UDP header. TFTP header. data. Network Layer. IP packet. IP, ICMP, IGMP. Data link layer.
E N D
data TFTP header data Application Layer TFTP message FTP, Telnet, HTTP Transport Layer UDP header TFTP header data UDP message TCP, UDP IP header UDP header TFTP header data Network Layer IP packet IP, ICMP, IGMP Data link layer Device Driver NIC UDP header TFTP header data Ethernet trailer Ethernet header IP header Ethernet frame PPP, SLIP, Ethernet 12.1 Network Divice Driver 원리 및 구동 • TCP/IP Protocol STACK www.huins.com
Application Area Application System Call Interface Virtual File System(VFS) BSD socket Inet(AF_INET) Network Subsystem Buffer Cache Kernel Area Transport(TCP,UDP) Network(IP) Character Device Driver Block Device Driver Network Device Driver Device Interface Hardware Hardware 12.1 Network Divice Driver 원리 및 구동 • TCP/IP on Linux www.huins.com
12.1 Network Divice Driver 원리 및 구동 • Interface with kernel core • struct net_devide • Kernel에서 network device를 활성화 시키거나 비활성화 시킬때 그리고 data를 network device를 통해 전송하고자 할 때 등 kernel이 device를 control 하기 휘해 호출할 함수의 포인터를 가지고 있다. • hard_start_xmit() • 그외 network device의 설정이나 상태에 대한 정보를 갖는 변수들을 가지고 있다. • Name • base_address • Interrupt • data의 수신은 비동기적으로 발생하는 사건이므로 interrupt를 통해 처리한다. • Data 수신 외에도 chip이 data를 전송할 준비가 된 경우, data에 오류가 발생경우 등을 interrupt를 통해 처리한다. www.huins.com
Network device driver Kernel core net_device 구조체 생성 Static struct net_device dev 초기화 함수 등록 dev.init = cirrus_probe() kernel에 등록 register_netdev(&dev) net_deivce 구조체 리스트에 dev 삽입 • net_device 구조체 초기화 • name, base_addr, irq 등의 설정 • hard_start_xmit, open, close 등의 함수 포인터에 실제 함수 연결 dev.init() 호출 장치 활성화 dev.open() 호출 interrupt 등록 request_irq() device 초기화 12.1 Network Divice Driver 원리 및 구동 • Network Device Driver 초기화 과정 www.huins.com
Application Application write() System call sys_write() Linux kernel f->f_op->write() VFS /* fs/read_write.c */ /* net/socket.c */ sock_write() BSD socket /* net/ipv4/af_inet.c */ inet_sendmsg() inet socket /* net/ipv4/tcp_output.c */ tcp_send_skb() TCP ip_queue_xmit() /* net/ipv4/ip_output.c */ IP /* driver/net/cirrus.c */ Device driver hard_start_xmit() Device interface H/W CS8900A MAC MAC CS8900A PHY PHY 12.1 Network Divice Driver 원리 및 구동 • Send Data www.huins.com
Application struct net_device{ name; …. open; hard_start_xmit; stop; hard_header; set_config; chagne_mtu; get_stats; …. } Data 전송 요청 net_device 구조체 Kernel protocol stack net_device 구조체 net_device 구조체 리스트에서 application 이 사용하는 장치에서 등록한 구조체의 함수(*hard_start_xmit()) 호출 net_device 구조체 . . . net_device구조체 의 hard_start_xmit가 가리키고 있는 실제 device driver module의 함수 실행 net_device 구조체 Network device driver Network device의 internal register를 setting 하여 data를 전송하도록 한다. Hardware 12.1 Network Divice Driver 원리 및 구동 • Send Data www.huins.com
Application Application read() System call sys_read() Linux kernel f->f_op->read() VFS sock_read() BSD socket inet_recvmsg() wake up inet socket tcp_rev_state_process() tcp_recvmsg() TCP sleep ip_rev() IP interrupt handler 수행 Device driver netif_rx() Device interface H/W CS9800 MAC MAC CS9800 PHY PHY 12.1 Network Divice Driver 원리 및 구동 • Receive Data www.huins.com
Application Data Read 요청 data가 들어올 때까지 process를 sleep 상태로 Kernel protocol stack Kernel에 data를 전달한다. kernel은 해당 process를 wake up 한다. Kernel interrupt handler driver에서 등록한 handler 함수를 호출 Network device driver Data를 수신하면 net device는 interrupt를 발생시킨다. Hardware data 12.1 Network Divice Driver 원리 및 구동 • Receive Data www.huins.com
hard_header_len mtu tx_queue_len Family, address broadcast …. struct net_device { name mem_end, mem_start rmem_end, rmem_start base addr irq start, interrupt tbusy … Qdisc /* sk_buff */ …. interface information method status ….} open hard_start_xmit stop hard_header set_config chagne_mtu get_stats ioctl …. 12.2 net_device structure • Differ fro character and block driver • Interface with protocol stack (not file system) • struct net_device is similar to struct file_operations www.huins.com
12.2 net_device structure www.huins.com
12.2 net_device structure www.huins.com
12.2 net_device structure www.huins.com
12.2 net_device structure www.huins.com
12.3 Device Driver source code – [kernel]/drivers/net/cirrus.c • cirrus.c 의 주요 함수 • cirrus_init() • module이 커널에 적재될 때에 수행되는 함수 • net_device 구조체를 만들고 register_netdev()함수를 호출한다. • cirrus_cleanup() • module이 커널에서 제거될 때에 수행되는 함수 • release_region(), unregister_netdev()호출 • cirrus_probe() • cirrus_init()에서 register_netdev()를 호출할때 parameter로 전달하는 dev구조체의 init 함수 포인터에 이 함수의 주소를 담아 전달한다. • register_netdev()함수 호출시 커널에서 이함수를 호출 • net_device의 나머지 부분들을 device에 맞게 초기화 한다. www.huins.com
12.3 Device Driver source code – [kernel]/drivers/net/cirrus.c • cirrus_start() • device 가 활성화 될 때에 수행되는 함수로 인터럽트를 등록하고 칩의 설정에 관련된 레지스터를 setting한다. • cirrus_stop() • device 가 비활성화 될 때에 수행되는 함수로 인터럽트를 해제하고 칩을 초기화한다. • cirrus_send_start() • Application에서 data의 전송을 요구할때 kernel의 tcp/ip protocol stack의 ip layer에서 호출하는 함수로 device의 레지스터를 설정하여 data를 전송하도록 한다. • cirrus_receive() • 외부에서 data를 수신했을때에 cirrus_interrupt()에서 호출하는 함수로 data를 device로 부터 받아와서 kernel 에 전달 해 준다. www.huins.com
12.3 Device Driver source code – [kernel]/drivers/net/cirrus.c • cirrus_interrupt() • 인터럽트를 관리하는 5개의 레지스터중 어느 레지스터에서 인터럽트가 발생하였는지를 관찰하고 어떤 인터럽트가 발생했는지를 확인하여 적절한 처리를 해주는 함수 • cirrus_start() 함수에서 kernel에 request_irq()함수를 호출하여 이함수를 device의 interrupt handler 함수로 등록한다. www.huins.com
register_netdev 함수를 호출 할때 수행됨 Kernel Area Network Device Driver device 가 활성화 될 때 수행됨 Kernel 이 ethernet을 통해 메시지를 전송할 때 호출 cirrus_probe() protocol stack cirrus_start() ip_output() cirrus_send_start() ip_rcv() cirrus_receive() cirrus_interrupt() cirrus_stop() device 가 비활성화 될 때 수행됨 device가 data frame을 수신하는 등의 interrupt가 발생했을 때 수행됨 12.3 Device Driver source code – [kernel]/drivers/net/cirrus.c www.huins.com
12.3 Device Driver source code - MACRO MODULE_AUTHOR ("Abraham van der Merwe <abraham@2d3d.co.za>"); MODULE_DESCRIPTION ("Cirrus Logic CS8900A driver for Linux (V0.02)"); MODULE_LICENSE ("GPL"); MODULE_PARM_DESC (io,"I/O Base Address"); MODULE_PARM (io,"i"); MODULE_PARM_DESC (irq,"IRQ Number"); MODULE_PARM (irq,"i"); module_init (cirrus_init); module_exit (cirrus_cleanup); www.huins.com
12.3 Device Driver source code - MACRO static struct net_device dev; … static int __init cirrus_init (void) { memset (&dev,0,sizeof (struct net_device)); dev.init = cirrus_probe; return (register_netdev (&dev)); } dev를 0으로 초기화 Dev를 list에 추가한 후 cirrus_probe() 호출 www.huins.com
12.3 Device Driver source code - MACRO static void __exit cirrus_cleanup (void) { release_region (dev.base_addr,16); unregister_netdev (&dev); } www.huins.com
12.3 Device Driver source code – cirrus_probe( ) int __init cirrus_probe (struct net_device *dev) { memset (&priv,0,sizeof (cirrus_t)); ether_setup (dev); dev->open = cirrus_start; dev->stop = cirrus_stop; dev->hard_start_xmit = cirrus_send_start; dev->get_stats = cirrus_get_stats; dev->set_multicast_list = cirrus_set_receive_mode; dev->set_mac_address = cirrus_set_mac_address; dev->tx_timeout = cirrus_transmit_timeout; dev->watchdog_timeo = HZ; www.huins.com
12.3 Device Driver source code – cirrus_probe( ) dev->dev_addr[0] = 0x00; dev->dev_addr[1] = 0x00; dev->dev_addr[2] = 0x00; dev->dev_addr[3] = 0x00; dev->dev_addr[4] = 0x00; dev->dev_addr[5] = 0x00; dev->if_port = IF_PORT_10BASET; dev->priv = (void *) &priv; SET_MODULE_OWNER (dev); dev->base_addr = CIRRUS_DEFAULT_IO; dev->irq = CIRRUS_DEFAULT_IRQ; www.huins.com
12.3 Device Driver source code – cirrus_probe( ) • /* module parameters override everything */ • if (io > 0) dev->base_addr = io; • if (irq > 0) dev->irq = irq; • ... ... • if ((result = check_region (dev->base_addr,16))) { • printk (KERN_ERR "%s: can't get I/O port address\ 0x%lx\n",dev->name,dev->base_addr); • return (result); • } • if(!request_region(dev->base_addr,16,dev->name) ) • return –EBUSY; • ... ... www.huins.com
12.3 Device Driver source code – cirrus_probe( ) #if 1 cirrus_write (dev,PP_SelfCTL,RESET); while((( reset_status = cirrus_read(dev,PP_SelfST)) & INITD ) == 0 ); chip_status = cirrus_read(dev, PP_SelfST ); #endif /* if an EEPROM is present, use it's MAC address */ ... ... /* verify EISA registration number for Cirrus Logic */ ... ... /* verify chip version */ ... ... /* setup interrupt number */ ... ... /* configure MAC address */ ... ... return (0); } www.huins.com
12.3 Device Driver source code – cirrus_start( ) static int cirrus_start (struct net_device *dev) { int result; /* valid ethernet address? */ if (!is_valid_ether_addr(dev->dev_addr)) { printk(KERN_ERR "%s: invalid ethernet MAC address\n",dev->name); return (-EINVAL); } www.huins.com
12.3 Device Driver source code – cirrus_start( ) /* install interrupt handler */ if ((result = request_irq (dev- >irq,&cirrus_interrupt,0,dev->name,dev)) < 0) { printk (KERN_ERR "%s: could not register interrupt %d\n",dev->name,dev->irq); return (result); } /* enable the ethernet controller */ cirrus_set (dev,PP_RxCFG,RxOKiE | BufferCRC | CRCerroriE | RuntiE | ExtradataiE); cirrus_set (dev,PP_RxCTL,RxOKA | IndividualA | BroadcastA); cirrus_set (dev,PP_TxCFG,TxOKiE | Out_of_windowiE | JabberiE); cirrus_set (dev,PP_BufCFG,Rdy4TxiE | RxMissiE | TxUnderruniE | TxColOvfiE | MissOvfloiE); cirrus_set (dev,PP_LineCTL,SerRxON | SerTxON); cirrus_set (dev,PP_BusCTL,EnableRQ); www.huins.com
12.3 Device Driver source code – cirrus_start( ) #ifdef FULL_DUPLEX cirrus_set (dev,PP_TestCTL,FDX); #endif /* #ifdef FULL_DUPLEX */ /* start the queue */ netif_start_queue (dev); MOD_INC_USE_COUNT; return (0); } www.huins.com
12.3 Device Driver source code – cirrus_stop( ) static int cirrus_stop (struct net_device *dev) { /* disable ethernet controller */ cirrus_write (dev,PP_BusCTL,0); cirrus_write (dev,PP_TestCTL,0); cirrus_write (dev,PP_SelfCTL,0); cirrus_write (dev,PP_LineCTL,0); cirrus_write (dev,PP_BufCFG,0); cirrus_write (dev,PP_TxCFG,0); cirrus_write (dev,PP_RxCTL,0); cirrus_write (dev,PP_RxCFG,0); www.huins.com
12.3 Device Driver source code – cirrus_stop( ) /* uninstall interrupt handler */ free_irq (dev->irq,dev); /* stop the queue */ netif_stop_queue (dev); MOD_DEC_USE_COUNT; return (0); } www.huins.com
12.3 Device Driver source code – cirrus_send_start( ) static int cirrus_send_start (struct sk_buff *skb,struct net_device *dev) { cirrus_t *priv = (cirrus_t *) dev->priv; u16 status; netif_stop_queue (dev); cirrus_write (dev,PP_TxCMD,TxStart (After5)); cirrus_write (dev,PP_TxLength,skb->len); www.huins.com
12.3 Device Driver source code – cirrus_send_start( ) status = cirrus_read (dev,PP_BusST); if ((status & TxBidErr)) { printk (KERN_WARNING "%s: Invalid frame size %d!\n",dev->name,skb->len); priv->stats.tx_errors++; priv->stats.tx_aborted_errors++; priv->txlen = 0; return (1); } if (!(status & Rdy4TxNOW)) { printk (KERN_WARNING "%s: Transmit buffer not free!\n",dev->name); priv->stats.tx_errors++; priv->txlen = 0; /* FIXME: store skb and send it in interrupt handler*/ return (1); } www.huins.com
12.3 Device Driver source code – cirrus_send_start( ) cirrus_frame_write (dev,skb); dev->trans_start = jiffies; dev_kfree_skb (skb); priv->txlen = skb->len; return (0); } www.huins.com
12.3 Device Driver source code – cirrus_receive( ) static void cirrus_receive (struct net_device *dev) { cirrus_t *priv = (cirrus_t *) dev->priv; struct sk_buff *skb; u16 status,length; status = cirrus_read (dev,PP_RxStatus); length = cirrus_read (dev,PP_RxLength); if (!(status & RxOK)) { priv->stats.rx_errors++; if ((status & (Runt | Extradata))) priv->stats.rx_length_errors++; if ((status & CRCerror)) priv->stats.rx_crc_errors++; return; } www.huins.com
12.3 Device Driver source code – cirrus_receive( ) if ((skb = dev_alloc_skb (length + 4)) == NULL) { priv->stats.rx_dropped++; return; } skb->dev = dev; skb_reserve (skb,2); cirrus_frame_read (dev,skb,length); www.huins.com
12.3 Device Driver source code – cirrus_receive( ) skb->protocol = eth_type_trans (skb,dev); netif_rx (skb); dev->last_rx = jiffies; priv->stats.rx_packets++; priv->stats.rx_bytes += length; } www.huins.com
12.3 Device Driver source code – cirrus_interrupt( ) static void cirrus_interrupt (int irq,void *id,struct pt_regs *regs) { struct net_device *dev = (struct net_device *) id; cirrus_t *priv; u16 status; if (dev->priv == NULL) { printk (KERN_WARNING "%s: irq %d for unknown device.\n",dev->name,irq); return; } priv = (cirrus_t *) dev->priv; www.huins.com
12.3 Device Driver source code – cirrus_interrupt( ) while ((status = cirrus_read (dev,PP_ISQ))) { switch (RegNum (status)) { case RxEvent: cirrus_receive (dev); break; www.huins.com
12.3 Device Driver source code – cirrus_interrupt( ) case TxEvent: priv->stats.collisions += ColCount (cirrus_read(dev,PP_TxCOL)); if (!(RegContent (status) & TxOK)) { priv->stats.tx_errors++; if ((RegContent (status) & Out_of_window)) priv->stats.tx_window_errors++; if ((RegContent (status) & Jabber)) priv->stats.tx_aborted_errors++; break; } else if (priv->txlen) { priv->stats.tx_packets++; priv->stats.tx_bytes += priv->txlen; } priv->txlen = 0; netif_wake_queue (dev); break; www.huins.com
12.3 Device Driver source code – cirrus_interrupt( ) case BufEvent: if ((RegContent (status) & RxMiss)) { u16 missed = MissCount (cirrus_read (dev,PP_RxMISS)); priv->stats.rx_errors += missed; priv->stats.rx_missed_errors += missed; } if ((RegContent (status) & TxUnderrun)) { priv->stats.tx_errors++; priv->stats.tx_fifo_errors++; } /* FIXME: if Rdy4Tx, transmit last sent packet (if any) */ priv->txlen = 0; netif_wake_queue (dev); break; www.huins.com
12.3 Device Driver source code – cirrus_interrupt( ) case TxCOL: priv->stats.collisions += ColCount (cirrus_read (dev,PP_TxCOL)); break; case RxMISS: status = MissCount (cirrus_read (dev,PP_RxMISS)); priv->stats.rx_errors += status; priv->stats.rx_missed_errors += status; break; } } } www.huins.com
12.4 Network device driver 구동 • Network device driver 동작 확인 • ifconfig를 명령 수행 • eth0가 보이지 않으면 % /etc/rc.d/init.d/network start 실행 www.huins.com
12.4 Network device driver 구동 • Network Device Driver 동작 test • Host에 ping을 보내어 제대로 동작하는지 확인한다. www.huins.com
12.4 Socket() • TCP/IP 계층 구조 • 현재 전 세계적으로 사용하고 있는 인터넷은 TCP/IP라는 프로토콜을 기반으로 동작한다. • 네트워크 계층구조의 기준이라고 할 수 있는 OSI7계층과 달리 TCP/IP는 4개의 계층으로 이루어져 있다. www.huins.com
12.4 Socket() • TCP/IP 계층 구조 중 ‘Transport계층’에서는 TCP와 UDP 프로토콜을 제공한다. • 이 두 프로토콜의 차이점은 아래와 같다. www.huins.com
12.4 Socket() • IP주소와 PORT번호 • IP • TCP/IP protocol을 사용하여 데이터를 주고 받기 위해서는 주소가 필요 • TCP/IP에서 주소와 관련된 protocol을 IP(Internel Protocol)이라고 함 • ‘.’으로 구분된 4byte 정수로 표시 • Port 번호 • Host에는 여러 프로세스가 동작하고 있는데 어느 데이터가 전송되어 왔을 때 어느 프로세스가 수신할 것이지를 결정하는 것이 port 번호 • 2byte 정수로 표시하며 0~66535까지 사용이 가능 • telnet(23), ftp(21), httpd(80) www.huins.com
12.4 Socket() • Socket이란 • TCP 계층에서 제공하는 인터페이스를 직접 사용하여 프로그래밍하는 것은 매우 복잡하고 관련 프로토콜의 내부 구조를 잘 알고 있어야 한다. • 이런 복잡한 작업을 간편하게 해주는 것이 socket이다. • Socket은 응용계층에서 TCP계층의 기능을 사용할 수 있도록 제공하는 API이다. www.huins.com
12.4 Socket() • Socket은 같은 호스트에서 내부 프로세스들끼리 통신할 때 사용하는 유닉스도메인Socket과 다른 호스트와의 통신을 위한 인터넷 Socket으로 구분된다. • AF_UNIX : 유닉스 도메인 Socket • AF_INET : 인터넷 Socket • Socket이 TCP를 사용하느냐, UDP를 사용하느냐에 따라 두 가지로 구분된다. • SOCK_STREAM : TCP를 사용 • SOCK_DGRAM : UDP를 사용 www.huins.com
12.4 Socket() • Socket의 종류와 TCP/UDP를 결합하면 4가지 통신 유형이 나타난다 • AF_UNIX, SOCK_STREAM • AF_UNIX, SOCK_DGRAM • AF_INET, SOCK_STREAM • AF_INET, SOCK_DGRAM www.huins.com